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 }