github.com/aliyun/credentials-go@v1.4.7/credentials/credential.go (about)

     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  }