credential.go raw

   1  package credentials
   2  
   3  import (
   4  	"bufio"
   5  	"errors"
   6  	"fmt"
   7  	"net/http"
   8  	"net/url"
   9  	"os"
  10  	"strings"
  11  	"time"
  12  
  13  	"github.com/alibabacloud-go/debug/debug"
  14  	"github.com/alibabacloud-go/tea/tea"
  15  	"github.com/aliyun/credentials-go/credentials/internal/utils"
  16  	"github.com/aliyun/credentials-go/credentials/providers"
  17  	"github.com/aliyun/credentials-go/credentials/request"
  18  	"github.com/aliyun/credentials-go/credentials/response"
  19  )
  20  
  21  var debuglog = debug.Init("credential")
  22  
  23  var hookParse = func(err error) error {
  24  	return err
  25  }
  26  
  27  // Credential is an interface for getting actual credential
  28  type Credential interface {
  29  	// Deprecated: GetAccessKeyId is deprecated, use GetCredential instead of.
  30  	GetAccessKeyId() (*string, error)
  31  	// Deprecated: GetAccessKeySecret is deprecated, use GetCredential instead of.
  32  	GetAccessKeySecret() (*string, error)
  33  	// Deprecated: GetSecurityToken is deprecated, use GetCredential instead of.
  34  	GetSecurityToken() (*string, error)
  35  	GetBearerToken() *string
  36  	GetType() *string
  37  	GetCredential() (*CredentialModel, error)
  38  }
  39  
  40  // Config is important when call NewCredential
  41  type Config struct {
  42  	// Credential type, including access_key, sts, bearer, ecs_ram_role, ram_role_arn, rsa_key_pair, oidc_role_arn, credentials_uri
  43  	Type            *string `json:"type"`
  44  	AccessKeyId     *string `json:"access_key_id"`
  45  	AccessKeySecret *string `json:"access_key_secret"`
  46  	SecurityToken   *string `json:"security_token"`
  47  	BearerToken     *string `json:"bearer_token"`
  48  
  49  	// Used when the type is ram_role_arn or oidc_role_arn
  50  	OIDCProviderArn       *string `json:"oidc_provider_arn"`
  51  	OIDCTokenFilePath     *string `json:"oidc_token"`
  52  	RoleArn               *string `json:"role_arn"`
  53  	RoleSessionName       *string `json:"role_session_name"`
  54  	RoleSessionExpiration *int    `json:"role_session_expiration"`
  55  	Policy                *string `json:"policy"`
  56  	ExternalId            *string `json:"external_id"`
  57  	STSEndpoint           *string `json:"sts_endpoint"`
  58  
  59  	// Used when the type is ecs_ram_role
  60  	RoleName *string `json:"role_name"`
  61  	// Deprecated
  62  	EnableIMDSv2  *bool `json:"enable_imds_v2"`
  63  	DisableIMDSv1 *bool `json:"disable_imds_v1"`
  64  	// Deprecated
  65  	MetadataTokenDuration *int `json:"metadata_token_duration"`
  66  
  67  	// Used when the type is credentials_uri
  68  	Url *string `json:"url"`
  69  
  70  	// Deprecated
  71  	// Used when the type is rsa_key_pair
  72  	SessionExpiration *int    `json:"session_expiration"`
  73  	PublicKeyId       *string `json:"public_key_id"`
  74  	PrivateKeyFile    *string `json:"private_key_file"`
  75  	Host              *string `json:"host"`
  76  
  77  	// Read timeout, in milliseconds.
  78  	// The default value for ecs_ram_role is 1000ms, the default value for ram_role_arn is 5000ms, and the default value for oidc_role_arn is 5000ms.
  79  	Timeout *int `json:"timeout"`
  80  	// Connection timeout, in milliseconds.
  81  	// The default value for ecs_ram_role is 1000ms, the default value for ram_role_arn is 10000ms, and the default value for oidc_role_arn is 10000ms.
  82  	ConnectTimeout *int `json:"connect_timeout"`
  83  
  84  	Proxy          *string  `json:"proxy"`
  85  	InAdvanceScale *float64 `json:"inAdvanceScale"`
  86  }
  87  
  88  func (s Config) String() string {
  89  	return tea.Prettify(s)
  90  }
  91  
  92  func (s Config) GoString() string {
  93  	return s.String()
  94  }
  95  
  96  func (s *Config) SetAccessKeyId(v string) *Config {
  97  	s.AccessKeyId = &v
  98  	return s
  99  }
 100  
 101  func (s *Config) SetAccessKeySecret(v string) *Config {
 102  	s.AccessKeySecret = &v
 103  	return s
 104  }
 105  
 106  func (s *Config) SetSecurityToken(v string) *Config {
 107  	s.SecurityToken = &v
 108  	return s
 109  }
 110  
 111  func (s *Config) SetRoleArn(v string) *Config {
 112  	s.RoleArn = &v
 113  	return s
 114  }
 115  
 116  func (s *Config) SetRoleSessionName(v string) *Config {
 117  	s.RoleSessionName = &v
 118  	return s
 119  }
 120  
 121  func (s *Config) SetPublicKeyId(v string) *Config {
 122  	s.PublicKeyId = &v
 123  	return s
 124  }
 125  
 126  func (s *Config) SetRoleName(v string) *Config {
 127  	s.RoleName = &v
 128  	return s
 129  }
 130  
 131  func (s *Config) SetEnableIMDSv2(v bool) *Config {
 132  	s.EnableIMDSv2 = &v
 133  	return s
 134  }
 135  
 136  func (s *Config) SetDisableIMDSv1(v bool) *Config {
 137  	s.DisableIMDSv1 = &v
 138  	return s
 139  }
 140  
 141  func (s *Config) SetMetadataTokenDuration(v int) *Config {
 142  	s.MetadataTokenDuration = &v
 143  	return s
 144  }
 145  
 146  func (s *Config) SetSessionExpiration(v int) *Config {
 147  	s.SessionExpiration = &v
 148  	return s
 149  }
 150  
 151  func (s *Config) SetPrivateKeyFile(v string) *Config {
 152  	s.PrivateKeyFile = &v
 153  	return s
 154  }
 155  
 156  func (s *Config) SetBearerToken(v string) *Config {
 157  	s.BearerToken = &v
 158  	return s
 159  }
 160  
 161  func (s *Config) SetRoleSessionExpiration(v int) *Config {
 162  	s.RoleSessionExpiration = &v
 163  	return s
 164  }
 165  
 166  func (s *Config) SetPolicy(v string) *Config {
 167  	s.Policy = &v
 168  	return s
 169  }
 170  
 171  func (s *Config) SetHost(v string) *Config {
 172  	s.Host = &v
 173  	return s
 174  }
 175  
 176  func (s *Config) SetTimeout(v int) *Config {
 177  	s.Timeout = &v
 178  	return s
 179  }
 180  
 181  func (s *Config) SetConnectTimeout(v int) *Config {
 182  	s.ConnectTimeout = &v
 183  	return s
 184  }
 185  
 186  func (s *Config) SetProxy(v string) *Config {
 187  	s.Proxy = &v
 188  	return s
 189  }
 190  
 191  func (s *Config) SetType(v string) *Config {
 192  	s.Type = &v
 193  	return s
 194  }
 195  
 196  func (s *Config) SetOIDCTokenFilePath(v string) *Config {
 197  	s.OIDCTokenFilePath = &v
 198  	return s
 199  }
 200  
 201  func (s *Config) SetOIDCProviderArn(v string) *Config {
 202  	s.OIDCProviderArn = &v
 203  	return s
 204  }
 205  
 206  func (s *Config) SetURLCredential(v string) *Config {
 207  	if v == "" {
 208  		v = os.Getenv("ALIBABA_CLOUD_CREDENTIALS_URI")
 209  	}
 210  	s.Url = &v
 211  	return s
 212  }
 213  
 214  func (s *Config) SetSTSEndpoint(v string) *Config {
 215  	s.STSEndpoint = &v
 216  	return s
 217  }
 218  
 219  func (s *Config) SetExternalId(v string) *Config {
 220  	s.ExternalId = &v
 221  	return s
 222  }
 223  
 224  // NewCredential return a credential according to the type in config.
 225  // if config is nil, the function will use default provider chain to get credentials.
 226  // please see README.md for detail.
 227  func NewCredential(config *Config) (credential Credential, err error) {
 228  	if config == nil {
 229  		provider := providers.NewDefaultCredentialsProvider()
 230  		credential = FromCredentialsProvider("default", provider)
 231  		return
 232  	}
 233  	switch tea.StringValue(config.Type) {
 234  	case "credentials_uri":
 235  		provider, err := providers.NewURLCredentialsProviderBuilder().
 236  			WithUrl(tea.StringValue(config.Url)).
 237  			WithHttpOptions(&providers.HttpOptions{
 238  				Proxy:          tea.StringValue(config.Proxy),
 239  				ReadTimeout:    tea.IntValue(config.Timeout),
 240  				ConnectTimeout: tea.IntValue(config.ConnectTimeout),
 241  			}).
 242  			Build()
 243  
 244  		if err != nil {
 245  			return nil, err
 246  		}
 247  		credential = FromCredentialsProvider("credentials_uri", provider)
 248  	case "oidc_role_arn":
 249  		provider, err := providers.NewOIDCCredentialsProviderBuilder().
 250  			WithRoleArn(tea.StringValue(config.RoleArn)).
 251  			WithOIDCTokenFilePath(tea.StringValue(config.OIDCTokenFilePath)).
 252  			WithOIDCProviderARN(tea.StringValue(config.OIDCProviderArn)).
 253  			WithDurationSeconds(tea.IntValue(config.RoleSessionExpiration)).
 254  			WithPolicy(tea.StringValue(config.Policy)).
 255  			WithRoleSessionName(tea.StringValue(config.RoleSessionName)).
 256  			WithSTSEndpoint(tea.StringValue(config.STSEndpoint)).
 257  			WithHttpOptions(&providers.HttpOptions{
 258  				Proxy:          tea.StringValue(config.Proxy),
 259  				ReadTimeout:    tea.IntValue(config.Timeout),
 260  				ConnectTimeout: tea.IntValue(config.ConnectTimeout),
 261  			}).
 262  			Build()
 263  
 264  		if err != nil {
 265  			return nil, err
 266  		}
 267  		credential = FromCredentialsProvider("oidc_role_arn", provider)
 268  	case "access_key":
 269  		provider, err := providers.NewStaticAKCredentialsProviderBuilder().
 270  			WithAccessKeyId(tea.StringValue(config.AccessKeyId)).
 271  			WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)).
 272  			Build()
 273  		if err != nil {
 274  			return nil, err
 275  		}
 276  
 277  		credential = FromCredentialsProvider("access_key", provider)
 278  	case "sts":
 279  		provider, err := providers.NewStaticSTSCredentialsProviderBuilder().
 280  			WithAccessKeyId(tea.StringValue(config.AccessKeyId)).
 281  			WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)).
 282  			WithSecurityToken(tea.StringValue(config.SecurityToken)).
 283  			Build()
 284  		if err != nil {
 285  			return nil, err
 286  		}
 287  
 288  		credential = FromCredentialsProvider("sts", provider)
 289  	case "ecs_ram_role":
 290  		provider, err := providers.NewECSRAMRoleCredentialsProviderBuilder().
 291  			WithRoleName(tea.StringValue(config.RoleName)).
 292  			WithDisableIMDSv1(tea.BoolValue(config.DisableIMDSv1)).
 293  			Build()
 294  
 295  		if err != nil {
 296  			return nil, err
 297  		}
 298  
 299  		credential = FromCredentialsProvider("ecs_ram_role", provider)
 300  	case "ram_role_arn":
 301  		var credentialsProvider providers.CredentialsProvider
 302  		if config.SecurityToken != nil && *config.SecurityToken != "" {
 303  			credentialsProvider, err = providers.NewStaticSTSCredentialsProviderBuilder().
 304  				WithAccessKeyId(tea.StringValue(config.AccessKeyId)).
 305  				WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)).
 306  				WithSecurityToken(tea.StringValue(config.SecurityToken)).
 307  				Build()
 308  		} else {
 309  			credentialsProvider, err = providers.NewStaticAKCredentialsProviderBuilder().
 310  				WithAccessKeyId(tea.StringValue(config.AccessKeyId)).
 311  				WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)).
 312  				Build()
 313  		}
 314  
 315  		if err != nil {
 316  			return nil, err
 317  		}
 318  
 319  		provider, err := providers.NewRAMRoleARNCredentialsProviderBuilder().
 320  			WithCredentialsProvider(credentialsProvider).
 321  			WithRoleArn(tea.StringValue(config.RoleArn)).
 322  			WithRoleSessionName(tea.StringValue(config.RoleSessionName)).
 323  			WithPolicy(tea.StringValue(config.Policy)).
 324  			WithDurationSeconds(tea.IntValue(config.RoleSessionExpiration)).
 325  			WithExternalId(tea.StringValue(config.ExternalId)).
 326  			WithStsEndpoint(tea.StringValue(config.STSEndpoint)).
 327  			WithHttpOptions(&providers.HttpOptions{
 328  				Proxy:          tea.StringValue(config.Proxy),
 329  				ReadTimeout:    tea.IntValue(config.Timeout),
 330  				ConnectTimeout: tea.IntValue(config.ConnectTimeout),
 331  			}).
 332  			Build()
 333  		if err != nil {
 334  			return nil, err
 335  		}
 336  
 337  		credential = FromCredentialsProvider("ram_role_arn", provider)
 338  	case "rsa_key_pair":
 339  		err = checkRSAKeyPair(config)
 340  		if err != nil {
 341  			return
 342  		}
 343  		file, err1 := os.Open(tea.StringValue(config.PrivateKeyFile))
 344  		if err1 != nil {
 345  			err = fmt.Errorf("InvalidPath: Can not open PrivateKeyFile, err is %s", err1.Error())
 346  			return
 347  		}
 348  		defer file.Close()
 349  		var privateKey string
 350  		scan := bufio.NewScanner(file)
 351  		for scan.Scan() {
 352  			if strings.HasPrefix(scan.Text(), "----") {
 353  				continue
 354  			}
 355  			privateKey += scan.Text() + "\n"
 356  		}
 357  		runtime := &utils.Runtime{
 358  			Host:           tea.StringValue(config.Host),
 359  			Proxy:          tea.StringValue(config.Proxy),
 360  			ReadTimeout:    tea.IntValue(config.Timeout),
 361  			ConnectTimeout: tea.IntValue(config.ConnectTimeout),
 362  			STSEndpoint:    tea.StringValue(config.STSEndpoint),
 363  		}
 364  		credential = newRsaKeyPairCredential(
 365  			privateKey,
 366  			tea.StringValue(config.PublicKeyId),
 367  			tea.IntValue(config.SessionExpiration),
 368  			runtime)
 369  	case "bearer":
 370  		if tea.StringValue(config.BearerToken) == "" {
 371  			err = errors.New("BearerToken cannot be empty")
 372  			return
 373  		}
 374  		credential = newBearerTokenCredential(tea.StringValue(config.BearerToken))
 375  	default:
 376  		err = errors.New("invalid type option, support: access_key, sts, bearer, ecs_ram_role, ram_role_arn, rsa_key_pair, oidc_role_arn, credentials_uri")
 377  		return
 378  	}
 379  	return credential, nil
 380  }
 381  
 382  func checkRSAKeyPair(config *Config) (err error) {
 383  	if tea.StringValue(config.PrivateKeyFile) == "" {
 384  		err = errors.New("PrivateKeyFile cannot be empty")
 385  		return
 386  	}
 387  	if tea.StringValue(config.PublicKeyId) == "" {
 388  		err = errors.New("PublicKeyId cannot be empty")
 389  		return
 390  	}
 391  	return
 392  }
 393  
 394  func doAction(request *request.CommonRequest, runtime *utils.Runtime) (content []byte, err error) {
 395  	var urlEncoded string
 396  	if request.BodyParams != nil {
 397  		urlEncoded = utils.GetURLFormedMap(request.BodyParams)
 398  	}
 399  	httpRequest, err := http.NewRequest(request.Method, request.URL, strings.NewReader(urlEncoded))
 400  	if err != nil {
 401  		return
 402  	}
 403  	httpRequest.Proto = "HTTP/1.1"
 404  	httpRequest.Host = request.Domain
 405  	debuglog("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)
 406  	debuglog("> Host: %s", httpRequest.Host)
 407  	for key, value := range request.Headers {
 408  		if value != "" {
 409  			debuglog("> %s: %s", key, value)
 410  			httpRequest.Header[key] = []string{value}
 411  		}
 412  	}
 413  	debuglog(">")
 414  	httpClient := &http.Client{}
 415  	httpClient.Timeout = time.Duration(runtime.ReadTimeout) * time.Second
 416  	proxy := &url.URL{}
 417  	if runtime.Proxy != "" {
 418  		proxy, err = url.Parse(runtime.Proxy)
 419  		if err != nil {
 420  			return
 421  		}
 422  	}
 423  	transport := &http.Transport{}
 424  	if proxy != nil && runtime.Proxy != "" {
 425  		transport.Proxy = http.ProxyURL(proxy)
 426  	}
 427  	transport.DialContext = utils.Timeout(time.Duration(runtime.ConnectTimeout) * time.Second)
 428  	httpClient.Transport = transport
 429  	httpResponse, err := hookDo(httpClient.Do)(httpRequest)
 430  	if err != nil {
 431  		return
 432  	}
 433  	debuglog("< %s %s", httpResponse.Proto, httpResponse.Status)
 434  	for key, value := range httpResponse.Header {
 435  		debuglog("< %s: %v", key, strings.Join(value, ""))
 436  	}
 437  	debuglog("<")
 438  
 439  	resp := &response.CommonResponse{}
 440  	err = hookParse(resp.ParseFromHTTPResponse(httpResponse))
 441  	if err != nil {
 442  		return
 443  	}
 444  	debuglog("%s", resp.GetHTTPContentString())
 445  	if resp.GetHTTPStatus() != http.StatusOK {
 446  		err = fmt.Errorf("httpStatus: %d, message = %s", resp.GetHTTPStatus(), resp.GetHTTPContentString())
 447  		return
 448  	}
 449  	return resp.GetHTTPContentBytes(), nil
 450  }
 451  
 452  type credentialsProviderWrap struct {
 453  	typeName string
 454  	provider providers.CredentialsProvider
 455  }
 456  
 457  // Deprecated: use GetCredential() instead of
 458  func (cp *credentialsProviderWrap) GetAccessKeyId() (accessKeyId *string, err error) {
 459  	cc, err := cp.provider.GetCredentials()
 460  	if err != nil {
 461  		return
 462  	}
 463  	accessKeyId = &cc.AccessKeyId
 464  	return
 465  }
 466  
 467  // Deprecated: use GetCredential() instead of
 468  func (cp *credentialsProviderWrap) GetAccessKeySecret() (accessKeySecret *string, err error) {
 469  	cc, err := cp.provider.GetCredentials()
 470  	if err != nil {
 471  		return
 472  	}
 473  	accessKeySecret = &cc.AccessKeySecret
 474  	return
 475  }
 476  
 477  // Deprecated: use GetCredential() instead of
 478  func (cp *credentialsProviderWrap) GetSecurityToken() (securityToken *string, err error) {
 479  	cc, err := cp.provider.GetCredentials()
 480  	if err != nil {
 481  		return
 482  	}
 483  	securityToken = &cc.SecurityToken
 484  	return
 485  }
 486  
 487  // Deprecated: don't use it
 488  func (cp *credentialsProviderWrap) GetBearerToken() (bearerToken *string) {
 489  	return tea.String("")
 490  }
 491  
 492  // Get credentials
 493  func (cp *credentialsProviderWrap) GetCredential() (cm *CredentialModel, err error) {
 494  	c, err := cp.provider.GetCredentials()
 495  	if err != nil {
 496  		return
 497  	}
 498  
 499  	cm = &CredentialModel{
 500  		AccessKeyId:     &c.AccessKeyId,
 501  		AccessKeySecret: &c.AccessKeySecret,
 502  		SecurityToken:   &c.SecurityToken,
 503  		Type:            &cp.typeName,
 504  		ProviderName:    &c.ProviderName,
 505  	}
 506  	return
 507  }
 508  
 509  func (cp *credentialsProviderWrap) GetType() *string {
 510  	return &cp.typeName
 511  }
 512  
 513  func FromCredentialsProvider(typeName string, cp providers.CredentialsProvider) Credential {
 514  	return &credentialsProviderWrap{
 515  		typeName: typeName,
 516  		provider: cp,
 517  	}
 518  }
 519