1 package credentials
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io/ioutil"
7 "os"
8 "strconv"
9 "time"
10
11 "github.com/alibabacloud-go/tea/tea"
12 "github.com/aliyun/credentials-go/credentials/request"
13 "github.com/aliyun/credentials-go/credentials/utils"
14 )
15
16 const defaultOIDCDurationSeconds = 3600
17
18
19 type OIDCCredential struct {
20 *credentialUpdater
21 AccessKeyId string
22 AccessKeySecret string
23 RoleArn string
24 OIDCProviderArn string
25 OIDCTokenFilePath string
26 Policy string
27 RoleSessionName string
28 RoleSessionExpiration int
29 sessionCredential *sessionCredential
30 runtime *utils.Runtime
31 }
32
33 type OIDCResponse struct {
34 Credentials *credentialsInResponse `json:"Credentials" xml:"Credentials"`
35 }
36
37 type OIDCcredentialsInResponse struct {
38 AccessKeyId string `json:"AccessKeyId" xml:"AccessKeyId"`
39 AccessKeySecret string `json:"AccessKeySecret" xml:"AccessKeySecret"`
40 SecurityToken string `json:"SecurityToken" xml:"SecurityToken"`
41 Expiration string `json:"Expiration" xml:"Expiration"`
42 }
43
44 func newOIDCRoleArnCredential(accessKeyId, accessKeySecret, roleArn, OIDCProviderArn, OIDCTokenFilePath, RoleSessionName, policy string, RoleSessionExpiration int, runtime *utils.Runtime) *OIDCCredential {
45 return &OIDCCredential{
46 AccessKeyId: accessKeyId,
47 AccessKeySecret: accessKeySecret,
48 RoleArn: roleArn,
49 OIDCProviderArn: OIDCProviderArn,
50 OIDCTokenFilePath: OIDCTokenFilePath,
51 RoleSessionName: RoleSessionName,
52 Policy: policy,
53 RoleSessionExpiration: RoleSessionExpiration,
54 credentialUpdater: new(credentialUpdater),
55 runtime: runtime,
56 }
57 }
58
59 func (e *OIDCCredential) GetCredential() (*CredentialModel, error) {
60 if e.sessionCredential == nil || e.needUpdateCredential() {
61 err := e.updateCredential()
62 if err != nil {
63 return nil, err
64 }
65 }
66 credential := &CredentialModel{
67 AccessKeyId: tea.String(e.sessionCredential.AccessKeyId),
68 AccessKeySecret: tea.String(e.sessionCredential.AccessKeySecret),
69 SecurityToken: tea.String(e.sessionCredential.SecurityToken),
70 Type: tea.String("oidc_role_arn"),
71 }
72 return credential, nil
73 }
74
75
76
77 func (r *OIDCCredential) GetAccessKeyId() (*string, error) {
78 if r.sessionCredential == nil || r.needUpdateCredential() {
79 err := r.updateCredential()
80 if err != nil {
81 return tea.String(""), err
82 }
83 }
84 return tea.String(r.sessionCredential.AccessKeyId), nil
85 }
86
87
88
89 func (r *OIDCCredential) GetAccessKeySecret() (*string, error) {
90 if r.sessionCredential == nil || r.needUpdateCredential() {
91 err := r.updateCredential()
92 if err != nil {
93 return tea.String(""), err
94 }
95 }
96 return tea.String(r.sessionCredential.AccessKeySecret), nil
97 }
98
99
100
101 func (r *OIDCCredential) GetSecurityToken() (*string, error) {
102 if r.sessionCredential == nil || r.needUpdateCredential() {
103 err := r.updateCredential()
104 if err != nil {
105 return tea.String(""), err
106 }
107 }
108 return tea.String(r.sessionCredential.SecurityToken), nil
109 }
110
111
112 func (r *OIDCCredential) GetBearerToken() *string {
113 return tea.String("")
114 }
115
116
117 func (r *OIDCCredential) GetType() *string {
118 return tea.String("oidc_role_arn")
119 }
120
121 func (r *OIDCCredential) GetOIDCToken(OIDCTokenFilePath string) *string {
122 tokenPath := OIDCTokenFilePath
123 _, err := os.Stat(tokenPath)
124 if os.IsNotExist(err) {
125 tokenPath = os.Getenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE")
126 if tokenPath == "" {
127 return nil
128 }
129 }
130 byt, err := ioutil.ReadFile(tokenPath)
131 if err != nil {
132 return nil
133 }
134 return tea.String(string(byt))
135 }
136
137 func (r *OIDCCredential) updateCredential() (err error) {
138 if r.runtime == nil {
139 r.runtime = new(utils.Runtime)
140 }
141 request := request.NewCommonRequest()
142 request.Domain = "sts.aliyuncs.com"
143 if r.runtime.STSEndpoint != "" {
144 request.Domain = r.runtime.STSEndpoint
145 }
146 request.Scheme = "HTTPS"
147 request.Method = "POST"
148 request.QueryParams["Timestamp"] = utils.GetTimeInFormatISO8601()
149 request.QueryParams["Action"] = "AssumeRoleWithOIDC"
150 request.QueryParams["Format"] = "JSON"
151 request.BodyParams["RoleArn"] = r.RoleArn
152 request.BodyParams["OIDCProviderArn"] = r.OIDCProviderArn
153 token := r.GetOIDCToken(r.OIDCTokenFilePath)
154 request.BodyParams["OIDCToken"] = tea.StringValue(token)
155 if r.Policy != "" {
156 request.QueryParams["Policy"] = r.Policy
157 }
158 if r.RoleSessionExpiration > 0 {
159 request.QueryParams["DurationSeconds"] = strconv.Itoa(r.RoleSessionExpiration)
160 }
161 request.QueryParams["RoleSessionName"] = r.RoleSessionName
162 request.QueryParams["Version"] = "2015-04-01"
163 request.QueryParams["SignatureNonce"] = utils.GetUUID()
164 request.Headers["Host"] = request.Domain
165 request.Headers["Accept-Encoding"] = "identity"
166 request.Headers["content-type"] = "application/x-www-form-urlencoded"
167 request.URL = request.BuildURL()
168 content, err := doAction(request, r.runtime)
169 if err != nil {
170 return fmt.Errorf("refresh RoleArn sts token err: %s", err.Error())
171 }
172 var resp *OIDCResponse
173 err = json.Unmarshal(content, &resp)
174 if err != nil {
175 return fmt.Errorf("refresh RoleArn sts token err: Json.Unmarshal fail: %s", err.Error())
176 }
177 if resp == nil || resp.Credentials == nil {
178 return fmt.Errorf("refresh RoleArn sts token err: Credentials is empty")
179 }
180 respCredentials := resp.Credentials
181 if respCredentials.AccessKeyId == "" || respCredentials.AccessKeySecret == "" || respCredentials.SecurityToken == "" || respCredentials.Expiration == "" {
182 return fmt.Errorf("refresh RoleArn sts token err: AccessKeyId: %s, AccessKeySecret: %s, SecurityToken: %s, Expiration: %s", respCredentials.AccessKeyId, respCredentials.AccessKeySecret, respCredentials.SecurityToken, respCredentials.Expiration)
183 }
184
185 expirationTime, err := time.Parse("2006-01-02T15:04:05Z", respCredentials.Expiration)
186 r.lastUpdateTimestamp = time.Now().Unix()
187 r.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix())
188 r.sessionCredential = &sessionCredential{
189 AccessKeyId: respCredentials.AccessKeyId,
190 AccessKeySecret: respCredentials.AccessKeySecret,
191 SecurityToken: respCredentials.SecurityToken,
192 }
193
194 return
195 }
196
View as plain text