浏览代码

Add credential providers

Chaohua Xu 6 年之前
父节点
当前提交
75a8644d75

+ 76 - 0
integration/credential_test.go

@@ -1,6 +1,15 @@
 package integration
 
 import (
+	"bufio"
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"strings"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/cs"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
 	"github.com/stretchr/testify/assert"
@@ -64,3 +73,70 @@ func Test_DescribeRegionsWithRPCrequestWithArn(t *testing.T) {
 	assert.Nil(t, err)
 	assert.Equal(t, 36, len(response.RequestId))
 }
+
+func TestDescribeRegionsWithProviderAndAk(t *testing.T) {
+	os.Setenv(provider.ENVAccessKeyID, os.Getenv("ACCESS_KEY_ID"))
+	os.Setenv(provider.ENVAccessKeySecret, os.Getenv("ACCESS_KEY_SECRET"))
+	request := requests.NewCommonRequest()
+	request.Version = "2014-05-26"
+	request.Product = "Ecs"
+	request.ApiName = "DescribeRegions"
+	request.SetDomain("ecs.aliyuncs.com")
+	request.TransToAcsRequest()
+	client, err := sdk.NewClientWithProvider(os.Getenv("REGION_ID"))
+	assert.Nil(t, err)
+	response, err := client.ProcessCommonRequest(request)
+	assert.Nil(t, err)
+	assert.True(t, response.IsSuccess())
+}
+
+func TestDescribeRegionsWithProviderAndRsaKeyPair(t *testing.T) {
+	request := requests.NewCommonRequest()
+	request.Version = "2014-05-26"
+	request.Product = "Ecs"
+	request.ApiName = "DescribeRegions"
+	request.SetDomain("ecs.ap-northeast-1.aliyuncs.com")
+	request.TransToAcsRequest()
+
+	key := os.Getenv("RSA_FILE_AES_KEY")
+
+	srcfile, err := os.Open("./encyptfile")
+	assert.Nil(t, err)
+	defer srcfile.Close()
+
+	buf := new(bytes.Buffer)
+	read := bufio.NewReader(srcfile)
+	read.WriteTo(buf)
+
+	block, err := aes.NewCipher([]byte(key))
+	assert.Nil(t, err)
+
+	origData := buf.Bytes()
+	blockdec := cipher.NewCBCDecrypter(block, []byte(key)[:block.BlockSize()])
+	orig := make([]byte, len(origData))
+	blockdec.CryptBlocks(orig, origData)
+	orig = PKCS7UnPadding(orig)
+
+	cyphbuf := bytes.NewBuffer(orig)
+	scan := bufio.NewScanner(cyphbuf)
+	var data string
+	for scan.Scan() {
+		if strings.HasPrefix(scan.Text(), "----") {
+			continue
+		}
+		data += scan.Text() + "\n"
+	}
+
+	client, err := sdk.NewClientWithRsaKeyPair("ap-northeast-1", os.Getenv("PUBLIC_KEY_ID"), data, 3600)
+	assert.Nil(t, err)
+
+	response, err := client.ProcessCommonRequest(request)
+	assert.Nil(t, err)
+	assert.True(t, response.IsSuccess())
+}
+
+func PKCS7UnPadding(origData []byte) []byte {
+	length := len(origData)
+	unpadding := int(origData[length-1])
+	return origData[:(length - unpadding)]
+}

二进制
integration/encyptfile


+ 12 - 12
sdk/auth/credentials/ecs_ram_role.go

@@ -1,17 +1,5 @@
 package credentials
 
-// Deprecated: Use EcsRamRoleCredential in this package instead.
-type StsRoleNameOnEcsCredential struct {
-	RoleName string
-}
-
-// Deprecated: Use NewEcsRamRoleCredential in this package instead.
-func NewStsRoleNameOnEcsCredential(roleName string) *StsRoleNameOnEcsCredential {
-	return &StsRoleNameOnEcsCredential{
-		RoleName: roleName,
-	}
-}
-
 func (oldCred *StsRoleNameOnEcsCredential) ToEcsRamRoleCredential() *EcsRamRoleCredential {
 	return &EcsRamRoleCredential{
 		RoleName: oldCred.RoleName,
@@ -27,3 +15,15 @@ func NewEcsRamRoleCredential(roleName string) *EcsRamRoleCredential {
 		RoleName: roleName,
 	}
 }
+
+// Deprecated: Use EcsRamRoleCredential in this package instead.
+type StsRoleNameOnEcsCredential struct {
+	RoleName string
+}
+
+// Deprecated: Use NewEcsRamRoleCredential in this package instead.
+func NewStsRoleNameOnEcsCredential(roleName string) *StsRoleNameOnEcsCredential {
+	return &StsRoleNameOnEcsCredential{
+		RoleName: roleName,
+	}
+}

+ 30 - 0
sdk/auth/credentials/provider/env.go

@@ -0,0 +1,30 @@
+package provider
+
+import (
+	"errors"
+	"os"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
+)
+
+type EnvProvider struct{}
+
+var ProviderEnv = new(EnvProvider)
+
+func NewEnvProvider() Provider {
+	return &EnvProvider{}
+}
+
+func (p *EnvProvider) Resolve() (auth.Credential, error) {
+	accessKeyID, ok1 := os.LookupEnv(ENVAccessKeyID)
+	accessKeySecret, ok2 := os.LookupEnv(ENVAccessKeySecret)
+	if !ok1 || !ok2 {
+		return nil, nil
+	}
+	if accessKeyID == "" || accessKeySecret == "" {
+		return nil, errors.New("Environmental variable (ALIBABACLOUD_ACCESS_KEY_ID or ALIBABACLOUD_ACCESS_KEY_SECRET) is empty")
+	}
+	return credentials.NewAccessKeyCredential(accessKeyID, accessKeySecret), nil
+}

+ 30 - 0
sdk/auth/credentials/provider/env_test.go

@@ -0,0 +1,30 @@
+package provider_test
+
+import (
+	"os"
+	"testing"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+)
+
+func TestEnvResolve(t *testing.T) {
+	p := provider.NewEnvProvider()
+	assert.Equal(t, &provider.EnvProvider{}, p)
+	c, err := p.Resolve()
+	assert.Nil(t, c)
+	assert.Nil(t, err)
+	os.Setenv(provider.ENVAccessKeyID, "")
+	os.Setenv(provider.ENVAccessKeySecret, "")
+	c, err = p.Resolve()
+	assert.Nil(t, c)
+	assert.EqualError(t, err, "Environmental variable (ALIBABACLOUD_ACCESS_KEY_ID or ALIBABACLOUD_ACCESS_KEY_SECRET) is empty")
+	os.Setenv(provider.ENVAccessKeyID, "AccessKeyId")
+	os.Setenv(provider.ENVAccessKeySecret, "AccessKeySecret")
+	c, err = p.Resolve()
+	assert.Nil(t, err)
+	assert.Equal(t, &credentials.AccessKeyCredential{"AccessKeyId", "AccessKeySecret"}, c)
+}

+ 92 - 0
sdk/auth/credentials/provider/instance_credentials.go

@@ -0,0 +1,92 @@
+package provider
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+)
+
+var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
+
+type InstanceCredentialsProvider struct{}
+
+var ProviderInstance = new(InstanceCredentialsProvider)
+
+var HookGet = func(fn func(string) (int, []byte, error)) func(string) (int, []byte, error) {
+	return fn
+}
+
+func NewInstanceCredentialsProvider() Provider {
+	return &InstanceCredentialsProvider{}
+}
+
+func (p *InstanceCredentialsProvider) Resolve() (auth.Credential, error) {
+	roleName, ok := os.LookupEnv(ENVEcsMetadata)
+	if !ok {
+		return nil, nil
+	}
+	if roleName == "" {
+		return nil, errors.New("Environmental variable 'ALIBABA_CLOUD_ECS_METADATA' are empty")
+	}
+	status, content, err := HookGet(get)(securityCredURL + roleName)
+	if err != nil {
+		return nil, err
+	}
+	if status != 200 {
+		if status == 404 {
+			return nil, fmt.Errorf("The role was not found in the instance")
+		}
+		return nil, fmt.Errorf("Received %d when getting security credentials for %s", status, roleName)
+	}
+	body := make(map[string]interface{})
+
+	if err := json.Unmarshal(content, &body); err != nil {
+		return nil, err
+	}
+
+	accessKeyID, err := extractString(body, "AccessKeyId")
+	if err != nil {
+		return nil, err
+	}
+	accessKeySecret, err := extractString(body, "AccessKeySecret")
+	if err != nil {
+		return nil, err
+	}
+	securityToken, err := extractString(body, "SecurityToken")
+	if err != nil {
+		return nil, err
+	}
+
+	return credentials.NewStsTokenCredential(accessKeyID, accessKeySecret, securityToken), nil
+}
+
+func get(url string) (status int, content []byte, err error) {
+	httpClient := http.DefaultClient
+	httpClient.Timeout = time.Second * 1
+	resp, err := httpClient.Get(url)
+	if err != nil {
+		return
+	}
+	defer resp.Body.Close()
+	content, err = ioutil.ReadAll(resp.Body)
+	return resp.StatusCode, content, err
+}
+
+func extractString(m map[string]interface{}, key string) (string, error) {
+	raw, ok := m[key]
+	if !ok {
+		return "", fmt.Errorf("%s not in map", key)
+	}
+	str, ok := raw.(string)
+	if !ok {
+		return "", fmt.Errorf("%s is not a string in map", key)
+	}
+	return str, nil
+}

+ 64 - 0
sdk/auth/credentials/provider/instance_credentials_test.go

@@ -0,0 +1,64 @@
+package provider_test
+
+import (
+	"os"
+	"testing"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+)
+
+func TestInstanceCredentialsProvider(t *testing.T) {
+	p := provider.NewInstanceCredentialsProvider()
+	c, err := p.Resolve()
+	assert.Nil(t, c)
+	assert.Nil(t, err)
+
+	os.Setenv(provider.ENVEcsMetadata, "")
+	c, err = p.Resolve()
+	assert.Nil(t, c)
+	assert.EqualError(t, err, "Environmental variable 'ALIBABA_CLOUD_ECS_METADATA' are empty")
+
+	os.Setenv(provider.ENVEcsMetadata, "test")
+	c, err = p.Resolve()
+	assert.Nil(t, c)
+	assert.NotNil(t, err)
+
+	provider.HookGet = func(fn func(string) (int, []byte, error)) func(string) (int, []byte, error) {
+		return func(string) (int, []byte, error) {
+			return 404, []byte(""), nil
+		}
+	}
+	c, err = p.Resolve()
+	assert.Nil(t, c)
+	assert.EqualError(t, err, "The role was not found in the instance")
+
+	provider.HookGet = func(fn func(string) (int, []byte, error)) func(string) (int, []byte, error) {
+		return func(string) (int, []byte, error) {
+			return 400, []byte(""), nil
+		}
+	}
+	c, err = p.Resolve()
+	assert.Nil(t, c)
+	assert.EqualError(t, err, "Received 400 when getting security credentials for test")
+
+	provider.HookGet = func(fn func(string) (int, []byte, error)) func(string) (int, []byte, error) {
+		return func(string) (int, []byte, error) {
+			return 200, []byte(`{
+				"AccessKeyId" : "STS.*******",
+				"AccessKeySecret" : "*******",
+				"Expiration" : "2019-01-28T15:15:56Z",
+				"SecurityToken" : "bbbbb",
+				"LastUpdated" : "2019-01-28T09:15:55Z",
+				"Code" : "Success"
+			  }`), nil
+		}
+	}
+	c, err = p.Resolve()
+	assert.Nil(t, err)
+	assert.Equal(t, credentials.NewStsTokenCredential("STS.*******", "*******", "bbbbb"), c)
+
+}

+ 159 - 0
sdk/auth/credentials/provider/profile_credentials.go

@@ -0,0 +1,159 @@
+package provider
+
+import (
+	"bufio"
+	"errors"
+	"os"
+	"runtime"
+	"strings"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+
+	ini "gopkg.in/ini.v1"
+)
+
+type ProfileProvider struct {
+	Profile string
+}
+
+var ProviderProfile = NewProfileProvider()
+
+// NewProfileProvider receive zero or more parameters,
+// when length of name is 0, the value of field Profile will be "default",
+// and when there are multiple inputs, the function will take the
+// first one and  discard the other values.
+func NewProfileProvider(name ...string) Provider {
+	p := new(ProfileProvider)
+	if len(name) == 0 {
+		p.Profile = "default"
+	} else {
+		p.Profile = name[0]
+	}
+	return p
+}
+
+// Resolve implements the Provider interface
+// when credential type is rsa_key_pair, the content of private_key file
+// must be able to be parsed directly into the required string
+// that NewRsaKeyPairCredential function needed
+func (p *ProfileProvider) Resolve() (auth.Credential, error) {
+	path, ok := os.LookupEnv(ENVCredentialFile)
+	if !ok {
+		path, err := checkDefaultPath()
+		if err != nil {
+			return nil, err
+		}
+		if path == "" {
+			return nil, nil
+		}
+	} else if path == "" {
+		return nil, errors.New("Environment variable '" + ENVCredentialFile + "' cannot be empty")
+	}
+
+	ini, err := ini.Load(path)
+	if err != nil {
+		return nil, errors.New("ERROR: Can not open file" + err.Error())
+	}
+
+	section, err := ini.GetSection(p.Profile)
+	if err != nil {
+		return nil, errors.New("ERROR: Can not load section" + err.Error())
+	}
+
+	value, err := section.GetKey("type")
+	if err != nil {
+		return nil, errors.New("ERROR: Can not find credential type" + err.Error())
+	}
+
+	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 {
+			return nil, errors.New("ERROR: Failed to get value")
+		}
+		if value1.String() == "" || value2.String() == "" {
+			return nil, errors.New("ERROR: Value can't be empty")
+		}
+		return credentials.NewAccessKeyCredential(value1.String(), value2.String()), nil
+	case "ecs_ram_role":
+		value1, err1 := section.GetKey("role_name")
+		if err1 != nil {
+			return nil, errors.New("ERROR: Failed to get value")
+		}
+		if value1.String() == "" {
+			return nil, errors.New("ERROR: Value can't be empty")
+		}
+		return credentials.NewEcsRamRoleCredential(value1.String()), nil
+	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 {
+			return nil, errors.New("ERROR: Failed to get value")
+		}
+		if value1.String() == "" || value2.String() == "" || value3.String() == "" || value4.String() == "" {
+			return nil, errors.New("ERROR: Value can't be empty")
+		}
+		return credentials.NewRamRoleArnCredential(value1.String(), value2.String(), value3.String(), value4.String(), 3600), nil
+	case "rsa_key_pair":
+		value1, err1 := section.GetKey("public_key_id")
+		value2, err2 := section.GetKey("private_key_file")
+		if err1 != nil || err2 != nil {
+			return nil, errors.New("ERROR: Failed to get value")
+		}
+		if value1.String() == "" || value2.String() == "" {
+			return nil, errors.New("ERROR: Value can't be empty")
+		}
+		file, err := os.Open(value2.String())
+		if err != nil {
+			return nil, errors.New("ERROR: Can not get private_key")
+		}
+		defer file.Close()
+		var privateKey string
+		scan := bufio.NewScanner(file)
+		var data string
+		for scan.Scan() {
+			if strings.HasPrefix(scan.Text(), "----") {
+				continue
+			}
+			data += scan.Text() + "\n"
+		}
+		return credentials.NewRsaKeyPairCredential(privateKey, value1.String(), 3600), nil
+
+	default:
+		return nil, errors.New("ERROR: Failed to get credential")
+	}
+}
+
+// GetHomePath return home directory according to the system.
+// if the environmental virables does not exist, will return empty
+func GetHomePath() string {
+	if runtime.GOOS == "windows" {
+		path, ok := os.LookupEnv("USERPROFILE")
+		if !ok {
+			return ""
+		}
+		return path
+	}
+	path, ok := os.LookupEnv("HOME")
+	if !ok {
+		return ""
+	}
+	return path
+}
+
+func checkDefaultPath() (path string, err error) {
+	path = GetHomePath()
+	if path == "" {
+		return "", errors.New("The default credential file path is invalid")
+	}
+	path = strings.Replace("~/.alibabacloud/credentials", "~", path, 1)
+	_, err = os.Stat(path)
+	if err != nil {
+		return "", nil
+	}
+	return path, nil
+}

+ 96 - 0
sdk/auth/credentials/provider/profile_credentials_test.go

@@ -0,0 +1,96 @@
+package provider_test
+
+import (
+	"os"
+	"testing"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+)
+
+var inistr = `
+[default]              
+enable = true                    
+type = access_key                
+access_key_id = foo               
+access_key_secret = bar            
+                   
+[client1]                         
+type = ecs_ram_role                
+role_name = EcsRamRoleTest       
+
+[client2]                                         
+type = ram_role_arn                
+access_key_id = foo
+access_key_secret = bar
+role_arn = role_arn
+role_session_name = session_name
+
+[client3]                          
+type = bearer_token                
+bearer_token = bearer_token        
+
+[client4]                          
+type = rsa_key_pair               
+public_key_id = publicKeyId       
+private_key_file = ./pk.pem
+`
+var privatekey = `this is privatekey`
+
+func TestProfileProvider(t *testing.T) {
+	p := provider.NewProfileProvider()
+	value, ok := p.(*provider.ProfileProvider)
+	assert.True(t, ok)
+	assert.Equal(t, value.Profile, "default")
+
+	p = provider.NewProfileProvider("first")
+	value, ok = p.(*provider.ProfileProvider)
+	assert.True(t, ok)
+	assert.Equal(t, value.Profile, "first")
+
+	c, err := p.Resolve()
+	assert.Nil(t, c)
+	assert.Nil(t, err)
+
+	os.Setenv(provider.ENVCredentialFile, "./credentials")
+
+	file, err := os.Create("./credentials")
+	assert.Nil(t, err)
+	file.WriteString(inistr)
+	file.Close()
+	defer os.Remove("./credentials")
+
+	p = provider.NewProfileProvider()
+	c, err = p.Resolve()
+	assert.Equal(t, credentials.NewAccessKeyCredential("foo", "bar"), c)
+	assert.Nil(t, err)
+
+	p = provider.NewProfileProvider("client1")
+	c, err = p.Resolve()
+	assert.Equal(t, credentials.NewEcsRamRoleCredential("EcsRamRoleTest"), c)
+	assert.Nil(t, err)
+
+	p = provider.NewProfileProvider("client2")
+	c, err = p.Resolve()
+	assert.Equal(t, credentials.NewRamRoleArnCredential("foo", "bar", "role_arn", "session_name", 3600), c)
+	assert.Nil(t, err)
+
+	file, err = os.Create("./pk.pem")
+	assert.Nil(t, err)
+	file.WriteString(privatekey)
+	file.Close()
+
+	p = provider.NewProfileProvider("client4")
+	c, err = p.Resolve()
+	assert.Equal(t, credentials.NewRsaKeyPairCredential("", "publicKeyId", 3600), c)
+	assert.Nil(t, err)
+	defer os.Remove(`./pk.pem`)
+
+	// p = provider.NewProfileProvider("client3")
+	// c, err = p.Resolve()
+	// assert.Equal(t, credentials.NewBearerCredential("bearer_token"), c)
+	// assert.Nil(t, err)
+}

+ 19 - 0
sdk/auth/credentials/provider/provider.go

@@ -0,0 +1,19 @@
+package provider
+
+import (
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
+)
+
+//Environmental virables that may be used by the provider
+const (
+	ENVAccessKeyID     = "ALIBABA_CLOUD_ACCESS_KEY_ID"
+	ENVAccessKeySecret = "ALIBABA_CLOUD_ACCESS_KEY_SECRET"
+	ENVCredentialFile  = "ALIBABA_CLOUD_CREDENTIALS_FILE"
+	ENVEcsMetadata     = "ALIBABA_CLOUD_ECS_METADATA"
+	PATHCredentialFile = "~/.alibabacloud/credentials"
+)
+
+// When you want to customize the provider, you only need to implement the method of the interface.
+type Provider interface {
+	Resolve() (auth.Credential, error)
+}

+ 34 - 0
sdk/auth/credentials/provider/provider_chain.go

@@ -0,0 +1,34 @@
+package provider
+
+import (
+	"errors"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
+)
+
+type ProviderChain struct {
+	Providers []Provider
+}
+
+var defaultproviders = []Provider{ProviderEnv, ProviderProfile, ProviderInstance}
+var DefaultChain = NewProviderChain(defaultproviders)
+
+func NewProviderChain(providers []Provider) Provider {
+	return &ProviderChain{
+		Providers: providers,
+	}
+}
+
+func (p *ProviderChain) Resolve() (auth.Credential, error) {
+	for _, provider := range p.Providers {
+		creds, err := provider.Resolve()
+		if err != nil {
+			return nil, err
+		} else if err == nil && creds == nil {
+			continue
+		}
+		return creds, err
+	}
+	return nil, errors.New("No credential found")
+
+}

+ 22 - 0
sdk/auth/credentials/provider/provider_chain_test.go

@@ -0,0 +1,22 @@
+package provider_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+)
+
+func TestProviderChain(t *testing.T) {
+	env := provider.NewEnvProvider()
+	pp := provider.NewProfileProvider()
+	instanceP := provider.NewInstanceCredentialsProvider()
+
+	pc := provider.NewProviderChain([]provider.Provider{env, pp, instanceP})
+
+	c, err := pc.Resolve()
+	assert.Equal(t, &credentials.AccessKeyCredential{AccessKeyId: "AccessKeyId", AccessKeySecret: "AccessKeySecret"}, c)
+	assert.Nil(t, err)
+}

+ 2 - 0
sdk/auth/credentials/providers/doc.go

@@ -0,0 +1,2 @@
+//Package providers Deprecated
+package providers

+ 1 - 0
sdk/auth/signers/algorithms.go

@@ -34,6 +34,7 @@ func ShaHmac1(source, secret string) string {
 }
 
 func Sha256WithRsa(source, secret string) string {
+	// block, _ := pem.Decode([]byte(secret))
 	decodeString, err := base64.StdEncoding.DecodeString(secret)
 	if err != nil {
 		panic(err)

+ 1 - 1
sdk/auth/signers/credential_updater.go

@@ -21,7 +21,7 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
 )
 
-const defaultInAdvanceScale = 0.8
+const defaultInAdvanceScale = 0.95
 
 type credentialUpdater struct {
 	credentialExpiration int

+ 1 - 1
sdk/auth/signers/signer_ecs_ram_role.go

@@ -24,7 +24,7 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
-	"github.com/jmespath/go-jmespath"
+	jmespath "github.com/jmespath/go-jmespath"
 )
 
 var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"

+ 3 - 2
sdk/auth/signers/signer_key_pair.go

@@ -24,7 +24,7 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
-	"github.com/jmespath/go-jmespath"
+	jmespath "github.com/jmespath/go-jmespath"
 )
 
 type SignerKeyPair struct {
@@ -97,7 +97,7 @@ func (signer *SignerKeyPair) GetExtraParam() map[string]string {
 }
 
 func (signer *SignerKeyPair) Sign(stringToSign, secretSuffix string) string {
-	secret := signer.sessionCredential.AccessKeyId + secretSuffix
+	secret := signer.sessionCredential.AccessKeySecret + secretSuffix
 	return ShaHmac1(stringToSign, secret)
 }
 
@@ -107,6 +107,7 @@ func (signer *SignerKeyPair) buildCommonRequest() (request *requests.CommonReque
 	request.Version = "2015-04-01"
 	request.ApiName = "GenerateSessionAccessKey"
 	request.Scheme = requests.HTTPS
+	request.SetDomain("sts.ap-northeast-1.aliyuncs.com")
 	request.QueryParams["PublicKeyId"] = signer.credential.PublicKeyId
 	request.QueryParams["DurationSeconds"] = strconv.Itoa(signer.credentialExpiration)
 	return

+ 1 - 1
sdk/auth/signers/signer_key_pair_test.go

@@ -170,5 +170,5 @@ func TestGetAccessKeyIdAndSign(t *testing.T) {
 	err = s.ensureCredential()
 	assert.Nil(t, err)
 	signature := s.Sign("string to sign", "/")
-	assert.Equal(t, "a3pLxd685VW4u078cdBKVh/Qf/A=", signature)
+	assert.Equal(t, "cgoenM6nl61t2wFdlaHVySuGAgY=", signature)
 }

+ 1 - 1
sdk/auth/signers/signer_ram_role_arn.go

@@ -25,7 +25,7 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
-	"github.com/jmespath/go-jmespath"
+	jmespath "github.com/jmespath/go-jmespath"
 )
 
 const (

+ 37 - 10
sdk/client.go

@@ -28,6 +28,8 @@ import (
 	"sync"
 	"time"
 
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints"
@@ -84,6 +86,19 @@ func (client *Client) GetHTTPSInsecure() bool {
 	return client.isInsecure
 }
 
+// InitWithProviderChain will get credential from the providerChain,
+// the RsaKeyPairCredential Only applicable to regionID `ap-northeast-1`,
+// if your providerChain may return a credential type with RsaKeyPairCredential,
+// please ensure your regionID is `ap-northeast-1`.
+func (client *Client) InitWithProviderChain(regionId string, provider provider.Provider) (err error) {
+	config := client.InitClientConfig()
+	credential, err := provider.Resolve()
+	if err != nil {
+		return
+	}
+	return client.InitWithOptions(regionId, config, credential)
+}
+
 func (client *Client) InitWithOptions(regionId string, config *Config, credential auth.Credential) (err error) {
 	client.isRunning = true
 	client.asyncChanLock = new(sync.RWMutex)
@@ -515,6 +530,18 @@ func NewClient() (client *Client, err error) {
 	return
 }
 
+func NewClientWithProvider(regionId string, providers ...provider.Provider) (client *Client, err error) {
+	client = &Client{}
+	var pc provider.Provider
+	if len(providers) == 0 {
+		pc = provider.DefaultChain
+	} else {
+		pc = provider.NewProviderChain(providers)
+	}
+	err = client.InitWithProviderChain(regionId, pc)
+	return
+}
+
 func NewClientWithOptions(regionId string, config *Config, credential auth.Credential) (client *Client, err error) {
 	client = &Client{}
 	err = client.InitWithOptions(regionId, config, credential)
@@ -557,16 +584,6 @@ func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, se
 	return
 }
 
-// Deprecated: Use NewClientWithRamRoleArn in this package instead.
-func NewClientWithStsRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
-	return NewClientWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
-}
-
-// Deprecated: Use NewClientWithEcsRamRole in this package instead.
-func NewClientWithStsRoleNameOnEcs(regionId string, roleName string) (client *Client, err error) {
-	return NewClientWithEcsRamRole(regionId, roleName)
-}
-
 func (client *Client) ProcessCommonRequest(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
 	request.TransToAcsRequest()
 	response = responses.NewCommonResponse()
@@ -593,3 +610,13 @@ func (client *Client) Shutdown() {
 	}
 	client.isRunning = false
 }
+
+// Deprecated: Use NewClientWithRamRoleArn in this package instead.
+func NewClientWithStsRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
+	return NewClientWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
+}
+
+// Deprecated: Use NewClientWithEcsRamRole in this package instead.
+func NewClientWithStsRoleNameOnEcs(regionId string, roleName string) (client *Client, err error) {
+	return NewClientWithEcsRamRole(regionId, roleName)
+}

+ 53 - 0
sdk/client_test.go

@@ -26,6 +26,8 @@ import (
 	"testing"
 	"time"
 
+	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
+
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
 
 	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
@@ -555,3 +557,54 @@ func TestClient_NewClientWithStsRoleArn(t *testing.T) {
 //	client.Shutdown()
 //	assert.Equal(t, false, client.isRunning)
 //}
+
+func TestInitWithProviderChain(t *testing.T) {
+
+	//testcase1: No any environment variable
+	c, err := NewClientWithProvider("cn-hangzhou")
+	assert.Empty(t, c)
+	assert.EqualError(t, err, "No credential found")
+
+	//testcase2: AK
+	os.Setenv(provider.ENVAccessKeyID, "AccessKeyId")
+	os.Setenv(provider.ENVAccessKeySecret, "AccessKeySecret")
+
+	c, err = NewClientWithProvider("cn-hangzhou")
+	assert.Nil(t, err)
+	expC, err := NewClientWithAccessKey("cn-hangzhou", "AccessKeyId", "AccessKeySecret")
+	assert.Nil(t, err)
+	assert.Equal(t, expC, c)
+
+	//testcase3:AK value is ""
+	os.Setenv(provider.ENVAccessKeyID, "")
+	os.Setenv(provider.ENVAccessKeySecret, "bbbb")
+	c, err = NewClientWithProvider("cn-hangzhou")
+	assert.EqualError(t, err, "Environmental variable (ALIBABACLOUD_ACCESS_KEY_ID or ALIBABACLOUD_ACCESS_KEY_SECRET) is empty")
+	assert.Empty(t, c)
+
+	//testcase4: Profile value is ""
+	os.Unsetenv(provider.ENVAccessKeyID)
+	os.Unsetenv(provider.ENVAccessKeySecret)
+	os.Setenv(provider.ENVCredentialFile, "")
+	c, err = NewClientWithProvider("cn-hangzhou")
+	assert.Empty(t, c)
+	assert.EqualError(t, err, "Environment variable 'ALIBABA_CLOUD_CREDENTIALS_FILE' cannot be empty")
+
+	//testcase5: Profile
+	os.Setenv(provider.ENVCredentialFile, "./profile")
+	c, err = NewClientWithProvider("cn-hangzhou")
+	assert.Empty(t, c)
+	assert.NotNil(t, err)
+	//testcase6:Instances
+	os.Unsetenv(provider.ENVCredentialFile)
+	os.Setenv(provider.ENVEcsMetadata, "")
+	c, err = NewClientWithProvider("cn-hangzhou")
+	assert.Empty(t, c)
+	assert.EqualError(t, err, "Environmental variable 'ALIBABA_CLOUD_ECS_METADATA' are empty")
+
+	//testcase7: Custom Providers
+	c, err = NewClientWithProvider("cn-hangzhou", provider.ProviderProfile, provider.ProviderEnv)
+	assert.Empty(t, c)
+	assert.EqualError(t, err, "No credential found")
+
+}