credentials/providers/profile.go (142 lines of code) (raw):
package providers
import (
"errors"
"fmt"
"os"
"path"
"github.com/aliyun/credentials-go/credentials/internal/utils"
"gopkg.in/ini.v1"
)
type ProfileCredentialsProvider struct {
profileName string
innerProvider CredentialsProvider
}
type ProfileCredentialsProviderBuilder struct {
provider *ProfileCredentialsProvider
}
func NewProfileCredentialsProviderBuilder() (builder *ProfileCredentialsProviderBuilder) {
return &ProfileCredentialsProviderBuilder{
provider: &ProfileCredentialsProvider{},
}
}
func (b *ProfileCredentialsProviderBuilder) WithProfileName(profileName string) *ProfileCredentialsProviderBuilder {
b.provider.profileName = profileName
return b
}
func (b *ProfileCredentialsProviderBuilder) Build() (provider *ProfileCredentialsProvider, err error) {
// 优先级:
// 1. 使用显示指定的 profileName
// 2. 使用环境变量(ALIBABA_CLOUD_PROFILE)指定的 profileName
// 3. 兜底使用 default 作为 profileName
b.provider.profileName = utils.GetDefaultString(b.provider.profileName, os.Getenv("ALIBABA_CLOUD_PROFILE"), "default")
provider = b.provider
return
}
func (provider *ProfileCredentialsProvider) getCredentialsProvider(ini *ini.File) (credentialsProvider CredentialsProvider, err error) {
section, err := ini.GetSection(provider.profileName)
if err != nil {
err = errors.New("ERROR: Can not load section" + err.Error())
return
}
value, err := section.GetKey("type")
if err != nil {
err = errors.New("ERROR: Can not find credential type" + err.Error())
return
}
switch value.String() {
case "access_key":
value1, err1 := section.GetKey("access_key_id")
value2, err2 := section.GetKey("access_key_secret")
if err1 != nil || err2 != nil {
err = errors.New("ERROR: Failed to get value")
return
}
if value1.String() == "" || value2.String() == "" {
err = errors.New("ERROR: Value can't be empty")
return
}
credentialsProvider, err = NewStaticAKCredentialsProviderBuilder().
WithAccessKeyId(value1.String()).
WithAccessKeySecret(value2.String()).
Build()
case "ecs_ram_role":
value1, err1 := section.GetKey("role_name")
if err1 != nil {
err = errors.New("ERROR: Failed to get value")
return
}
credentialsProvider, err = NewECSRAMRoleCredentialsProviderBuilder().WithRoleName(value1.String()).Build()
case "ram_role_arn":
value1, err1 := section.GetKey("access_key_id")
value2, err2 := section.GetKey("access_key_secret")
value3, err3 := section.GetKey("role_arn")
value4, err4 := section.GetKey("role_session_name")
if err1 != nil || err2 != nil || err3 != nil || err4 != nil {
err = errors.New("ERROR: Failed to get value")
return
}
if value1.String() == "" || value2.String() == "" || value3.String() == "" || value4.String() == "" {
err = errors.New("ERROR: Value can't be empty")
return
}
previous, err5 := NewStaticAKCredentialsProviderBuilder().
WithAccessKeyId(value1.String()).
WithAccessKeySecret(value2.String()).
Build()
if err5 != nil {
err = errors.New("get previous credentials provider failed")
return
}
rawPolicy, _ := section.GetKey("policy")
policy := ""
if rawPolicy != nil {
policy = rawPolicy.String()
}
credentialsProvider, err = NewRAMRoleARNCredentialsProviderBuilder().
WithCredentialsProvider(previous).
WithRoleArn(value3.String()).
WithRoleSessionName(value4.String()).
WithPolicy(policy).
WithDurationSeconds(3600).
Build()
default:
err = errors.New("ERROR: Failed to get credential")
}
return
}
func (provider *ProfileCredentialsProvider) GetCredentials() (cc *Credentials, err error) {
if provider.innerProvider == nil {
sharedCfgPath := os.Getenv("ALIBABA_CLOUD_CREDENTIALS_FILE")
if sharedCfgPath == "" {
homeDir := getHomePath()
if homeDir == "" {
err = fmt.Errorf("cannot found home dir")
return
}
sharedCfgPath = path.Join(homeDir, ".alibabacloud/credentials")
}
ini, err1 := ini.Load(sharedCfgPath)
if err1 != nil {
err = errors.New("ERROR: Can not open file" + err1.Error())
return
}
provider.innerProvider, err = provider.getCredentialsProvider(ini)
if err != nil {
return
}
}
innerCC, err := provider.innerProvider.GetCredentials()
if err != nil {
return
}
providerName := innerCC.ProviderName
if providerName == "" {
providerName = provider.innerProvider.GetProviderName()
}
cc = &Credentials{
AccessKeyId: innerCC.AccessKeyId,
AccessKeySecret: innerCC.AccessKeySecret,
SecurityToken: innerCC.SecurityToken,
ProviderName: fmt.Sprintf("%s/%s", provider.GetProviderName(), providerName),
}
return
}
func (provider *ProfileCredentialsProvider) GetProviderName() string {
return "profile"
}