...

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

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

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

View as plain text