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

     1  package credentials
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/alibabacloud-go/tea/tea"
    10  	"github.com/aliyun/credentials-go/credentials/internal/utils"
    11  	ini "gopkg.in/ini.v1"
    12  )
    13  
    14  type profileProvider struct {
    15  	Profile string
    16  }
    17  
    18  var providerProfile = newProfileProvider()
    19  
    20  var hookState = func(info os.FileInfo, err error) (os.FileInfo, error) {
    21  	return info, err
    22  }
    23  
    24  // NewProfileProvider receive zero or more parameters,
    25  // when length of name is 0, the value of field Profile will be "default",
    26  // and when there are multiple inputs, the function will take the
    27  // first one and  discard the other values.
    28  func newProfileProvider(name ...string) Provider {
    29  	p := new(profileProvider)
    30  	if len(name) == 0 {
    31  		p.Profile = "default"
    32  	} else {
    33  		p.Profile = name[0]
    34  	}
    35  	return p
    36  }
    37  
    38  // resolve implements the Provider interface
    39  // when credential type is rsa_key_pair, the content of private_key file
    40  // must be able to be parsed directly into the required string
    41  // that NewRsaKeyPairCredential function needed
    42  func (p *profileProvider) resolve() (*Config, error) {
    43  	path, ok := os.LookupEnv(ENVCredentialFile)
    44  	if !ok {
    45  		defaultPath, err := checkDefaultPath()
    46  		if err != nil {
    47  			return nil, err
    48  		}
    49  		path = defaultPath
    50  		if path == "" {
    51  			return nil, nil
    52  		}
    53  	} else if path == "" {
    54  		return nil, errors.New(ENVCredentialFile + " cannot be empty")
    55  	}
    56  
    57  	value, section, err := getType(path, p.Profile)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	switch value.String() {
    62  	case "access_key":
    63  		config, err := getAccessKey(section)
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  		return config, nil
    68  	case "sts":
    69  		config, err := getSTS(section)
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  		return config, nil
    74  	case "bearer":
    75  		config, err := getBearerToken(section)
    76  		if err != nil {
    77  			return nil, err
    78  		}
    79  		return config, nil
    80  	case "ecs_ram_role":
    81  		config, err := getEcsRAMRole(section)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		return config, nil
    86  	case "ram_role_arn":
    87  		config, err := getRAMRoleArn(section)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  		return config, nil
    92  	case "rsa_key_pair":
    93  		config, err := getRSAKeyPair(section)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		return config, nil
    98  	default:
    99  		return nil, errors.New("invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair")
   100  	}
   101  }
   102  
   103  func getRSAKeyPair(section *ini.Section) (*Config, error) {
   104  	publicKeyId, err := section.GetKey("public_key_id")
   105  	if err != nil {
   106  		return nil, errors.New("missing required public_key_id option in profile for rsa_key_pair")
   107  	}
   108  	if publicKeyId.String() == "" {
   109  		return nil, errors.New("public_key_id cannot be empty")
   110  	}
   111  	privateKeyFile, err := section.GetKey("private_key_file")
   112  	if err != nil {
   113  		return nil, errors.New("missing required private_key_file option in profile for rsa_key_pair")
   114  	}
   115  	if privateKeyFile.String() == "" {
   116  		return nil, errors.New("private_key_file cannot be empty")
   117  	}
   118  	sessionExpiration, _ := section.GetKey("session_expiration")
   119  	expiration := 0
   120  	if sessionExpiration != nil {
   121  		expiration, err = sessionExpiration.Int()
   122  		if err != nil {
   123  			return nil, errors.New("session_expiration must be an int")
   124  		}
   125  	}
   126  	config := &Config{
   127  		Type:              tea.String("rsa_key_pair"),
   128  		PublicKeyId:       tea.String(publicKeyId.String()),
   129  		PrivateKeyFile:    tea.String(privateKeyFile.String()),
   130  		SessionExpiration: tea.Int(expiration),
   131  	}
   132  	err = setRuntimeToConfig(config, section)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	return config, nil
   137  }
   138  
   139  func getRAMRoleArn(section *ini.Section) (*Config, error) {
   140  	accessKeyId, err := section.GetKey("access_key_id")
   141  	if err != nil {
   142  		return nil, errors.New("missing required access_key_id option in profile for ram_role_arn")
   143  	}
   144  	if accessKeyId.String() == "" {
   145  		return nil, errors.New("access_key_id cannot be empty")
   146  	}
   147  	accessKeySecret, err := section.GetKey("access_key_secret")
   148  	if err != nil {
   149  		return nil, errors.New("missing required access_key_secret option in profile for ram_role_arn")
   150  	}
   151  	if accessKeySecret.String() == "" {
   152  		return nil, errors.New("access_key_secret cannot be empty")
   153  	}
   154  	roleArn, err := section.GetKey("role_arn")
   155  	if err != nil {
   156  		return nil, errors.New("missing required role_arn option in profile for ram_role_arn")
   157  	}
   158  	if roleArn.String() == "" {
   159  		return nil, errors.New("role_arn cannot be empty")
   160  	}
   161  	roleSessionName, err := section.GetKey("role_session_name")
   162  	if err != nil {
   163  		return nil, errors.New("missing required role_session_name option in profile for ram_role_arn")
   164  	}
   165  	if roleSessionName.String() == "" {
   166  		return nil, errors.New("role_session_name cannot be empty")
   167  	}
   168  	roleSessionExpiration, _ := section.GetKey("role_session_expiration")
   169  	expiration := 0
   170  	if roleSessionExpiration != nil {
   171  		expiration, err = roleSessionExpiration.Int()
   172  		if err != nil {
   173  			return nil, errors.New("role_session_expiration must be an int")
   174  		}
   175  	}
   176  	config := &Config{
   177  		Type:                  tea.String("ram_role_arn"),
   178  		AccessKeyId:           tea.String(accessKeyId.String()),
   179  		AccessKeySecret:       tea.String(accessKeySecret.String()),
   180  		RoleArn:               tea.String(roleArn.String()),
   181  		RoleSessionName:       tea.String(roleSessionName.String()),
   182  		RoleSessionExpiration: tea.Int(expiration),
   183  	}
   184  	err = setRuntimeToConfig(config, section)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	return config, nil
   189  }
   190  
   191  func getEcsRAMRole(section *ini.Section) (*Config, error) {
   192  	roleName, _ := section.GetKey("role_name")
   193  	config := &Config{
   194  		Type: tea.String("ecs_ram_role"),
   195  	}
   196  	if roleName != nil {
   197  		config.RoleName = tea.String(roleName.String())
   198  	}
   199  	err := setRuntimeToConfig(config, section)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	return config, nil
   204  }
   205  
   206  func getBearerToken(section *ini.Section) (*Config, error) {
   207  	bearerToken, err := section.GetKey("bearer_token")
   208  	if err != nil {
   209  		return nil, errors.New("missing required bearer_token option in profile for bearer")
   210  	}
   211  	if bearerToken.String() == "" {
   212  		return nil, errors.New("bearer_token cannot be empty")
   213  	}
   214  	config := &Config{
   215  		Type:        tea.String("bearer"),
   216  		BearerToken: tea.String(bearerToken.String()),
   217  	}
   218  	return config, nil
   219  }
   220  
   221  func getSTS(section *ini.Section) (*Config, error) {
   222  	accesskeyid, err := section.GetKey("access_key_id")
   223  	if err != nil {
   224  		return nil, errors.New("missing required access_key_id option in profile for sts")
   225  	}
   226  	if accesskeyid.String() == "" {
   227  		return nil, errors.New("access_key_id cannot be empty")
   228  	}
   229  	accessKeySecret, err := section.GetKey("access_key_secret")
   230  	if err != nil {
   231  		return nil, errors.New("missing required access_key_secret option in profile for sts")
   232  	}
   233  	if accessKeySecret.String() == "" {
   234  		return nil, errors.New("access_key_secret cannot be empty")
   235  	}
   236  	securityToken, err := section.GetKey("security_token")
   237  	if err != nil {
   238  		return nil, errors.New("missing required security_token option in profile for sts")
   239  	}
   240  	if securityToken.String() == "" {
   241  		return nil, errors.New("security_token cannot be empty")
   242  	}
   243  	config := &Config{
   244  		Type:            tea.String("sts"),
   245  		AccessKeyId:     tea.String(accesskeyid.String()),
   246  		AccessKeySecret: tea.String(accessKeySecret.String()),
   247  		SecurityToken:   tea.String(securityToken.String()),
   248  	}
   249  	return config, nil
   250  }
   251  
   252  func getAccessKey(section *ini.Section) (*Config, error) {
   253  	accesskeyid, err := section.GetKey("access_key_id")
   254  	if err != nil {
   255  		return nil, errors.New("missing required access_key_id option in profile for access_key")
   256  	}
   257  	if accesskeyid.String() == "" {
   258  		return nil, errors.New("access_key_id cannot be empty")
   259  	}
   260  	accessKeySecret, err := section.GetKey("access_key_secret")
   261  	if err != nil {
   262  		return nil, errors.New("missing required access_key_secret option in profile for access_key")
   263  	}
   264  	if accessKeySecret.String() == "" {
   265  		return nil, errors.New("access_key_secret cannot be empty")
   266  	}
   267  	config := &Config{
   268  		Type:            tea.String("access_key"),
   269  		AccessKeyId:     tea.String(accesskeyid.String()),
   270  		AccessKeySecret: tea.String(accessKeySecret.String()),
   271  	}
   272  	return config, nil
   273  }
   274  
   275  func getType(path, profile string) (*ini.Key, *ini.Section, error) {
   276  	ini, err := ini.Load(path)
   277  	if err != nil {
   278  		return nil, nil, errors.New("ERROR: Can not open file " + err.Error())
   279  	}
   280  
   281  	section, err := ini.GetSection(profile)
   282  	if err != nil {
   283  		return nil, nil, errors.New("ERROR: Can not load section " + err.Error())
   284  	}
   285  
   286  	value, err := section.GetKey("type")
   287  	if err != nil {
   288  		return nil, nil, errors.New("missing required type option " + err.Error())
   289  	}
   290  	return value, section, nil
   291  }
   292  
   293  func checkDefaultPath() (path string, err error) {
   294  	path = utils.GetHomePath()
   295  	if path == "" {
   296  		return "", errors.New("the default credential file path is invalid")
   297  	}
   298  	path = strings.Replace("~/.alibabacloud/credentials", "~", path, 1)
   299  	_, err = hookState(os.Stat(path))
   300  	if err != nil {
   301  		return "", nil
   302  	}
   303  	return path, nil
   304  }
   305  
   306  func setRuntimeToConfig(config *Config, section *ini.Section) error {
   307  	rawTimeout, _ := section.GetKey("timeout")
   308  	rawConnectTimeout, _ := section.GetKey("connect_timeout")
   309  	rawProxy, _ := section.GetKey("proxy")
   310  	rawHost, _ := section.GetKey("host")
   311  	if rawProxy != nil {
   312  		config.Proxy = tea.String(rawProxy.String())
   313  	}
   314  	if rawConnectTimeout != nil {
   315  		connectTimeout, err := rawConnectTimeout.Int()
   316  		if err != nil {
   317  			return fmt.Errorf("please set connect_timeout with an int value")
   318  		}
   319  		config.ConnectTimeout = tea.Int(connectTimeout)
   320  	}
   321  	if rawTimeout != nil {
   322  		timeout, err := rawTimeout.Int()
   323  		if err != nil {
   324  			return fmt.Errorf("please set timeout with an int value")
   325  		}
   326  		config.Timeout = tea.Int(timeout)
   327  	}
   328  	if rawHost != nil {
   329  		config.Host = tea.String(rawHost.String())
   330  	}
   331  	return nil
   332  }