1 package credentials
2
3 import (
4 "bufio"
5 "errors"
6 "fmt"
7 "net/http"
8 "net/url"
9 "os"
10 "strings"
11 "time"
12
13 "github.com/alibabacloud-go/debug/debug"
14 "github.com/alibabacloud-go/tea/tea"
15 "github.com/aliyun/credentials-go/credentials/request"
16 "github.com/aliyun/credentials-go/credentials/response"
17 "github.com/aliyun/credentials-go/credentials/utils"
18 )
19
20 var debuglog = debug.Init("credential")
21
22 var hookParse = func(err error) error {
23 return err
24 }
25
26
27 type Credential interface {
28 GetAccessKeyId() (*string, error)
29 GetAccessKeySecret() (*string, error)
30 GetSecurityToken() (*string, error)
31 GetBearerToken() *string
32 GetType() *string
33 GetCredential() (*CredentialModel, error)
34 }
35
36
37 type Config struct {
38 Type *string `json:"type"`
39 AccessKeyId *string `json:"access_key_id"`
40 AccessKeySecret *string `json:"access_key_secret"`
41 OIDCProviderArn *string `json:"oidc_provider_arn"`
42 OIDCTokenFilePath *string `json:"oidc_token"`
43 RoleArn *string `json:"role_arn"`
44 RoleSessionName *string `json:"role_session_name"`
45 PublicKeyId *string `json:"public_key_id"`
46 RoleName *string `json:"role_name"`
47 SessionExpiration *int `json:"session_expiration"`
48 PrivateKeyFile *string `json:"private_key_file"`
49 BearerToken *string `json:"bearer_token"`
50 SecurityToken *string `json:"security_token"`
51 RoleSessionExpiration *int `json:"role_session_expiratioon"`
52 Policy *string `json:"policy"`
53 Host *string `json:"host"`
54 Timeout *int `json:"timeout"`
55 ConnectTimeout *int `json:"connect_timeout"`
56 Proxy *string `json:"proxy"`
57 InAdvanceScale *float64 `json:"inAdvanceScale"`
58 Url *string `json:"url"`
59 STSEndpoint *string `json:"sts_endpoint"`
60 ExternalId *string `json:"external_id"`
61 }
62
63 func (s Config) String() string {
64 return tea.Prettify(s)
65 }
66
67 func (s Config) GoString() string {
68 return s.String()
69 }
70
71 func (s *Config) SetAccessKeyId(v string) *Config {
72 s.AccessKeyId = &v
73 return s
74 }
75
76 func (s *Config) SetAccessKeySecret(v string) *Config {
77 s.AccessKeySecret = &v
78 return s
79 }
80
81 func (s *Config) SetSecurityToken(v string) *Config {
82 s.SecurityToken = &v
83 return s
84 }
85
86 func (s *Config) SetRoleArn(v string) *Config {
87 s.RoleArn = &v
88 return s
89 }
90
91 func (s *Config) SetRoleSessionName(v string) *Config {
92 s.RoleSessionName = &v
93 return s
94 }
95
96 func (s *Config) SetPublicKeyId(v string) *Config {
97 s.PublicKeyId = &v
98 return s
99 }
100
101 func (s *Config) SetRoleName(v string) *Config {
102 s.RoleName = &v
103 return s
104 }
105
106 func (s *Config) SetSessionExpiration(v int) *Config {
107 s.SessionExpiration = &v
108 return s
109 }
110
111 func (s *Config) SetPrivateKeyFile(v string) *Config {
112 s.PrivateKeyFile = &v
113 return s
114 }
115
116 func (s *Config) SetBearerToken(v string) *Config {
117 s.BearerToken = &v
118 return s
119 }
120
121 func (s *Config) SetRoleSessionExpiration(v int) *Config {
122 s.RoleSessionExpiration = &v
123 return s
124 }
125
126 func (s *Config) SetPolicy(v string) *Config {
127 s.Policy = &v
128 return s
129 }
130
131 func (s *Config) SetHost(v string) *Config {
132 s.Host = &v
133 return s
134 }
135
136 func (s *Config) SetTimeout(v int) *Config {
137 s.Timeout = &v
138 return s
139 }
140
141 func (s *Config) SetConnectTimeout(v int) *Config {
142 s.ConnectTimeout = &v
143 return s
144 }
145
146 func (s *Config) SetProxy(v string) *Config {
147 s.Proxy = &v
148 return s
149 }
150
151 func (s *Config) SetType(v string) *Config {
152 s.Type = &v
153 return s
154 }
155
156 func (s *Config) SetOIDCTokenFilePath(v string) *Config {
157 s.OIDCTokenFilePath = &v
158 return s
159 }
160
161 func (s *Config) SetOIDCProviderArn(v string) *Config {
162 s.OIDCProviderArn = &v
163 return s
164 }
165
166 func (s *Config) SetURLCredential(v string) *Config {
167 if v == "" {
168 v = os.Getenv("ALIBABA_CLOUD_CREDENTIALS_URI")
169 }
170 s.Url = &v
171 return s
172 }
173
174 func (s *Config) SetSTSEndpoint(v string) *Config {
175 s.STSEndpoint = &v
176 return s
177 }
178
179
180
181
182 func NewCredential(config *Config) (credential Credential, err error) {
183 if config == nil {
184 config, err = defaultChain.resolve()
185 if err != nil {
186 return
187 }
188 return NewCredential(config)
189 }
190 switch tea.StringValue(config.Type) {
191 case "credentials_uri":
192 credential = newURLCredential(tea.StringValue(config.Url))
193 case "oidc_role_arn":
194 err = checkoutAssumeRamoidc(config)
195 if err != nil {
196 return
197 }
198 runtime := &utils.Runtime{
199 Host: tea.StringValue(config.Host),
200 Proxy: tea.StringValue(config.Proxy),
201 ReadTimeout: tea.IntValue(config.Timeout),
202 ConnectTimeout: tea.IntValue(config.ConnectTimeout),
203 STSEndpoint: tea.StringValue(config.STSEndpoint),
204 }
205 credential = newOIDCRoleArnCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.RoleArn), tea.StringValue(config.OIDCProviderArn), tea.StringValue(config.OIDCTokenFilePath), tea.StringValue(config.RoleSessionName), tea.StringValue(config.Policy), tea.IntValue(config.RoleSessionExpiration), runtime)
206 case "access_key":
207 err = checkAccessKey(config)
208 if err != nil {
209 return
210 }
211 credential = newAccessKeyCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret))
212 case "sts":
213 err = checkSTS(config)
214 if err != nil {
215 return
216 }
217 credential = newStsTokenCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.SecurityToken))
218 case "ecs_ram_role":
219 checkEcsRAMRole(config)
220 runtime := &utils.Runtime{
221 Host: tea.StringValue(config.Host),
222 Proxy: tea.StringValue(config.Proxy),
223 ReadTimeout: tea.IntValue(config.Timeout),
224 ConnectTimeout: tea.IntValue(config.ConnectTimeout),
225 }
226 credential = newEcsRAMRoleCredential(tea.StringValue(config.RoleName), tea.Float64Value(config.InAdvanceScale), runtime)
227 case "ram_role_arn":
228 err = checkRAMRoleArn(config)
229 if err != nil {
230 return
231 }
232 runtime := &utils.Runtime{
233 Host: tea.StringValue(config.Host),
234 Proxy: tea.StringValue(config.Proxy),
235 ReadTimeout: tea.IntValue(config.Timeout),
236 ConnectTimeout: tea.IntValue(config.ConnectTimeout),
237 STSEndpoint: tea.StringValue(config.STSEndpoint),
238 }
239 credential = newRAMRoleArnWithExternalIdCredential(
240 tea.StringValue(config.AccessKeyId),
241 tea.StringValue(config.AccessKeySecret),
242 tea.StringValue(config.RoleArn),
243 tea.StringValue(config.RoleSessionName),
244 tea.StringValue(config.Policy),
245 tea.IntValue(config.RoleSessionExpiration),
246 tea.StringValue(config.ExternalId),
247 runtime)
248 case "rsa_key_pair":
249 err = checkRSAKeyPair(config)
250 if err != nil {
251 return
252 }
253 file, err1 := os.Open(tea.StringValue(config.PrivateKeyFile))
254 if err1 != nil {
255 err = fmt.Errorf("InvalidPath: Can not open PrivateKeyFile, err is %s", err1.Error())
256 return
257 }
258 defer file.Close()
259 var privateKey string
260 scan := bufio.NewScanner(file)
261 for scan.Scan() {
262 if strings.HasPrefix(scan.Text(), "----") {
263 continue
264 }
265 privateKey += scan.Text() + "\n"
266 }
267 runtime := &utils.Runtime{
268 Host: tea.StringValue(config.Host),
269 Proxy: tea.StringValue(config.Proxy),
270 ReadTimeout: tea.IntValue(config.Timeout),
271 ConnectTimeout: tea.IntValue(config.ConnectTimeout),
272 STSEndpoint: tea.StringValue(config.STSEndpoint),
273 }
274 credential = newRsaKeyPairCredential(privateKey, tea.StringValue(config.PublicKeyId), tea.IntValue(config.SessionExpiration), runtime)
275 case "bearer":
276 if tea.StringValue(config.BearerToken) == "" {
277 err = errors.New("BearerToken cannot be empty")
278 return
279 }
280 credential = newBearerTokenCredential(tea.StringValue(config.BearerToken))
281 default:
282 err = errors.New("Invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair")
283 return
284 }
285 return credential, nil
286 }
287
288 func checkRSAKeyPair(config *Config) (err error) {
289 if tea.StringValue(config.PrivateKeyFile) == "" {
290 err = errors.New("PrivateKeyFile cannot be empty")
291 return
292 }
293 if tea.StringValue(config.PublicKeyId) == "" {
294 err = errors.New("PublicKeyId cannot be empty")
295 return
296 }
297 return
298 }
299
300 func checkoutAssumeRamoidc(config *Config) (err error) {
301 if tea.StringValue(config.RoleArn) == "" {
302 err = errors.New("RoleArn cannot be empty")
303 return
304 }
305 if tea.StringValue(config.OIDCProviderArn) == "" {
306 err = errors.New("OIDCProviderArn cannot be empty")
307 return
308 }
309 return
310 }
311
312 func checkRAMRoleArn(config *Config) (err error) {
313 if tea.StringValue(config.AccessKeySecret) == "" {
314 err = errors.New("AccessKeySecret cannot be empty")
315 return
316 }
317 if tea.StringValue(config.RoleArn) == "" {
318 err = errors.New("RoleArn cannot be empty")
319 return
320 }
321 if tea.StringValue(config.RoleSessionName) == "" {
322 err = errors.New("RoleSessionName cannot be empty")
323 return
324 }
325 if tea.StringValue(config.AccessKeyId) == "" {
326 err = errors.New("AccessKeyId cannot be empty")
327 return
328 }
329 return
330 }
331
332 func checkEcsRAMRole(config *Config) (err error) {
333 return
334 }
335
336 func checkSTS(config *Config) (err error) {
337 if tea.StringValue(config.AccessKeyId) == "" {
338 err = errors.New("AccessKeyId cannot be empty")
339 return
340 }
341 if tea.StringValue(config.AccessKeySecret) == "" {
342 err = errors.New("AccessKeySecret cannot be empty")
343 return
344 }
345 if tea.StringValue(config.SecurityToken) == "" {
346 err = errors.New("SecurityToken cannot be empty")
347 return
348 }
349 return
350 }
351
352 func checkAccessKey(config *Config) (err error) {
353 if tea.StringValue(config.AccessKeyId) == "" {
354 err = errors.New("AccessKeyId cannot be empty")
355 return
356 }
357 if tea.StringValue(config.AccessKeySecret) == "" {
358 err = errors.New("AccessKeySecret cannot be empty")
359 return
360 }
361 return
362 }
363
364 func doAction(request *request.CommonRequest, runtime *utils.Runtime) (content []byte, err error) {
365 var urlEncoded string
366 if request.BodyParams != nil {
367 urlEncoded = utils.GetURLFormedMap(request.BodyParams)
368 }
369 httpRequest, err := http.NewRequest(request.Method, request.URL, strings.NewReader(urlEncoded))
370 if err != nil {
371 return
372 }
373 httpRequest.Proto = "HTTP/1.1"
374 httpRequest.Host = request.Domain
375 debuglog("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)
376 debuglog("> Host: %s", httpRequest.Host)
377 for key, value := range request.Headers {
378 if value != "" {
379 debuglog("> %s: %s", key, value)
380 httpRequest.Header[key] = []string{value}
381 }
382 }
383 debuglog(">")
384 httpClient := &http.Client{}
385 httpClient.Timeout = time.Duration(runtime.ReadTimeout) * time.Second
386 proxy := &url.URL{}
387 if runtime.Proxy != "" {
388 proxy, err = url.Parse(runtime.Proxy)
389 if err != nil {
390 return
391 }
392 }
393 trans := &http.Transport{}
394 if proxy != nil && runtime.Proxy != "" {
395 trans.Proxy = http.ProxyURL(proxy)
396 }
397 trans.DialContext = utils.Timeout(time.Duration(runtime.ConnectTimeout) * time.Second)
398 httpClient.Transport = trans
399 httpResponse, err := hookDo(httpClient.Do)(httpRequest)
400 if err != nil {
401 return
402 }
403 debuglog("< %s %s", httpResponse.Proto, httpResponse.Status)
404 for key, value := range httpResponse.Header {
405 debuglog("< %s: %v", key, strings.Join(value, ""))
406 }
407 debuglog("<")
408
409 resp := &response.CommonResponse{}
410 err = hookParse(resp.ParseFromHTTPResponse(httpResponse))
411 if err != nil {
412 return
413 }
414 debuglog("%s", resp.GetHTTPContentString())
415 if resp.GetHTTPStatus() != http.StatusOK {
416 err = fmt.Errorf("httpStatus: %d, message = %s", resp.GetHTTPStatus(), resp.GetHTTPContentString())
417 return
418 }
419 return resp.GetHTTPContentBytes(), nil
420 }
421
View as plain text