profile.go raw

   1  package providers
   2  
   3  import (
   4  	"errors"
   5  	"fmt"
   6  	"os"
   7  	"path"
   8  
   9  	"github.com/aliyun/credentials-go/credentials/internal/utils"
  10  	"gopkg.in/ini.v1"
  11  )
  12  
  13  type ProfileCredentialsProvider struct {
  14  	profileName   string
  15  	innerProvider CredentialsProvider
  16  }
  17  
  18  type ProfileCredentialsProviderBuilder struct {
  19  	provider *ProfileCredentialsProvider
  20  }
  21  
  22  func NewProfileCredentialsProviderBuilder() (builder *ProfileCredentialsProviderBuilder) {
  23  	return &ProfileCredentialsProviderBuilder{
  24  		provider: &ProfileCredentialsProvider{},
  25  	}
  26  }
  27  
  28  func (b *ProfileCredentialsProviderBuilder) WithProfileName(profileName string) *ProfileCredentialsProviderBuilder {
  29  	b.provider.profileName = profileName
  30  	return b
  31  }
  32  
  33  func (b *ProfileCredentialsProviderBuilder) Build() (provider *ProfileCredentialsProvider, err error) {
  34  	// 优先级:
  35  	// 1. 使用显示指定的 profileName
  36  	// 2. 使用环境变量(ALIBABA_CLOUD_PROFILE)指定的 profileName
  37  	// 3. 兜底使用 default 作为 profileName
  38  	b.provider.profileName = utils.GetDefaultString(b.provider.profileName, os.Getenv("ALIBABA_CLOUD_PROFILE"), "default")
  39  
  40  	provider = b.provider
  41  	return
  42  }
  43  
  44  func (provider *ProfileCredentialsProvider) getCredentialsProvider(ini *ini.File) (credentialsProvider CredentialsProvider, err error) {
  45  	section, err := ini.GetSection(provider.profileName)
  46  	if err != nil {
  47  		err = errors.New("ERROR: Can not load section" + err.Error())
  48  		return
  49  	}
  50  
  51  	value, err := section.GetKey("type")
  52  	if err != nil {
  53  		err = errors.New("ERROR: Can not find credential type" + err.Error())
  54  		return
  55  	}
  56  
  57  	switch value.String() {
  58  	case "access_key":
  59  		value1, err1 := section.GetKey("access_key_id")
  60  		value2, err2 := section.GetKey("access_key_secret")
  61  		if err1 != nil || err2 != nil {
  62  			err = errors.New("ERROR: Failed to get value")
  63  			return
  64  		}
  65  
  66  		if value1.String() == "" || value2.String() == "" {
  67  			err = errors.New("ERROR: Value can't be empty")
  68  			return
  69  		}
  70  
  71  		credentialsProvider, err = NewStaticAKCredentialsProviderBuilder().
  72  			WithAccessKeyId(value1.String()).
  73  			WithAccessKeySecret(value2.String()).
  74  			Build()
  75  	case "ecs_ram_role":
  76  		value1, err1 := section.GetKey("role_name")
  77  		if err1 != nil {
  78  			err = errors.New("ERROR: Failed to get value")
  79  			return
  80  		}
  81  		credentialsProvider, err = NewECSRAMRoleCredentialsProviderBuilder().WithRoleName(value1.String()).Build()
  82  	case "ram_role_arn":
  83  		value1, err1 := section.GetKey("access_key_id")
  84  		value2, err2 := section.GetKey("access_key_secret")
  85  		value3, err3 := section.GetKey("role_arn")
  86  		value4, err4 := section.GetKey("role_session_name")
  87  		if err1 != nil || err2 != nil || err3 != nil || err4 != nil {
  88  			err = errors.New("ERROR: Failed to get value")
  89  			return
  90  		}
  91  		if value1.String() == "" || value2.String() == "" || value3.String() == "" || value4.String() == "" {
  92  			err = errors.New("ERROR: Value can't be empty")
  93  			return
  94  		}
  95  		previous, err5 := NewStaticAKCredentialsProviderBuilder().
  96  			WithAccessKeyId(value1.String()).
  97  			WithAccessKeySecret(value2.String()).
  98  			Build()
  99  		if err5 != nil {
 100  			err = errors.New("get previous credentials provider failed")
 101  			return
 102  		}
 103  		rawPolicy, _ := section.GetKey("policy")
 104  		policy := ""
 105  		if rawPolicy != nil {
 106  			policy = rawPolicy.String()
 107  		}
 108  
 109  		credentialsProvider, err = NewRAMRoleARNCredentialsProviderBuilder().
 110  			WithCredentialsProvider(previous).
 111  			WithRoleArn(value3.String()).
 112  			WithRoleSessionName(value4.String()).
 113  			WithPolicy(policy).
 114  			WithDurationSeconds(3600).
 115  			Build()
 116  	default:
 117  		err = errors.New("ERROR: Failed to get credential")
 118  	}
 119  	return
 120  }
 121  
 122  func (provider *ProfileCredentialsProvider) GetCredentials() (cc *Credentials, err error) {
 123  	if provider.innerProvider == nil {
 124  		sharedCfgPath := os.Getenv("ALIBABA_CLOUD_CREDENTIALS_FILE")
 125  		if sharedCfgPath == "" {
 126  			homeDir := getHomePath()
 127  			if homeDir == "" {
 128  				err = fmt.Errorf("cannot found home dir")
 129  				return
 130  			}
 131  
 132  			sharedCfgPath = path.Join(homeDir, ".alibabacloud/credentials")
 133  		}
 134  
 135  		ini, err1 := ini.Load(sharedCfgPath)
 136  		if err1 != nil {
 137  			err = errors.New("ERROR: Can not open file" + err1.Error())
 138  			return
 139  		}
 140  
 141  		provider.innerProvider, err = provider.getCredentialsProvider(ini)
 142  		if err != nil {
 143  			return
 144  		}
 145  	}
 146  
 147  	innerCC, err := provider.innerProvider.GetCredentials()
 148  	if err != nil {
 149  		return
 150  	}
 151  
 152  	providerName := innerCC.ProviderName
 153  	if providerName == "" {
 154  		providerName = provider.innerProvider.GetProviderName()
 155  	}
 156  
 157  	cc = &Credentials{
 158  		AccessKeyId:     innerCC.AccessKeyId,
 159  		AccessKeySecret: innerCC.AccessKeySecret,
 160  		SecurityToken:   innerCC.SecurityToken,
 161  		ProviderName:    fmt.Sprintf("%s/%s", provider.GetProviderName(), providerName),
 162  	}
 163  
 164  	return
 165  }
 166  
 167  func (provider *ProfileCredentialsProvider) GetProviderName() string {
 168  	return "profile"
 169  }
 170