...

Source file src/github.com/aliyun/credentials-go/credentials/credential.go

Documentation: github.com/aliyun/credentials-go/credentials

     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/request"
    16  	"github.com/aliyun/credentials-go/credentials/response"
    17  	"github.com/aliyun/credentials-go/credentials/utils"
    18  )
    19  
    20  var debuglog = debug.Init("credential")
    21  
    22  var hookParse = func(err error) error {
    23  	return err
    24  }
    25  
    26  // Credential is an interface for getting actual credential
    27  type Credential interface {
    28  	GetAccessKeyId() (*string, error)
    29  	GetAccessKeySecret() (*string, error)
    30  	GetSecurityToken() (*string, error)
    31  	GetBearerToken() *string
    32  	GetType() *string
    33  	GetCredential() (*CredentialModel, error)
    34  }
    35  
    36  // Config is important when call NewCredential
    37  type Config struct {
    38  	Type                  *string  `json:"type"`
    39  	AccessKeyId           *string  `json:"access_key_id"`
    40  	AccessKeySecret       *string  `json:"access_key_secret"`
    41  	OIDCProviderArn       *string  `json:"oidc_provider_arn"`
    42  	OIDCTokenFilePath     *string  `json:"oidc_token"`
    43  	RoleArn               *string  `json:"role_arn"`
    44  	RoleSessionName       *string  `json:"role_session_name"`
    45  	PublicKeyId           *string  `json:"public_key_id"`
    46  	RoleName              *string  `json:"role_name"`
    47  	SessionExpiration     *int     `json:"session_expiration"`
    48  	PrivateKeyFile        *string  `json:"private_key_file"`
    49  	BearerToken           *string  `json:"bearer_token"`
    50  	SecurityToken         *string  `json:"security_token"`
    51  	RoleSessionExpiration *int     `json:"role_session_expiratioon"`
    52  	Policy                *string  `json:"policy"`
    53  	Host                  *string  `json:"host"`
    54  	Timeout               *int     `json:"timeout"`
    55  	ConnectTimeout        *int     `json:"connect_timeout"`
    56  	Proxy                 *string  `json:"proxy"`
    57  	InAdvanceScale        *float64 `json:"inAdvanceScale"`
    58  	Url                   *string  `json:"url"`
    59  	STSEndpoint           *string  `json:"sts_endpoint"`
    60  	ExternalId            *string  `json:"external_id"`
    61  }
    62  
    63  func (s Config) String() string {
    64  	return tea.Prettify(s)
    65  }
    66  
    67  func (s Config) GoString() string {
    68  	return s.String()
    69  }
    70  
    71  func (s *Config) SetAccessKeyId(v string) *Config {
    72  	s.AccessKeyId = &v
    73  	return s
    74  }
    75  
    76  func (s *Config) SetAccessKeySecret(v string) *Config {
    77  	s.AccessKeySecret = &v
    78  	return s
    79  }
    80  
    81  func (s *Config) SetSecurityToken(v string) *Config {
    82  	s.SecurityToken = &v
    83  	return s
    84  }
    85  
    86  func (s *Config) SetRoleArn(v string) *Config {
    87  	s.RoleArn = &v
    88  	return s
    89  }
    90  
    91  func (s *Config) SetRoleSessionName(v string) *Config {
    92  	s.RoleSessionName = &v
    93  	return s
    94  }
    95  
    96  func (s *Config) SetPublicKeyId(v string) *Config {
    97  	s.PublicKeyId = &v
    98  	return s
    99  }
   100  
   101  func (s *Config) SetRoleName(v string) *Config {
   102  	s.RoleName = &v
   103  	return s
   104  }
   105  
   106  func (s *Config) SetSessionExpiration(v int) *Config {
   107  	s.SessionExpiration = &v
   108  	return s
   109  }
   110  
   111  func (s *Config) SetPrivateKeyFile(v string) *Config {
   112  	s.PrivateKeyFile = &v
   113  	return s
   114  }
   115  
   116  func (s *Config) SetBearerToken(v string) *Config {
   117  	s.BearerToken = &v
   118  	return s
   119  }
   120  
   121  func (s *Config) SetRoleSessionExpiration(v int) *Config {
   122  	s.RoleSessionExpiration = &v
   123  	return s
   124  }
   125  
   126  func (s *Config) SetPolicy(v string) *Config {
   127  	s.Policy = &v
   128  	return s
   129  }
   130  
   131  func (s *Config) SetHost(v string) *Config {
   132  	s.Host = &v
   133  	return s
   134  }
   135  
   136  func (s *Config) SetTimeout(v int) *Config {
   137  	s.Timeout = &v
   138  	return s
   139  }
   140  
   141  func (s *Config) SetConnectTimeout(v int) *Config {
   142  	s.ConnectTimeout = &v
   143  	return s
   144  }
   145  
   146  func (s *Config) SetProxy(v string) *Config {
   147  	s.Proxy = &v
   148  	return s
   149  }
   150  
   151  func (s *Config) SetType(v string) *Config {
   152  	s.Type = &v
   153  	return s
   154  }
   155  
   156  func (s *Config) SetOIDCTokenFilePath(v string) *Config {
   157  	s.OIDCTokenFilePath = &v
   158  	return s
   159  }
   160  
   161  func (s *Config) SetOIDCProviderArn(v string) *Config {
   162  	s.OIDCProviderArn = &v
   163  	return s
   164  }
   165  
   166  func (s *Config) SetURLCredential(v string) *Config {
   167  	if v == "" {
   168  		v = os.Getenv("ALIBABA_CLOUD_CREDENTIALS_URI")
   169  	}
   170  	s.Url = &v
   171  	return s
   172  }
   173  
   174  func (s *Config) SetSTSEndpoint(v string) *Config {
   175  	s.STSEndpoint = &v
   176  	return s
   177  }
   178  
   179  // NewCredential return a credential according to the type in config.
   180  // if config is nil, the function will use default provider chain to get credential.
   181  // please see README.md for detail.
   182  func NewCredential(config *Config) (credential Credential, err error) {
   183  	if config == nil {
   184  		config, err = defaultChain.resolve()
   185  		if err != nil {
   186  			return
   187  		}
   188  		return NewCredential(config)
   189  	}
   190  	switch tea.StringValue(config.Type) {
   191  	case "credentials_uri":
   192  		credential = newURLCredential(tea.StringValue(config.Url))
   193  	case "oidc_role_arn":
   194  		err = checkoutAssumeRamoidc(config)
   195  		if err != nil {
   196  			return
   197  		}
   198  		runtime := &utils.Runtime{
   199  			Host:           tea.StringValue(config.Host),
   200  			Proxy:          tea.StringValue(config.Proxy),
   201  			ReadTimeout:    tea.IntValue(config.Timeout),
   202  			ConnectTimeout: tea.IntValue(config.ConnectTimeout),
   203  			STSEndpoint:    tea.StringValue(config.STSEndpoint),
   204  		}
   205  		credential = newOIDCRoleArnCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.RoleArn), tea.StringValue(config.OIDCProviderArn), tea.StringValue(config.OIDCTokenFilePath), tea.StringValue(config.RoleSessionName), tea.StringValue(config.Policy), tea.IntValue(config.RoleSessionExpiration), runtime)
   206  	case "access_key":
   207  		err = checkAccessKey(config)
   208  		if err != nil {
   209  			return
   210  		}
   211  		credential = newAccessKeyCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret))
   212  	case "sts":
   213  		err = checkSTS(config)
   214  		if err != nil {
   215  			return
   216  		}
   217  		credential = newStsTokenCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.SecurityToken))
   218  	case "ecs_ram_role":
   219  		checkEcsRAMRole(config)
   220  		runtime := &utils.Runtime{
   221  			Host:           tea.StringValue(config.Host),
   222  			Proxy:          tea.StringValue(config.Proxy),
   223  			ReadTimeout:    tea.IntValue(config.Timeout),
   224  			ConnectTimeout: tea.IntValue(config.ConnectTimeout),
   225  		}
   226  		credential = newEcsRAMRoleCredential(tea.StringValue(config.RoleName), tea.Float64Value(config.InAdvanceScale), runtime)
   227  	case "ram_role_arn":
   228  		err = checkRAMRoleArn(config)
   229  		if err != nil {
   230  			return
   231  		}
   232  		runtime := &utils.Runtime{
   233  			Host:           tea.StringValue(config.Host),
   234  			Proxy:          tea.StringValue(config.Proxy),
   235  			ReadTimeout:    tea.IntValue(config.Timeout),
   236  			ConnectTimeout: tea.IntValue(config.ConnectTimeout),
   237  			STSEndpoint:    tea.StringValue(config.STSEndpoint),
   238  		}
   239  		credential = newRAMRoleArnWithExternalIdCredential(
   240  			tea.StringValue(config.AccessKeyId),
   241  			tea.StringValue(config.AccessKeySecret),
   242  			tea.StringValue(config.RoleArn),
   243  			tea.StringValue(config.RoleSessionName),
   244  			tea.StringValue(config.Policy),
   245  			tea.IntValue(config.RoleSessionExpiration),
   246  			tea.StringValue(config.ExternalId),
   247  			runtime)
   248  	case "rsa_key_pair":
   249  		err = checkRSAKeyPair(config)
   250  		if err != nil {
   251  			return
   252  		}
   253  		file, err1 := os.Open(tea.StringValue(config.PrivateKeyFile))
   254  		if err1 != nil {
   255  			err = fmt.Errorf("InvalidPath: Can not open PrivateKeyFile, err is %s", err1.Error())
   256  			return
   257  		}
   258  		defer file.Close()
   259  		var privateKey string
   260  		scan := bufio.NewScanner(file)
   261  		for scan.Scan() {
   262  			if strings.HasPrefix(scan.Text(), "----") {
   263  				continue
   264  			}
   265  			privateKey += scan.Text() + "\n"
   266  		}
   267  		runtime := &utils.Runtime{
   268  			Host:           tea.StringValue(config.Host),
   269  			Proxy:          tea.StringValue(config.Proxy),
   270  			ReadTimeout:    tea.IntValue(config.Timeout),
   271  			ConnectTimeout: tea.IntValue(config.ConnectTimeout),
   272  			STSEndpoint:    tea.StringValue(config.STSEndpoint),
   273  		}
   274  		credential = newRsaKeyPairCredential(privateKey, tea.StringValue(config.PublicKeyId), tea.IntValue(config.SessionExpiration), runtime)
   275  	case "bearer":
   276  		if tea.StringValue(config.BearerToken) == "" {
   277  			err = errors.New("BearerToken cannot be empty")
   278  			return
   279  		}
   280  		credential = newBearerTokenCredential(tea.StringValue(config.BearerToken))
   281  	default:
   282  		err = errors.New("Invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair")
   283  		return
   284  	}
   285  	return credential, nil
   286  }
   287  
   288  func checkRSAKeyPair(config *Config) (err error) {
   289  	if tea.StringValue(config.PrivateKeyFile) == "" {
   290  		err = errors.New("PrivateKeyFile cannot be empty")
   291  		return
   292  	}
   293  	if tea.StringValue(config.PublicKeyId) == "" {
   294  		err = errors.New("PublicKeyId cannot be empty")
   295  		return
   296  	}
   297  	return
   298  }
   299  
   300  func checkoutAssumeRamoidc(config *Config) (err error) {
   301  	if tea.StringValue(config.RoleArn) == "" {
   302  		err = errors.New("RoleArn cannot be empty")
   303  		return
   304  	}
   305  	if tea.StringValue(config.OIDCProviderArn) == "" {
   306  		err = errors.New("OIDCProviderArn cannot be empty")
   307  		return
   308  	}
   309  	return
   310  }
   311  
   312  func checkRAMRoleArn(config *Config) (err error) {
   313  	if tea.StringValue(config.AccessKeySecret) == "" {
   314  		err = errors.New("AccessKeySecret cannot be empty")
   315  		return
   316  	}
   317  	if tea.StringValue(config.RoleArn) == "" {
   318  		err = errors.New("RoleArn cannot be empty")
   319  		return
   320  	}
   321  	if tea.StringValue(config.RoleSessionName) == "" {
   322  		err = errors.New("RoleSessionName cannot be empty")
   323  		return
   324  	}
   325  	if tea.StringValue(config.AccessKeyId) == "" {
   326  		err = errors.New("AccessKeyId cannot be empty")
   327  		return
   328  	}
   329  	return
   330  }
   331  
   332  func checkEcsRAMRole(config *Config) (err error) {
   333  	return
   334  }
   335  
   336  func checkSTS(config *Config) (err error) {
   337  	if tea.StringValue(config.AccessKeyId) == "" {
   338  		err = errors.New("AccessKeyId cannot be empty")
   339  		return
   340  	}
   341  	if tea.StringValue(config.AccessKeySecret) == "" {
   342  		err = errors.New("AccessKeySecret cannot be empty")
   343  		return
   344  	}
   345  	if tea.StringValue(config.SecurityToken) == "" {
   346  		err = errors.New("SecurityToken cannot be empty")
   347  		return
   348  	}
   349  	return
   350  }
   351  
   352  func checkAccessKey(config *Config) (err error) {
   353  	if tea.StringValue(config.AccessKeyId) == "" {
   354  		err = errors.New("AccessKeyId cannot be empty")
   355  		return
   356  	}
   357  	if tea.StringValue(config.AccessKeySecret) == "" {
   358  		err = errors.New("AccessKeySecret cannot be empty")
   359  		return
   360  	}
   361  	return
   362  }
   363  
   364  func doAction(request *request.CommonRequest, runtime *utils.Runtime) (content []byte, err error) {
   365  	var urlEncoded string
   366  	if request.BodyParams != nil {
   367  		urlEncoded = utils.GetURLFormedMap(request.BodyParams)
   368  	}
   369  	httpRequest, err := http.NewRequest(request.Method, request.URL, strings.NewReader(urlEncoded))
   370  	if err != nil {
   371  		return
   372  	}
   373  	httpRequest.Proto = "HTTP/1.1"
   374  	httpRequest.Host = request.Domain
   375  	debuglog("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)
   376  	debuglog("> Host: %s", httpRequest.Host)
   377  	for key, value := range request.Headers {
   378  		if value != "" {
   379  			debuglog("> %s: %s", key, value)
   380  			httpRequest.Header[key] = []string{value}
   381  		}
   382  	}
   383  	debuglog(">")
   384  	httpClient := &http.Client{}
   385  	httpClient.Timeout = time.Duration(runtime.ReadTimeout) * time.Second
   386  	proxy := &url.URL{}
   387  	if runtime.Proxy != "" {
   388  		proxy, err = url.Parse(runtime.Proxy)
   389  		if err != nil {
   390  			return
   391  		}
   392  	}
   393  	trans := &http.Transport{}
   394  	if proxy != nil && runtime.Proxy != "" {
   395  		trans.Proxy = http.ProxyURL(proxy)
   396  	}
   397  	trans.DialContext = utils.Timeout(time.Duration(runtime.ConnectTimeout) * time.Second)
   398  	httpClient.Transport = trans
   399  	httpResponse, err := hookDo(httpClient.Do)(httpRequest)
   400  	if err != nil {
   401  		return
   402  	}
   403  	debuglog("< %s %s", httpResponse.Proto, httpResponse.Status)
   404  	for key, value := range httpResponse.Header {
   405  		debuglog("< %s: %v", key, strings.Join(value, ""))
   406  	}
   407  	debuglog("<")
   408  
   409  	resp := &response.CommonResponse{}
   410  	err = hookParse(resp.ParseFromHTTPResponse(httpResponse))
   411  	if err != nil {
   412  		return
   413  	}
   414  	debuglog("%s", resp.GetHTTPContentString())
   415  	if resp.GetHTTPStatus() != http.StatusOK {
   416  		err = fmt.Errorf("httpStatus: %d, message = %s", resp.GetHTTPStatus(), resp.GetHTTPContentString())
   417  		return
   418  	}
   419  	return resp.GetHTTPContentBytes(), nil
   420  }
   421  

View as plain text