uri.go raw
1 package providers
2
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "net/http"
8 "os"
9 "time"
10
11 httputil "github.com/aliyun/credentials-go/credentials/internal/http"
12 )
13
14 type URLCredentialsProvider struct {
15 url string
16 // for sts
17 sessionCredentials *sessionCredentials
18 // for http options
19 httpOptions *HttpOptions
20 // inner
21 expirationTimestamp int64
22 }
23
24 type URLCredentialsProviderBuilder struct {
25 provider *URLCredentialsProvider
26 }
27
28 func NewURLCredentialsProviderBuilder() *URLCredentialsProviderBuilder {
29 return &URLCredentialsProviderBuilder{
30 provider: &URLCredentialsProvider{},
31 }
32 }
33
34 func (builder *URLCredentialsProviderBuilder) WithUrl(url string) *URLCredentialsProviderBuilder {
35 builder.provider.url = url
36 return builder
37 }
38
39 func (builder *URLCredentialsProviderBuilder) WithHttpOptions(httpOptions *HttpOptions) *URLCredentialsProviderBuilder {
40 builder.provider.httpOptions = httpOptions
41 return builder
42 }
43
44 func (builder *URLCredentialsProviderBuilder) Build() (provider *URLCredentialsProvider, err error) {
45
46 if builder.provider.url == "" {
47 builder.provider.url = os.Getenv("ALIBABA_CLOUD_CREDENTIALS_URI")
48 }
49
50 if builder.provider.url == "" {
51 err = errors.New("the url is empty")
52 return
53 }
54
55 provider = builder.provider
56 return
57 }
58
59 type urlResponse struct {
60 AccessKeyId *string `json:"AccessKeyId"`
61 AccessKeySecret *string `json:"AccessKeySecret"`
62 SecurityToken *string `json:"SecurityToken"`
63 Expiration *string `json:"Expiration"`
64 }
65
66 func (provider *URLCredentialsProvider) getCredentials() (session *sessionCredentials, err error) {
67 req := &httputil.Request{
68 Method: "GET",
69 URL: provider.url,
70 }
71
72 connectTimeout := 5 * time.Second
73 readTimeout := 10 * time.Second
74
75 if provider.httpOptions != nil && provider.httpOptions.ConnectTimeout > 0 {
76 connectTimeout = time.Duration(provider.httpOptions.ConnectTimeout) * time.Millisecond
77 }
78 if provider.httpOptions != nil && provider.httpOptions.ReadTimeout > 0 {
79 readTimeout = time.Duration(provider.httpOptions.ReadTimeout) * time.Millisecond
80 }
81 if provider.httpOptions != nil && provider.httpOptions.Proxy != "" {
82 req.Proxy = provider.httpOptions.Proxy
83 }
84 req.ConnectTimeout = connectTimeout
85 req.ReadTimeout = readTimeout
86
87 res, err := httpDo(req)
88 if err != nil {
89 return
90 }
91
92 if res.StatusCode != http.StatusOK {
93 err = fmt.Errorf("get credentials from %s failed: %s", req.BuildRequestURL(), string(res.Body))
94 return
95 }
96
97 var resp urlResponse
98 err = json.Unmarshal(res.Body, &resp)
99 if err != nil {
100 err = fmt.Errorf("get credentials from %s failed with error, json unmarshal fail: %s", req.BuildRequestURL(), err.Error())
101 return
102 }
103
104 if resp.AccessKeyId == nil || resp.AccessKeySecret == nil || resp.SecurityToken == nil || resp.Expiration == nil {
105 err = fmt.Errorf("refresh credentials from %s failed: %s", req.BuildRequestURL(), string(res.Body))
106 return
107 }
108
109 session = &sessionCredentials{
110 AccessKeyId: *resp.AccessKeyId,
111 AccessKeySecret: *resp.AccessKeySecret,
112 SecurityToken: *resp.SecurityToken,
113 Expiration: *resp.Expiration,
114 }
115 return
116 }
117
118 func (provider *URLCredentialsProvider) needUpdateCredential() (result bool) {
119 if provider.expirationTimestamp == 0 {
120 return true
121 }
122
123 return provider.expirationTimestamp-time.Now().Unix() <= 180
124 }
125
126 func (provider *URLCredentialsProvider) GetCredentials() (cc *Credentials, err error) {
127 if provider.sessionCredentials == nil || provider.needUpdateCredential() {
128 sessionCredentials, err1 := provider.getCredentials()
129 if err1 != nil {
130 return nil, err1
131 }
132
133 provider.sessionCredentials = sessionCredentials
134 expirationTime, err2 := time.Parse("2006-01-02T15:04:05Z", sessionCredentials.Expiration)
135 if err2 != nil {
136 return nil, err2
137 }
138 provider.expirationTimestamp = expirationTime.Unix()
139 }
140
141 cc = &Credentials{
142 AccessKeyId: provider.sessionCredentials.AccessKeyId,
143 AccessKeySecret: provider.sessionCredentials.AccessKeySecret,
144 SecurityToken: provider.sessionCredentials.SecurityToken,
145 ProviderName: provider.GetProviderName(),
146 }
147 return
148 }
149
150 func (provider *URLCredentialsProvider) GetProviderName() string {
151 return "credential_uri"
152 }
153