ram_role_arn_credentials_provider.go raw
1 package credentials
2
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "strconv"
8 "time"
9
10 "github.com/alibabacloud-go/tea/tea"
11 "github.com/aliyun/credentials-go/credentials/internal/utils"
12 "github.com/aliyun/credentials-go/credentials/request"
13 )
14
15 const defaultDurationSeconds = 3600
16
17 // RAMRoleArnCredentialsProvider is a kind of credentials
18 type RAMRoleArnCredentialsProvider struct {
19 *credentialUpdater
20 AccessKeyId string
21 AccessKeySecret string
22 SecurityToken string
23 RoleArn string
24 RoleSessionName string
25 RoleSessionExpiration int
26 Policy string
27 ExternalId string
28 sessionCredential *sessionCredential
29 runtime *utils.Runtime
30 }
31
32 type ramRoleArnResponse struct {
33 Credentials *credentialsInResponse `json:"Credentials" xml:"Credentials"`
34 }
35
36 type credentialsInResponse struct {
37 AccessKeyId string `json:"AccessKeyId" xml:"AccessKeyId"`
38 AccessKeySecret string `json:"AccessKeySecret" xml:"AccessKeySecret"`
39 SecurityToken string `json:"SecurityToken" xml:"SecurityToken"`
40 Expiration string `json:"Expiration" xml:"Expiration"`
41 }
42
43 func newRAMRoleArnl(accessKeyId, accessKeySecret, securityToken, roleArn, roleSessionName, policy string, roleSessionExpiration int, externalId string, runtime *utils.Runtime) *RAMRoleArnCredentialsProvider {
44 return &RAMRoleArnCredentialsProvider{
45 AccessKeyId: accessKeyId,
46 AccessKeySecret: accessKeySecret,
47 SecurityToken: securityToken,
48 RoleArn: roleArn,
49 RoleSessionName: roleSessionName,
50 RoleSessionExpiration: roleSessionExpiration,
51 Policy: policy,
52 ExternalId: externalId,
53 credentialUpdater: new(credentialUpdater),
54 runtime: runtime,
55 }
56 }
57
58 func newRAMRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy string, roleSessionExpiration int, runtime *utils.Runtime) *RAMRoleArnCredentialsProvider {
59 return &RAMRoleArnCredentialsProvider{
60 AccessKeyId: accessKeyId,
61 AccessKeySecret: accessKeySecret,
62 RoleArn: roleArn,
63 RoleSessionName: roleSessionName,
64 RoleSessionExpiration: roleSessionExpiration,
65 Policy: policy,
66 credentialUpdater: new(credentialUpdater),
67 runtime: runtime,
68 }
69 }
70
71 func newRAMRoleArnWithExternalIdCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy string, roleSessionExpiration int, externalId string, runtime *utils.Runtime) *RAMRoleArnCredentialsProvider {
72 return &RAMRoleArnCredentialsProvider{
73 AccessKeyId: accessKeyId,
74 AccessKeySecret: accessKeySecret,
75 RoleArn: roleArn,
76 RoleSessionName: roleSessionName,
77 RoleSessionExpiration: roleSessionExpiration,
78 Policy: policy,
79 ExternalId: externalId,
80 credentialUpdater: new(credentialUpdater),
81 runtime: runtime,
82 }
83 }
84
85 func (e *RAMRoleArnCredentialsProvider) GetCredential() (*CredentialModel, error) {
86 if e.sessionCredential == nil || e.needUpdateCredential() {
87 err := e.updateCredential()
88 if err != nil {
89 return nil, err
90 }
91 }
92 credential := &CredentialModel{
93 AccessKeyId: tea.String(e.sessionCredential.AccessKeyId),
94 AccessKeySecret: tea.String(e.sessionCredential.AccessKeySecret),
95 SecurityToken: tea.String(e.sessionCredential.SecurityToken),
96 Type: tea.String("ram_role_arn"),
97 }
98 return credential, nil
99 }
100
101 // GetAccessKeyId reutrns RAMRoleArnCredentialsProvider's AccessKeyId
102 // if AccessKeyId is not exist or out of date, the function will update it.
103 func (r *RAMRoleArnCredentialsProvider) GetAccessKeyId() (accessKeyId *string, err error) {
104 c, err := r.GetCredential()
105 if err != nil {
106 return
107 }
108
109 accessKeyId = c.AccessKeyId
110 return
111 }
112
113 // GetAccessSecret reutrns RAMRoleArnCredentialsProvider's AccessKeySecret
114 // if AccessKeySecret is not exist or out of date, the function will update it.
115 func (r *RAMRoleArnCredentialsProvider) GetAccessKeySecret() (accessKeySecret *string, err error) {
116 c, err := r.GetCredential()
117 if err != nil {
118 return
119 }
120
121 accessKeySecret = c.AccessKeySecret
122 return
123 }
124
125 // GetSecurityToken reutrns RAMRoleArnCredentialsProvider's SecurityToken
126 // if SecurityToken is not exist or out of date, the function will update it.
127 func (r *RAMRoleArnCredentialsProvider) GetSecurityToken() (securityToken *string, err error) {
128 c, err := r.GetCredential()
129 if err != nil {
130 return
131 }
132
133 securityToken = c.SecurityToken
134 return
135 }
136
137 // GetBearerToken is useless RAMRoleArnCredentialsProvider
138 func (r *RAMRoleArnCredentialsProvider) GetBearerToken() *string {
139 return tea.String("")
140 }
141
142 // GetType reutrns RAMRoleArnCredentialsProvider's type
143 func (r *RAMRoleArnCredentialsProvider) GetType() *string {
144 return tea.String("ram_role_arn")
145 }
146
147 func (r *RAMRoleArnCredentialsProvider) updateCredential() (err error) {
148 if r.runtime == nil {
149 r.runtime = new(utils.Runtime)
150 }
151 request := request.NewCommonRequest()
152 request.Domain = "sts.aliyuncs.com"
153 if r.runtime.STSEndpoint != "" {
154 request.Domain = r.runtime.STSEndpoint
155 }
156 request.Scheme = "HTTPS"
157 request.Method = "GET"
158 request.QueryParams["AccessKeyId"] = r.AccessKeyId
159 if r.SecurityToken != "" {
160 request.QueryParams["SecurityToken"] = r.SecurityToken
161 }
162 request.QueryParams["Action"] = "AssumeRole"
163 request.QueryParams["Format"] = "JSON"
164 if r.RoleSessionExpiration > 0 {
165 if r.RoleSessionExpiration >= 900 && r.RoleSessionExpiration <= 3600 {
166 request.QueryParams["DurationSeconds"] = strconv.Itoa(r.RoleSessionExpiration)
167 } else {
168 err = errors.New("[InvalidParam]:Assume Role session duration should be in the range of 15min - 1Hr")
169 return
170 }
171 } else {
172 request.QueryParams["DurationSeconds"] = strconv.Itoa(defaultDurationSeconds)
173 }
174 request.QueryParams["RoleArn"] = r.RoleArn
175 if r.Policy != "" {
176 request.QueryParams["Policy"] = r.Policy
177 }
178 if r.ExternalId != "" {
179 request.QueryParams["ExternalId"] = r.ExternalId
180 }
181 request.QueryParams["RoleSessionName"] = r.RoleSessionName
182 request.QueryParams["SignatureMethod"] = "HMAC-SHA1"
183 request.QueryParams["SignatureVersion"] = "1.0"
184 request.QueryParams["Version"] = "2015-04-01"
185 request.QueryParams["Timestamp"] = utils.GetTimeInFormatISO8601()
186 request.QueryParams["SignatureNonce"] = utils.GetUUID()
187 signature := utils.ShaHmac1(request.BuildStringToSign(), r.AccessKeySecret+"&")
188 request.QueryParams["Signature"] = signature
189 request.Headers["Host"] = request.Domain
190 request.Headers["Accept-Encoding"] = "identity"
191 request.URL = request.BuildURL()
192 content, err := doAction(request, r.runtime)
193 if err != nil {
194 return fmt.Errorf("refresh RoleArn sts token err: %s", err.Error())
195 }
196 var resp *ramRoleArnResponse
197 err = json.Unmarshal(content, &resp)
198 if err != nil {
199 return fmt.Errorf("refresh RoleArn sts token err: Json.Unmarshal fail: %s", err.Error())
200 }
201 if resp == nil || resp.Credentials == nil {
202 return fmt.Errorf("refresh RoleArn sts token err: Credentials is empty")
203 }
204 respCredentials := resp.Credentials
205 if respCredentials.AccessKeyId == "" || respCredentials.AccessKeySecret == "" || respCredentials.SecurityToken == "" || respCredentials.Expiration == "" {
206 return fmt.Errorf("refresh RoleArn sts token err: AccessKeyId: %s, AccessKeySecret: %s, SecurityToken: %s, Expiration: %s", respCredentials.AccessKeyId, respCredentials.AccessKeySecret, respCredentials.SecurityToken, respCredentials.Expiration)
207 }
208
209 expirationTime, err := time.Parse("2006-01-02T15:04:05Z", respCredentials.Expiration)
210 r.lastUpdateTimestamp = time.Now().Unix()
211 r.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix())
212 r.sessionCredential = &sessionCredential{
213 AccessKeyId: respCredentials.AccessKeyId,
214 AccessKeySecret: respCredentials.AccessKeySecret,
215 SecurityToken: respCredentials.SecurityToken,
216 }
217
218 return
219 }
220