diff options
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/pkg/credentials')
20 files changed, 2662 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/assume_role.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/assume_role.go new file mode 100644 index 0000000..800c4a2 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/assume_role.go | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2020 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "bytes" | ||
22 | "crypto/sha256" | ||
23 | "encoding/hex" | ||
24 | "encoding/xml" | ||
25 | "errors" | ||
26 | "io" | ||
27 | "net/http" | ||
28 | "net/url" | ||
29 | "strconv" | ||
30 | "strings" | ||
31 | "time" | ||
32 | |||
33 | "github.com/minio/minio-go/v7/pkg/signer" | ||
34 | ) | ||
35 | |||
36 | // AssumeRoleResponse contains the result of successful AssumeRole request. | ||
37 | type AssumeRoleResponse struct { | ||
38 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleResponse" json:"-"` | ||
39 | |||
40 | Result AssumeRoleResult `xml:"AssumeRoleResult"` | ||
41 | ResponseMetadata struct { | ||
42 | RequestID string `xml:"RequestId,omitempty"` | ||
43 | } `xml:"ResponseMetadata,omitempty"` | ||
44 | } | ||
45 | |||
46 | // AssumeRoleResult - Contains the response to a successful AssumeRole | ||
47 | // request, including temporary credentials that can be used to make | ||
48 | // MinIO API requests. | ||
49 | type AssumeRoleResult struct { | ||
50 | // The identifiers for the temporary security credentials that the operation | ||
51 | // returns. | ||
52 | AssumedRoleUser AssumedRoleUser `xml:",omitempty"` | ||
53 | |||
54 | // The temporary security credentials, which include an access key ID, a secret | ||
55 | // access key, and a security (or session) token. | ||
56 | // | ||
57 | // Note: The size of the security token that STS APIs return is not fixed. We | ||
58 | // strongly recommend that you make no assumptions about the maximum size. As | ||
59 | // of this writing, the typical size is less than 4096 bytes, but that can vary. | ||
60 | // Also, future updates to AWS might require larger sizes. | ||
61 | Credentials struct { | ||
62 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
63 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
64 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
65 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
66 | } `xml:",omitempty"` | ||
67 | |||
68 | // A percentage value that indicates the size of the policy in packed form. | ||
69 | // The service rejects any policy with a packed size greater than 100 percent, | ||
70 | // which means the policy exceeded the allowed space. | ||
71 | PackedPolicySize int `xml:",omitempty"` | ||
72 | } | ||
73 | |||
74 | // A STSAssumeRole retrieves credentials from MinIO service, and keeps track if | ||
75 | // those credentials are expired. | ||
76 | type STSAssumeRole struct { | ||
77 | Expiry | ||
78 | |||
79 | // Required http Client to use when connecting to MinIO STS service. | ||
80 | Client *http.Client | ||
81 | |||
82 | // STS endpoint to fetch STS credentials. | ||
83 | STSEndpoint string | ||
84 | |||
85 | // various options for this request. | ||
86 | Options STSAssumeRoleOptions | ||
87 | } | ||
88 | |||
89 | // STSAssumeRoleOptions collection of various input options | ||
90 | // to obtain AssumeRole credentials. | ||
91 | type STSAssumeRoleOptions struct { | ||
92 | // Mandatory inputs. | ||
93 | AccessKey string | ||
94 | SecretKey string | ||
95 | |||
96 | SessionToken string // Optional if the first request is made with temporary credentials. | ||
97 | Policy string // Optional to assign a policy to the assumed role | ||
98 | |||
99 | Location string // Optional commonly needed with AWS STS. | ||
100 | DurationSeconds int // Optional defaults to 1 hour. | ||
101 | |||
102 | // Optional only valid if using with AWS STS | ||
103 | RoleARN string | ||
104 | RoleSessionName string | ||
105 | ExternalID string | ||
106 | } | ||
107 | |||
108 | // NewSTSAssumeRole returns a pointer to a new | ||
109 | // Credentials object wrapping the STSAssumeRole. | ||
110 | func NewSTSAssumeRole(stsEndpoint string, opts STSAssumeRoleOptions) (*Credentials, error) { | ||
111 | if stsEndpoint == "" { | ||
112 | return nil, errors.New("STS endpoint cannot be empty") | ||
113 | } | ||
114 | if opts.AccessKey == "" || opts.SecretKey == "" { | ||
115 | return nil, errors.New("AssumeRole credentials access/secretkey is mandatory") | ||
116 | } | ||
117 | return New(&STSAssumeRole{ | ||
118 | Client: &http.Client{ | ||
119 | Transport: http.DefaultTransport, | ||
120 | }, | ||
121 | STSEndpoint: stsEndpoint, | ||
122 | Options: opts, | ||
123 | }), nil | ||
124 | } | ||
125 | |||
126 | const defaultDurationSeconds = 3600 | ||
127 | |||
128 | // closeResponse close non nil response with any response Body. | ||
129 | // convenient wrapper to drain any remaining data on response body. | ||
130 | // | ||
131 | // Subsequently this allows golang http RoundTripper | ||
132 | // to re-use the same connection for future requests. | ||
133 | func closeResponse(resp *http.Response) { | ||
134 | // Callers should close resp.Body when done reading from it. | ||
135 | // If resp.Body is not closed, the Client's underlying RoundTripper | ||
136 | // (typically Transport) may not be able to re-use a persistent TCP | ||
137 | // connection to the server for a subsequent "keep-alive" request. | ||
138 | if resp != nil && resp.Body != nil { | ||
139 | // Drain any remaining Body and then close the connection. | ||
140 | // Without this closing connection would disallow re-using | ||
141 | // the same connection for future uses. | ||
142 | // - http://stackoverflow.com/a/17961593/4465767 | ||
143 | io.Copy(io.Discard, resp.Body) | ||
144 | resp.Body.Close() | ||
145 | } | ||
146 | } | ||
147 | |||
148 | func getAssumeRoleCredentials(clnt *http.Client, endpoint string, opts STSAssumeRoleOptions) (AssumeRoleResponse, error) { | ||
149 | v := url.Values{} | ||
150 | v.Set("Action", "AssumeRole") | ||
151 | v.Set("Version", STSVersion) | ||
152 | if opts.RoleARN != "" { | ||
153 | v.Set("RoleArn", opts.RoleARN) | ||
154 | } | ||
155 | if opts.RoleSessionName != "" { | ||
156 | v.Set("RoleSessionName", opts.RoleSessionName) | ||
157 | } | ||
158 | if opts.DurationSeconds > defaultDurationSeconds { | ||
159 | v.Set("DurationSeconds", strconv.Itoa(opts.DurationSeconds)) | ||
160 | } else { | ||
161 | v.Set("DurationSeconds", strconv.Itoa(defaultDurationSeconds)) | ||
162 | } | ||
163 | if opts.Policy != "" { | ||
164 | v.Set("Policy", opts.Policy) | ||
165 | } | ||
166 | if opts.ExternalID != "" { | ||
167 | v.Set("ExternalId", opts.ExternalID) | ||
168 | } | ||
169 | |||
170 | u, err := url.Parse(endpoint) | ||
171 | if err != nil { | ||
172 | return AssumeRoleResponse{}, err | ||
173 | } | ||
174 | u.Path = "/" | ||
175 | |||
176 | postBody := strings.NewReader(v.Encode()) | ||
177 | hash := sha256.New() | ||
178 | if _, err = io.Copy(hash, postBody); err != nil { | ||
179 | return AssumeRoleResponse{}, err | ||
180 | } | ||
181 | postBody.Seek(0, 0) | ||
182 | |||
183 | req, err := http.NewRequest(http.MethodPost, u.String(), postBody) | ||
184 | if err != nil { | ||
185 | return AssumeRoleResponse{}, err | ||
186 | } | ||
187 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
188 | req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(hash.Sum(nil))) | ||
189 | if opts.SessionToken != "" { | ||
190 | req.Header.Set("X-Amz-Security-Token", opts.SessionToken) | ||
191 | } | ||
192 | req = signer.SignV4STS(*req, opts.AccessKey, opts.SecretKey, opts.Location) | ||
193 | |||
194 | resp, err := clnt.Do(req) | ||
195 | if err != nil { | ||
196 | return AssumeRoleResponse{}, err | ||
197 | } | ||
198 | defer closeResponse(resp) | ||
199 | if resp.StatusCode != http.StatusOK { | ||
200 | var errResp ErrorResponse | ||
201 | buf, err := io.ReadAll(resp.Body) | ||
202 | if err != nil { | ||
203 | return AssumeRoleResponse{}, err | ||
204 | } | ||
205 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
206 | if err != nil { | ||
207 | var s3Err Error | ||
208 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
209 | return AssumeRoleResponse{}, err | ||
210 | } | ||
211 | errResp.RequestID = s3Err.RequestID | ||
212 | errResp.STSError.Code = s3Err.Code | ||
213 | errResp.STSError.Message = s3Err.Message | ||
214 | } | ||
215 | return AssumeRoleResponse{}, errResp | ||
216 | } | ||
217 | |||
218 | a := AssumeRoleResponse{} | ||
219 | if _, err = xmlDecodeAndBody(resp.Body, &a); err != nil { | ||
220 | return AssumeRoleResponse{}, err | ||
221 | } | ||
222 | return a, nil | ||
223 | } | ||
224 | |||
225 | // Retrieve retrieves credentials from the MinIO service. | ||
226 | // Error will be returned if the request fails. | ||
227 | func (m *STSAssumeRole) Retrieve() (Value, error) { | ||
228 | a, err := getAssumeRoleCredentials(m.Client, m.STSEndpoint, m.Options) | ||
229 | if err != nil { | ||
230 | return Value{}, err | ||
231 | } | ||
232 | |||
233 | // Expiry window is set to 10secs. | ||
234 | m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
235 | |||
236 | return Value{ | ||
237 | AccessKeyID: a.Result.Credentials.AccessKey, | ||
238 | SecretAccessKey: a.Result.Credentials.SecretKey, | ||
239 | SessionToken: a.Result.Credentials.SessionToken, | ||
240 | SignerType: SignatureV4, | ||
241 | }, nil | ||
242 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/chain.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/chain.go new file mode 100644 index 0000000..ddccfb1 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/chain.go | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | // A Chain will search for a provider which returns credentials | ||
21 | // and cache that provider until Retrieve is called again. | ||
22 | // | ||
23 | // The Chain provides a way of chaining multiple providers together | ||
24 | // which will pick the first available using priority order of the | ||
25 | // Providers in the list. | ||
26 | // | ||
27 | // If none of the Providers retrieve valid credentials Value, ChainProvider's | ||
28 | // Retrieve() will return the no credentials value. | ||
29 | // | ||
30 | // If a Provider is found which returns valid credentials Value ChainProvider | ||
31 | // will cache that Provider for all calls to IsExpired(), until Retrieve is | ||
32 | // called again after IsExpired() is true. | ||
33 | // | ||
34 | // creds := credentials.NewChainCredentials( | ||
35 | // []credentials.Provider{ | ||
36 | // &credentials.EnvAWSS3{}, | ||
37 | // &credentials.EnvMinio{}, | ||
38 | // }) | ||
39 | // | ||
40 | // // Usage of ChainCredentials. | ||
41 | // mc, err := minio.NewWithCredentials(endpoint, creds, secure, "us-east-1") | ||
42 | // if err != nil { | ||
43 | // log.Fatalln(err) | ||
44 | // } | ||
45 | type Chain struct { | ||
46 | Providers []Provider | ||
47 | curr Provider | ||
48 | } | ||
49 | |||
50 | // NewChainCredentials returns a pointer to a new Credentials object | ||
51 | // wrapping a chain of providers. | ||
52 | func NewChainCredentials(providers []Provider) *Credentials { | ||
53 | return New(&Chain{ | ||
54 | Providers: append([]Provider{}, providers...), | ||
55 | }) | ||
56 | } | ||
57 | |||
58 | // Retrieve returns the credentials value, returns no credentials(anonymous) | ||
59 | // if no credentials provider returned any value. | ||
60 | // | ||
61 | // If a provider is found with credentials, it will be cached and any calls | ||
62 | // to IsExpired() will return the expired state of the cached provider. | ||
63 | func (c *Chain) Retrieve() (Value, error) { | ||
64 | for _, p := range c.Providers { | ||
65 | creds, _ := p.Retrieve() | ||
66 | // Always prioritize non-anonymous providers, if any. | ||
67 | if creds.AccessKeyID == "" && creds.SecretAccessKey == "" { | ||
68 | continue | ||
69 | } | ||
70 | c.curr = p | ||
71 | return creds, nil | ||
72 | } | ||
73 | // At this point we have exhausted all the providers and | ||
74 | // are left without any credentials return anonymous. | ||
75 | return Value{ | ||
76 | SignerType: SignatureAnonymous, | ||
77 | }, nil | ||
78 | } | ||
79 | |||
80 | // IsExpired will returned the expired state of the currently cached provider | ||
81 | // if there is one. If there is no current provider, true will be returned. | ||
82 | func (c *Chain) IsExpired() bool { | ||
83 | if c.curr != nil { | ||
84 | return c.curr.IsExpired() | ||
85 | } | ||
86 | |||
87 | return true | ||
88 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/config.json.sample b/vendor/github.com/minio/minio-go/v7/pkg/credentials/config.json.sample new file mode 100644 index 0000000..d793c9e --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/config.json.sample | |||
@@ -0,0 +1,17 @@ | |||
1 | { | ||
2 | "version": "8", | ||
3 | "hosts": { | ||
4 | "play": { | ||
5 | "url": "https://play.min.io", | ||
6 | "accessKey": "Q3AM3UQ867SPQQA43P2F", | ||
7 | "secretKey": "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", | ||
8 | "api": "S3v2" | ||
9 | }, | ||
10 | "s3": { | ||
11 | "url": "https://s3.amazonaws.com", | ||
12 | "accessKey": "accessKey", | ||
13 | "secretKey": "secret", | ||
14 | "api": "S3v4" | ||
15 | } | ||
16 | } | ||
17 | } \ No newline at end of file | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go new file mode 100644 index 0000000..af61049 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "sync" | ||
22 | "time" | ||
23 | ) | ||
24 | |||
25 | const ( | ||
26 | // STSVersion sts version string | ||
27 | STSVersion = "2011-06-15" | ||
28 | |||
29 | // How much duration to slash from the given expiration duration | ||
30 | defaultExpiryWindow = 0.8 | ||
31 | ) | ||
32 | |||
33 | // A Value is the AWS credentials value for individual credential fields. | ||
34 | type Value struct { | ||
35 | // AWS Access key ID | ||
36 | AccessKeyID string | ||
37 | |||
38 | // AWS Secret Access Key | ||
39 | SecretAccessKey string | ||
40 | |||
41 | // AWS Session Token | ||
42 | SessionToken string | ||
43 | |||
44 | // Signature Type. | ||
45 | SignerType SignatureType | ||
46 | } | ||
47 | |||
48 | // A Provider is the interface for any component which will provide credentials | ||
49 | // Value. A provider is required to manage its own Expired state, and what to | ||
50 | // be expired means. | ||
51 | type Provider interface { | ||
52 | // Retrieve returns nil if it successfully retrieved the value. | ||
53 | // Error is returned if the value were not obtainable, or empty. | ||
54 | Retrieve() (Value, error) | ||
55 | |||
56 | // IsExpired returns if the credentials are no longer valid, and need | ||
57 | // to be retrieved. | ||
58 | IsExpired() bool | ||
59 | } | ||
60 | |||
61 | // A Expiry provides shared expiration logic to be used by credentials | ||
62 | // providers to implement expiry functionality. | ||
63 | // | ||
64 | // The best method to use this struct is as an anonymous field within the | ||
65 | // provider's struct. | ||
66 | // | ||
67 | // Example: | ||
68 | // | ||
69 | // type IAMCredentialProvider struct { | ||
70 | // Expiry | ||
71 | // ... | ||
72 | // } | ||
73 | type Expiry struct { | ||
74 | // The date/time when to expire on | ||
75 | expiration time.Time | ||
76 | |||
77 | // If set will be used by IsExpired to determine the current time. | ||
78 | // Defaults to time.Now if CurrentTime is not set. | ||
79 | CurrentTime func() time.Time | ||
80 | } | ||
81 | |||
82 | // SetExpiration sets the expiration IsExpired will check when called. | ||
83 | // | ||
84 | // If window is greater than 0 the expiration time will be reduced by the | ||
85 | // window value. | ||
86 | // | ||
87 | // Using a window is helpful to trigger credentials to expire sooner than | ||
88 | // the expiration time given to ensure no requests are made with expired | ||
89 | // tokens. | ||
90 | func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) { | ||
91 | if e.CurrentTime == nil { | ||
92 | e.CurrentTime = time.Now | ||
93 | } | ||
94 | cut := window | ||
95 | if cut < 0 { | ||
96 | expireIn := expiration.Sub(e.CurrentTime()) | ||
97 | cut = time.Duration(float64(expireIn) * (1 - defaultExpiryWindow)) | ||
98 | } | ||
99 | e.expiration = expiration.Add(-cut) | ||
100 | } | ||
101 | |||
102 | // IsExpired returns if the credentials are expired. | ||
103 | func (e *Expiry) IsExpired() bool { | ||
104 | if e.CurrentTime == nil { | ||
105 | e.CurrentTime = time.Now | ||
106 | } | ||
107 | return e.expiration.Before(e.CurrentTime()) | ||
108 | } | ||
109 | |||
110 | // Credentials - A container for synchronous safe retrieval of credentials Value. | ||
111 | // Credentials will cache the credentials value until they expire. Once the value | ||
112 | // expires the next Get will attempt to retrieve valid credentials. | ||
113 | // | ||
114 | // Credentials is safe to use across multiple goroutines and will manage the | ||
115 | // synchronous state so the Providers do not need to implement their own | ||
116 | // synchronization. | ||
117 | // | ||
118 | // The first Credentials.Get() will always call Provider.Retrieve() to get the | ||
119 | // first instance of the credentials Value. All calls to Get() after that | ||
120 | // will return the cached credentials Value until IsExpired() returns true. | ||
121 | type Credentials struct { | ||
122 | sync.Mutex | ||
123 | |||
124 | creds Value | ||
125 | forceRefresh bool | ||
126 | provider Provider | ||
127 | } | ||
128 | |||
129 | // New returns a pointer to a new Credentials with the provider set. | ||
130 | func New(provider Provider) *Credentials { | ||
131 | return &Credentials{ | ||
132 | provider: provider, | ||
133 | forceRefresh: true, | ||
134 | } | ||
135 | } | ||
136 | |||
137 | // Get returns the credentials value, or error if the credentials Value failed | ||
138 | // to be retrieved. | ||
139 | // | ||
140 | // Will return the cached credentials Value if it has not expired. If the | ||
141 | // credentials Value has expired the Provider's Retrieve() will be called | ||
142 | // to refresh the credentials. | ||
143 | // | ||
144 | // If Credentials.Expire() was called the credentials Value will be force | ||
145 | // expired, and the next call to Get() will cause them to be refreshed. | ||
146 | func (c *Credentials) Get() (Value, error) { | ||
147 | if c == nil { | ||
148 | return Value{}, nil | ||
149 | } | ||
150 | |||
151 | c.Lock() | ||
152 | defer c.Unlock() | ||
153 | |||
154 | if c.isExpired() { | ||
155 | creds, err := c.provider.Retrieve() | ||
156 | if err != nil { | ||
157 | return Value{}, err | ||
158 | } | ||
159 | c.creds = creds | ||
160 | c.forceRefresh = false | ||
161 | } | ||
162 | |||
163 | return c.creds, nil | ||
164 | } | ||
165 | |||
166 | // Expire expires the credentials and forces them to be retrieved on the | ||
167 | // next call to Get(). | ||
168 | // | ||
169 | // This will override the Provider's expired state, and force Credentials | ||
170 | // to call the Provider's Retrieve(). | ||
171 | func (c *Credentials) Expire() { | ||
172 | c.Lock() | ||
173 | defer c.Unlock() | ||
174 | |||
175 | c.forceRefresh = true | ||
176 | } | ||
177 | |||
178 | // IsExpired returns if the credentials are no longer valid, and need | ||
179 | // to be refreshed. | ||
180 | // | ||
181 | // If the Credentials were forced to be expired with Expire() this will | ||
182 | // reflect that override. | ||
183 | func (c *Credentials) IsExpired() bool { | ||
184 | c.Lock() | ||
185 | defer c.Unlock() | ||
186 | |||
187 | return c.isExpired() | ||
188 | } | ||
189 | |||
190 | // isExpired helper method wrapping the definition of expired credentials. | ||
191 | func (c *Credentials) isExpired() bool { | ||
192 | return c.forceRefresh || c.provider.IsExpired() | ||
193 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.json b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.json new file mode 100644 index 0000000..afbfad5 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.json | |||
@@ -0,0 +1,7 @@ | |||
1 | { | ||
2 | "Version": 1, | ||
3 | "SessionToken": "token", | ||
4 | "AccessKeyId": "accessKey", | ||
5 | "SecretAccessKey": "secret", | ||
6 | "Expiration": "9999-04-27T16:02:25.000Z" | ||
7 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.sample b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.sample new file mode 100644 index 0000000..e2dc1bf --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.sample | |||
@@ -0,0 +1,15 @@ | |||
1 | [default] | ||
2 | aws_access_key_id = accessKey | ||
3 | aws_secret_access_key = secret | ||
4 | aws_session_token = token | ||
5 | |||
6 | [no_token] | ||
7 | aws_access_key_id = accessKey | ||
8 | aws_secret_access_key = secret | ||
9 | |||
10 | [with_colon] | ||
11 | aws_access_key_id: accessKey | ||
12 | aws_secret_access_key: secret | ||
13 | |||
14 | [with_process] | ||
15 | credential_process = /bin/cat credentials.json | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/doc.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/doc.go new file mode 100644 index 0000000..fbfb105 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/doc.go | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | // Package credentials provides credential retrieval and management | ||
19 | // for S3 compatible object storage. | ||
20 | // | ||
21 | // By default the Credentials.Get() will cache the successful result of a | ||
22 | // Provider's Retrieve() until Provider.IsExpired() returns true. At which | ||
23 | // point Credentials will call Provider's Retrieve() to get new credential Value. | ||
24 | // | ||
25 | // The Provider is responsible for determining when credentials have expired. | ||
26 | // It is also important to note that Credentials will always call Retrieve the | ||
27 | // first time Credentials.Get() is called. | ||
28 | // | ||
29 | // Example of using the environment variable credentials. | ||
30 | // | ||
31 | // creds := NewFromEnv() | ||
32 | // // Retrieve the credentials value | ||
33 | // credValue, err := creds.Get() | ||
34 | // if err != nil { | ||
35 | // // handle error | ||
36 | // } | ||
37 | // | ||
38 | // Example of forcing credentials to expire and be refreshed on the next Get(). | ||
39 | // This may be helpful to proactively expire credentials and refresh them sooner | ||
40 | // than they would naturally expire on their own. | ||
41 | // | ||
42 | // creds := NewFromIAM("") | ||
43 | // creds.Expire() | ||
44 | // credsValue, err := creds.Get() | ||
45 | // // New credentials will be retrieved instead of from cache. | ||
46 | // | ||
47 | // # Custom Provider | ||
48 | // | ||
49 | // Each Provider built into this package also provides a helper method to generate | ||
50 | // a Credentials pointer setup with the provider. To use a custom Provider just | ||
51 | // create a type which satisfies the Provider interface and pass it to the | ||
52 | // NewCredentials method. | ||
53 | // | ||
54 | // type MyProvider struct{} | ||
55 | // func (m *MyProvider) Retrieve() (Value, error) {...} | ||
56 | // func (m *MyProvider) IsExpired() bool {...} | ||
57 | // | ||
58 | // creds := NewCredentials(&MyProvider{}) | ||
59 | // credValue, err := creds.Get() | ||
60 | package credentials | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_aws.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_aws.go new file mode 100644 index 0000000..b6e60d0 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_aws.go | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import "os" | ||
21 | |||
22 | // A EnvAWS retrieves credentials from the environment variables of the | ||
23 | // running process. EnvAWSironment credentials never expire. | ||
24 | // | ||
25 | // EnvAWSironment variables used: | ||
26 | // | ||
27 | // * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY. | ||
28 | // * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY. | ||
29 | // * Secret Token: AWS_SESSION_TOKEN. | ||
30 | type EnvAWS struct { | ||
31 | retrieved bool | ||
32 | } | ||
33 | |||
34 | // NewEnvAWS returns a pointer to a new Credentials object | ||
35 | // wrapping the environment variable provider. | ||
36 | func NewEnvAWS() *Credentials { | ||
37 | return New(&EnvAWS{}) | ||
38 | } | ||
39 | |||
40 | // Retrieve retrieves the keys from the environment. | ||
41 | func (e *EnvAWS) Retrieve() (Value, error) { | ||
42 | e.retrieved = false | ||
43 | |||
44 | id := os.Getenv("AWS_ACCESS_KEY_ID") | ||
45 | if id == "" { | ||
46 | id = os.Getenv("AWS_ACCESS_KEY") | ||
47 | } | ||
48 | |||
49 | secret := os.Getenv("AWS_SECRET_ACCESS_KEY") | ||
50 | if secret == "" { | ||
51 | secret = os.Getenv("AWS_SECRET_KEY") | ||
52 | } | ||
53 | |||
54 | signerType := SignatureV4 | ||
55 | if id == "" || secret == "" { | ||
56 | signerType = SignatureAnonymous | ||
57 | } | ||
58 | |||
59 | e.retrieved = true | ||
60 | return Value{ | ||
61 | AccessKeyID: id, | ||
62 | SecretAccessKey: secret, | ||
63 | SessionToken: os.Getenv("AWS_SESSION_TOKEN"), | ||
64 | SignerType: signerType, | ||
65 | }, nil | ||
66 | } | ||
67 | |||
68 | // IsExpired returns if the credentials have been retrieved. | ||
69 | func (e *EnvAWS) IsExpired() bool { | ||
70 | return !e.retrieved | ||
71 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_minio.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_minio.go new file mode 100644 index 0000000..5bfeab1 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_minio.go | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import "os" | ||
21 | |||
22 | // A EnvMinio retrieves credentials from the environment variables of the | ||
23 | // running process. EnvMinioironment credentials never expire. | ||
24 | // | ||
25 | // Environment variables used: | ||
26 | // | ||
27 | // * Access Key ID: MINIO_ACCESS_KEY. | ||
28 | // * Secret Access Key: MINIO_SECRET_KEY. | ||
29 | // * Access Key ID: MINIO_ROOT_USER. | ||
30 | // * Secret Access Key: MINIO_ROOT_PASSWORD. | ||
31 | type EnvMinio struct { | ||
32 | retrieved bool | ||
33 | } | ||
34 | |||
35 | // NewEnvMinio returns a pointer to a new Credentials object | ||
36 | // wrapping the environment variable provider. | ||
37 | func NewEnvMinio() *Credentials { | ||
38 | return New(&EnvMinio{}) | ||
39 | } | ||
40 | |||
41 | // Retrieve retrieves the keys from the environment. | ||
42 | func (e *EnvMinio) Retrieve() (Value, error) { | ||
43 | e.retrieved = false | ||
44 | |||
45 | id := os.Getenv("MINIO_ROOT_USER") | ||
46 | secret := os.Getenv("MINIO_ROOT_PASSWORD") | ||
47 | |||
48 | signerType := SignatureV4 | ||
49 | if id == "" || secret == "" { | ||
50 | id = os.Getenv("MINIO_ACCESS_KEY") | ||
51 | secret = os.Getenv("MINIO_SECRET_KEY") | ||
52 | if id == "" || secret == "" { | ||
53 | signerType = SignatureAnonymous | ||
54 | } | ||
55 | } | ||
56 | |||
57 | e.retrieved = true | ||
58 | return Value{ | ||
59 | AccessKeyID: id, | ||
60 | SecretAccessKey: secret, | ||
61 | SignerType: signerType, | ||
62 | }, nil | ||
63 | } | ||
64 | |||
65 | // IsExpired returns if the credentials have been retrieved. | ||
66 | func (e *EnvMinio) IsExpired() bool { | ||
67 | return !e.retrieved | ||
68 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/error_response.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/error_response.go new file mode 100644 index 0000000..07a9c2f --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/error_response.go | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2021 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "bytes" | ||
22 | "encoding/xml" | ||
23 | "fmt" | ||
24 | "io" | ||
25 | ) | ||
26 | |||
27 | // ErrorResponse - Is the typed error returned. | ||
28 | // ErrorResponse struct should be comparable since it is compared inside | ||
29 | // golang http API (https://github.com/golang/go/issues/29768) | ||
30 | type ErrorResponse struct { | ||
31 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ ErrorResponse" json:"-"` | ||
32 | STSError struct { | ||
33 | Type string `xml:"Type"` | ||
34 | Code string `xml:"Code"` | ||
35 | Message string `xml:"Message"` | ||
36 | } `xml:"Error"` | ||
37 | RequestID string `xml:"RequestId"` | ||
38 | } | ||
39 | |||
40 | // Error - Is the typed error returned by all API operations. | ||
41 | type Error struct { | ||
42 | XMLName xml.Name `xml:"Error" json:"-"` | ||
43 | Code string | ||
44 | Message string | ||
45 | BucketName string | ||
46 | Key string | ||
47 | Resource string | ||
48 | RequestID string `xml:"RequestId"` | ||
49 | HostID string `xml:"HostId"` | ||
50 | |||
51 | // Region where the bucket is located. This header is returned | ||
52 | // only in HEAD bucket and ListObjects response. | ||
53 | Region string | ||
54 | |||
55 | // Captures the server string returned in response header. | ||
56 | Server string | ||
57 | |||
58 | // Underlying HTTP status code for the returned error | ||
59 | StatusCode int `xml:"-" json:"-"` | ||
60 | } | ||
61 | |||
62 | // Error - Returns S3 error string. | ||
63 | func (e Error) Error() string { | ||
64 | if e.Message == "" { | ||
65 | return fmt.Sprintf("Error response code %s.", e.Code) | ||
66 | } | ||
67 | return e.Message | ||
68 | } | ||
69 | |||
70 | // Error - Returns STS error string. | ||
71 | func (e ErrorResponse) Error() string { | ||
72 | if e.STSError.Message == "" { | ||
73 | return fmt.Sprintf("Error response code %s.", e.STSError.Code) | ||
74 | } | ||
75 | return e.STSError.Message | ||
76 | } | ||
77 | |||
78 | // xmlDecoder provide decoded value in xml. | ||
79 | func xmlDecoder(body io.Reader, v interface{}) error { | ||
80 | d := xml.NewDecoder(body) | ||
81 | return d.Decode(v) | ||
82 | } | ||
83 | |||
84 | // xmlDecodeAndBody reads the whole body up to 1MB and | ||
85 | // tries to XML decode it into v. | ||
86 | // The body that was read and any error from reading or decoding is returned. | ||
87 | func xmlDecodeAndBody(bodyReader io.Reader, v interface{}) ([]byte, error) { | ||
88 | // read the whole body (up to 1MB) | ||
89 | const maxBodyLength = 1 << 20 | ||
90 | body, err := io.ReadAll(io.LimitReader(bodyReader, maxBodyLength)) | ||
91 | if err != nil { | ||
92 | return nil, err | ||
93 | } | ||
94 | return bytes.TrimSpace(body), xmlDecoder(bytes.NewReader(body), v) | ||
95 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go new file mode 100644 index 0000000..5b07376 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "encoding/json" | ||
22 | "errors" | ||
23 | "os" | ||
24 | "os/exec" | ||
25 | "path/filepath" | ||
26 | "strings" | ||
27 | "time" | ||
28 | |||
29 | ini "gopkg.in/ini.v1" | ||
30 | ) | ||
31 | |||
32 | // A externalProcessCredentials stores the output of a credential_process | ||
33 | type externalProcessCredentials struct { | ||
34 | Version int | ||
35 | SessionToken string | ||
36 | AccessKeyID string `json:"AccessKeyId"` | ||
37 | SecretAccessKey string | ||
38 | Expiration time.Time | ||
39 | } | ||
40 | |||
41 | // A FileAWSCredentials retrieves credentials from the current user's home | ||
42 | // directory, and keeps track if those credentials are expired. | ||
43 | // | ||
44 | // Profile ini file example: $HOME/.aws/credentials | ||
45 | type FileAWSCredentials struct { | ||
46 | Expiry | ||
47 | |||
48 | // Path to the shared credentials file. | ||
49 | // | ||
50 | // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the | ||
51 | // env value is empty will default to current user's home directory. | ||
52 | // Linux/OSX: "$HOME/.aws/credentials" | ||
53 | // Windows: "%USERPROFILE%\.aws\credentials" | ||
54 | Filename string | ||
55 | |||
56 | // AWS Profile to extract credentials from the shared credentials file. If empty | ||
57 | // will default to environment variable "AWS_PROFILE" or "default" if | ||
58 | // environment variable is also not set. | ||
59 | Profile string | ||
60 | |||
61 | // retrieved states if the credentials have been successfully retrieved. | ||
62 | retrieved bool | ||
63 | } | ||
64 | |||
65 | // NewFileAWSCredentials returns a pointer to a new Credentials object | ||
66 | // wrapping the Profile file provider. | ||
67 | func NewFileAWSCredentials(filename, profile string) *Credentials { | ||
68 | return New(&FileAWSCredentials{ | ||
69 | Filename: filename, | ||
70 | Profile: profile, | ||
71 | }) | ||
72 | } | ||
73 | |||
74 | // Retrieve reads and extracts the shared credentials from the current | ||
75 | // users home directory. | ||
76 | func (p *FileAWSCredentials) Retrieve() (Value, error) { | ||
77 | if p.Filename == "" { | ||
78 | p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE") | ||
79 | if p.Filename == "" { | ||
80 | homeDir, err := os.UserHomeDir() | ||
81 | if err != nil { | ||
82 | return Value{}, err | ||
83 | } | ||
84 | p.Filename = filepath.Join(homeDir, ".aws", "credentials") | ||
85 | } | ||
86 | } | ||
87 | if p.Profile == "" { | ||
88 | p.Profile = os.Getenv("AWS_PROFILE") | ||
89 | if p.Profile == "" { | ||
90 | p.Profile = "default" | ||
91 | } | ||
92 | } | ||
93 | |||
94 | p.retrieved = false | ||
95 | |||
96 | iniProfile, err := loadProfile(p.Filename, p.Profile) | ||
97 | if err != nil { | ||
98 | return Value{}, err | ||
99 | } | ||
100 | |||
101 | // Default to empty string if not found. | ||
102 | id := iniProfile.Key("aws_access_key_id") | ||
103 | // Default to empty string if not found. | ||
104 | secret := iniProfile.Key("aws_secret_access_key") | ||
105 | // Default to empty string if not found. | ||
106 | token := iniProfile.Key("aws_session_token") | ||
107 | |||
108 | // If credential_process is defined, obtain credentials by executing | ||
109 | // the external process | ||
110 | credentialProcess := strings.TrimSpace(iniProfile.Key("credential_process").String()) | ||
111 | if credentialProcess != "" { | ||
112 | args := strings.Fields(credentialProcess) | ||
113 | if len(args) <= 1 { | ||
114 | return Value{}, errors.New("invalid credential process args") | ||
115 | } | ||
116 | cmd := exec.Command(args[0], args[1:]...) | ||
117 | out, err := cmd.Output() | ||
118 | if err != nil { | ||
119 | return Value{}, err | ||
120 | } | ||
121 | var externalProcessCredentials externalProcessCredentials | ||
122 | err = json.Unmarshal([]byte(out), &externalProcessCredentials) | ||
123 | if err != nil { | ||
124 | return Value{}, err | ||
125 | } | ||
126 | p.retrieved = true | ||
127 | p.SetExpiration(externalProcessCredentials.Expiration, DefaultExpiryWindow) | ||
128 | return Value{ | ||
129 | AccessKeyID: externalProcessCredentials.AccessKeyID, | ||
130 | SecretAccessKey: externalProcessCredentials.SecretAccessKey, | ||
131 | SessionToken: externalProcessCredentials.SessionToken, | ||
132 | SignerType: SignatureV4, | ||
133 | }, nil | ||
134 | } | ||
135 | p.retrieved = true | ||
136 | return Value{ | ||
137 | AccessKeyID: id.String(), | ||
138 | SecretAccessKey: secret.String(), | ||
139 | SessionToken: token.String(), | ||
140 | SignerType: SignatureV4, | ||
141 | }, nil | ||
142 | } | ||
143 | |||
144 | // loadProfiles loads from the file pointed to by shared credentials filename for profile. | ||
145 | // The credentials retrieved from the profile will be returned or error. Error will be | ||
146 | // returned if it fails to read from the file, or the data is invalid. | ||
147 | func loadProfile(filename, profile string) (*ini.Section, error) { | ||
148 | config, err := ini.Load(filename) | ||
149 | if err != nil { | ||
150 | return nil, err | ||
151 | } | ||
152 | iniProfile, err := config.GetSection(profile) | ||
153 | if err != nil { | ||
154 | return nil, err | ||
155 | } | ||
156 | return iniProfile, nil | ||
157 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go new file mode 100644 index 0000000..eb77767 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "os" | ||
22 | "path/filepath" | ||
23 | "runtime" | ||
24 | |||
25 | jsoniter "github.com/json-iterator/go" | ||
26 | ) | ||
27 | |||
28 | // A FileMinioClient retrieves credentials from the current user's home | ||
29 | // directory, and keeps track if those credentials are expired. | ||
30 | // | ||
31 | // Configuration file example: $HOME/.mc/config.json | ||
32 | type FileMinioClient struct { | ||
33 | // Path to the shared credentials file. | ||
34 | // | ||
35 | // If empty will look for "MINIO_SHARED_CREDENTIALS_FILE" env variable. If the | ||
36 | // env value is empty will default to current user's home directory. | ||
37 | // Linux/OSX: "$HOME/.mc/config.json" | ||
38 | // Windows: "%USERALIAS%\mc\config.json" | ||
39 | Filename string | ||
40 | |||
41 | // MinIO Alias to extract credentials from the shared credentials file. If empty | ||
42 | // will default to environment variable "MINIO_ALIAS" or "default" if | ||
43 | // environment variable is also not set. | ||
44 | Alias string | ||
45 | |||
46 | // retrieved states if the credentials have been successfully retrieved. | ||
47 | retrieved bool | ||
48 | } | ||
49 | |||
50 | // NewFileMinioClient returns a pointer to a new Credentials object | ||
51 | // wrapping the Alias file provider. | ||
52 | func NewFileMinioClient(filename, alias string) *Credentials { | ||
53 | return New(&FileMinioClient{ | ||
54 | Filename: filename, | ||
55 | Alias: alias, | ||
56 | }) | ||
57 | } | ||
58 | |||
59 | // Retrieve reads and extracts the shared credentials from the current | ||
60 | // users home directory. | ||
61 | func (p *FileMinioClient) Retrieve() (Value, error) { | ||
62 | if p.Filename == "" { | ||
63 | if value, ok := os.LookupEnv("MINIO_SHARED_CREDENTIALS_FILE"); ok { | ||
64 | p.Filename = value | ||
65 | } else { | ||
66 | homeDir, err := os.UserHomeDir() | ||
67 | if err != nil { | ||
68 | return Value{}, err | ||
69 | } | ||
70 | p.Filename = filepath.Join(homeDir, ".mc", "config.json") | ||
71 | if runtime.GOOS == "windows" { | ||
72 | p.Filename = filepath.Join(homeDir, "mc", "config.json") | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | if p.Alias == "" { | ||
78 | p.Alias = os.Getenv("MINIO_ALIAS") | ||
79 | if p.Alias == "" { | ||
80 | p.Alias = "s3" | ||
81 | } | ||
82 | } | ||
83 | |||
84 | p.retrieved = false | ||
85 | |||
86 | hostCfg, err := loadAlias(p.Filename, p.Alias) | ||
87 | if err != nil { | ||
88 | return Value{}, err | ||
89 | } | ||
90 | |||
91 | p.retrieved = true | ||
92 | return Value{ | ||
93 | AccessKeyID: hostCfg.AccessKey, | ||
94 | SecretAccessKey: hostCfg.SecretKey, | ||
95 | SignerType: parseSignatureType(hostCfg.API), | ||
96 | }, nil | ||
97 | } | ||
98 | |||
99 | // IsExpired returns if the shared credentials have expired. | ||
100 | func (p *FileMinioClient) IsExpired() bool { | ||
101 | return !p.retrieved | ||
102 | } | ||
103 | |||
104 | // hostConfig configuration of a host. | ||
105 | type hostConfig struct { | ||
106 | URL string `json:"url"` | ||
107 | AccessKey string `json:"accessKey"` | ||
108 | SecretKey string `json:"secretKey"` | ||
109 | API string `json:"api"` | ||
110 | } | ||
111 | |||
112 | // config config version. | ||
113 | type config struct { | ||
114 | Version string `json:"version"` | ||
115 | Hosts map[string]hostConfig `json:"hosts"` | ||
116 | Aliases map[string]hostConfig `json:"aliases"` | ||
117 | } | ||
118 | |||
119 | // loadAliass loads from the file pointed to by shared credentials filename for alias. | ||
120 | // The credentials retrieved from the alias will be returned or error. Error will be | ||
121 | // returned if it fails to read from the file. | ||
122 | func loadAlias(filename, alias string) (hostConfig, error) { | ||
123 | cfg := &config{} | ||
124 | json := jsoniter.ConfigCompatibleWithStandardLibrary | ||
125 | |||
126 | configBytes, err := os.ReadFile(filename) | ||
127 | if err != nil { | ||
128 | return hostConfig{}, err | ||
129 | } | ||
130 | if err = json.Unmarshal(configBytes, cfg); err != nil { | ||
131 | return hostConfig{}, err | ||
132 | } | ||
133 | |||
134 | if cfg.Version == "10" { | ||
135 | return cfg.Aliases[alias], nil | ||
136 | } | ||
137 | |||
138 | return cfg.Hosts[alias], nil | ||
139 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/iam_aws.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/iam_aws.go new file mode 100644 index 0000000..c5153c4 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/iam_aws.go | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "bufio" | ||
22 | "context" | ||
23 | "errors" | ||
24 | "fmt" | ||
25 | "io" | ||
26 | "net" | ||
27 | "net/http" | ||
28 | "net/url" | ||
29 | "os" | ||
30 | "path" | ||
31 | "strings" | ||
32 | "time" | ||
33 | |||
34 | jsoniter "github.com/json-iterator/go" | ||
35 | ) | ||
36 | |||
37 | // DefaultExpiryWindow - Default expiry window. | ||
38 | // ExpiryWindow will allow the credentials to trigger refreshing | ||
39 | // prior to the credentials actually expiring. This is beneficial | ||
40 | // so race conditions with expiring credentials do not cause | ||
41 | // request to fail unexpectedly due to ExpiredTokenException exceptions. | ||
42 | // DefaultExpiryWindow can be used as parameter to (*Expiry).SetExpiration. | ||
43 | // When used the tokens refresh will be triggered when 80% of the elapsed | ||
44 | // time until the actual expiration time is passed. | ||
45 | const DefaultExpiryWindow = -1 | ||
46 | |||
47 | // A IAM retrieves credentials from the EC2 service, and keeps track if | ||
48 | // those credentials are expired. | ||
49 | type IAM struct { | ||
50 | Expiry | ||
51 | |||
52 | // Required http Client to use when connecting to IAM metadata service. | ||
53 | Client *http.Client | ||
54 | |||
55 | // Custom endpoint to fetch IAM role credentials. | ||
56 | Endpoint string | ||
57 | |||
58 | // Region configurable custom region for STS | ||
59 | Region string | ||
60 | |||
61 | // Support for container authorization token https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html | ||
62 | Container struct { | ||
63 | AuthorizationToken string | ||
64 | CredentialsFullURI string | ||
65 | CredentialsRelativeURI string | ||
66 | } | ||
67 | |||
68 | // EKS based k8s RBAC authorization - https://docs.aws.amazon.com/eks/latest/userguide/pod-configuration.html | ||
69 | EKSIdentity struct { | ||
70 | TokenFile string | ||
71 | RoleARN string | ||
72 | RoleSessionName string | ||
73 | } | ||
74 | } | ||
75 | |||
76 | // IAM Roles for Amazon EC2 | ||
77 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
78 | const ( | ||
79 | DefaultIAMRoleEndpoint = "http://169.254.169.254" | ||
80 | DefaultECSRoleEndpoint = "http://169.254.170.2" | ||
81 | DefaultSTSRoleEndpoint = "https://sts.amazonaws.com" | ||
82 | DefaultIAMSecurityCredsPath = "/latest/meta-data/iam/security-credentials/" | ||
83 | TokenRequestTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" | ||
84 | TokenPath = "/latest/api/token" | ||
85 | TokenTTL = "21600" | ||
86 | TokenRequestHeader = "X-aws-ec2-metadata-token" | ||
87 | ) | ||
88 | |||
89 | // NewIAM returns a pointer to a new Credentials object wrapping the IAM. | ||
90 | func NewIAM(endpoint string) *Credentials { | ||
91 | return New(&IAM{ | ||
92 | Client: &http.Client{ | ||
93 | Transport: http.DefaultTransport, | ||
94 | }, | ||
95 | Endpoint: endpoint, | ||
96 | }) | ||
97 | } | ||
98 | |||
99 | // Retrieve retrieves credentials from the EC2 service. | ||
100 | // Error will be returned if the request fails, or unable to extract | ||
101 | // the desired | ||
102 | func (m *IAM) Retrieve() (Value, error) { | ||
103 | token := os.Getenv("AWS_CONTAINER_AUTHORIZATION_TOKEN") | ||
104 | if token == "" { | ||
105 | token = m.Container.AuthorizationToken | ||
106 | } | ||
107 | |||
108 | relativeURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") | ||
109 | if relativeURI == "" { | ||
110 | relativeURI = m.Container.CredentialsRelativeURI | ||
111 | } | ||
112 | |||
113 | fullURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI") | ||
114 | if fullURI == "" { | ||
115 | fullURI = m.Container.CredentialsFullURI | ||
116 | } | ||
117 | |||
118 | identityFile := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE") | ||
119 | if identityFile == "" { | ||
120 | identityFile = m.EKSIdentity.TokenFile | ||
121 | } | ||
122 | |||
123 | roleArn := os.Getenv("AWS_ROLE_ARN") | ||
124 | if roleArn == "" { | ||
125 | roleArn = m.EKSIdentity.RoleARN | ||
126 | } | ||
127 | |||
128 | roleSessionName := os.Getenv("AWS_ROLE_SESSION_NAME") | ||
129 | if roleSessionName == "" { | ||
130 | roleSessionName = m.EKSIdentity.RoleSessionName | ||
131 | } | ||
132 | |||
133 | region := os.Getenv("AWS_REGION") | ||
134 | if region == "" { | ||
135 | region = m.Region | ||
136 | } | ||
137 | |||
138 | var roleCreds ec2RoleCredRespBody | ||
139 | var err error | ||
140 | |||
141 | endpoint := m.Endpoint | ||
142 | switch { | ||
143 | case identityFile != "": | ||
144 | if len(endpoint) == 0 { | ||
145 | if region != "" { | ||
146 | if strings.HasPrefix(region, "cn-") { | ||
147 | endpoint = "https://sts." + region + ".amazonaws.com.cn" | ||
148 | } else { | ||
149 | endpoint = "https://sts." + region + ".amazonaws.com" | ||
150 | } | ||
151 | } else { | ||
152 | endpoint = DefaultSTSRoleEndpoint | ||
153 | } | ||
154 | } | ||
155 | |||
156 | creds := &STSWebIdentity{ | ||
157 | Client: m.Client, | ||
158 | STSEndpoint: endpoint, | ||
159 | GetWebIDTokenExpiry: func() (*WebIdentityToken, error) { | ||
160 | token, err := os.ReadFile(identityFile) | ||
161 | if err != nil { | ||
162 | return nil, err | ||
163 | } | ||
164 | |||
165 | return &WebIdentityToken{Token: string(token)}, nil | ||
166 | }, | ||
167 | RoleARN: roleArn, | ||
168 | roleSessionName: roleSessionName, | ||
169 | } | ||
170 | |||
171 | stsWebIdentityCreds, err := creds.Retrieve() | ||
172 | if err == nil { | ||
173 | m.SetExpiration(creds.Expiration(), DefaultExpiryWindow) | ||
174 | } | ||
175 | return stsWebIdentityCreds, err | ||
176 | |||
177 | case relativeURI != "": | ||
178 | if len(endpoint) == 0 { | ||
179 | endpoint = fmt.Sprintf("%s%s", DefaultECSRoleEndpoint, relativeURI) | ||
180 | } | ||
181 | |||
182 | roleCreds, err = getEcsTaskCredentials(m.Client, endpoint, token) | ||
183 | |||
184 | case fullURI != "": | ||
185 | if len(endpoint) == 0 { | ||
186 | endpoint = fullURI | ||
187 | var ok bool | ||
188 | if ok, err = isLoopback(endpoint); !ok { | ||
189 | if err == nil { | ||
190 | err = fmt.Errorf("uri host is not a loopback address: %s", endpoint) | ||
191 | } | ||
192 | break | ||
193 | } | ||
194 | } | ||
195 | |||
196 | roleCreds, err = getEcsTaskCredentials(m.Client, endpoint, token) | ||
197 | |||
198 | default: | ||
199 | roleCreds, err = getCredentials(m.Client, endpoint) | ||
200 | } | ||
201 | |||
202 | if err != nil { | ||
203 | return Value{}, err | ||
204 | } | ||
205 | // Expiry window is set to 10secs. | ||
206 | m.SetExpiration(roleCreds.Expiration, DefaultExpiryWindow) | ||
207 | |||
208 | return Value{ | ||
209 | AccessKeyID: roleCreds.AccessKeyID, | ||
210 | SecretAccessKey: roleCreds.SecretAccessKey, | ||
211 | SessionToken: roleCreds.Token, | ||
212 | SignerType: SignatureV4, | ||
213 | }, nil | ||
214 | } | ||
215 | |||
216 | // A ec2RoleCredRespBody provides the shape for unmarshaling credential | ||
217 | // request responses. | ||
218 | type ec2RoleCredRespBody struct { | ||
219 | // Success State | ||
220 | Expiration time.Time | ||
221 | AccessKeyID string | ||
222 | SecretAccessKey string | ||
223 | Token string | ||
224 | |||
225 | // Error state | ||
226 | Code string | ||
227 | Message string | ||
228 | |||
229 | // Unused params. | ||
230 | LastUpdated time.Time | ||
231 | Type string | ||
232 | } | ||
233 | |||
234 | // Get the final IAM role URL where the request will | ||
235 | // be sent to fetch the rolling access credentials. | ||
236 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
237 | func getIAMRoleURL(endpoint string) (*url.URL, error) { | ||
238 | u, err := url.Parse(endpoint) | ||
239 | if err != nil { | ||
240 | return nil, err | ||
241 | } | ||
242 | u.Path = DefaultIAMSecurityCredsPath | ||
243 | return u, nil | ||
244 | } | ||
245 | |||
246 | // listRoleNames lists of credential role names associated | ||
247 | // with the current EC2 service. If there are no credentials, | ||
248 | // or there is an error making or receiving the request. | ||
249 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
250 | func listRoleNames(client *http.Client, u *url.URL, token string) ([]string, error) { | ||
251 | req, err := http.NewRequest(http.MethodGet, u.String(), nil) | ||
252 | if err != nil { | ||
253 | return nil, err | ||
254 | } | ||
255 | if token != "" { | ||
256 | req.Header.Add(TokenRequestHeader, token) | ||
257 | } | ||
258 | resp, err := client.Do(req) | ||
259 | if err != nil { | ||
260 | return nil, err | ||
261 | } | ||
262 | defer resp.Body.Close() | ||
263 | if resp.StatusCode != http.StatusOK { | ||
264 | return nil, errors.New(resp.Status) | ||
265 | } | ||
266 | |||
267 | credsList := []string{} | ||
268 | s := bufio.NewScanner(resp.Body) | ||
269 | for s.Scan() { | ||
270 | credsList = append(credsList, s.Text()) | ||
271 | } | ||
272 | |||
273 | if err := s.Err(); err != nil { | ||
274 | return nil, err | ||
275 | } | ||
276 | |||
277 | return credsList, nil | ||
278 | } | ||
279 | |||
280 | func getEcsTaskCredentials(client *http.Client, endpoint, token string) (ec2RoleCredRespBody, error) { | ||
281 | req, err := http.NewRequest(http.MethodGet, endpoint, nil) | ||
282 | if err != nil { | ||
283 | return ec2RoleCredRespBody{}, err | ||
284 | } | ||
285 | |||
286 | if token != "" { | ||
287 | req.Header.Set("Authorization", token) | ||
288 | } | ||
289 | |||
290 | resp, err := client.Do(req) | ||
291 | if err != nil { | ||
292 | return ec2RoleCredRespBody{}, err | ||
293 | } | ||
294 | defer resp.Body.Close() | ||
295 | if resp.StatusCode != http.StatusOK { | ||
296 | return ec2RoleCredRespBody{}, errors.New(resp.Status) | ||
297 | } | ||
298 | |||
299 | respCreds := ec2RoleCredRespBody{} | ||
300 | if err := jsoniter.NewDecoder(resp.Body).Decode(&respCreds); err != nil { | ||
301 | return ec2RoleCredRespBody{}, err | ||
302 | } | ||
303 | |||
304 | return respCreds, nil | ||
305 | } | ||
306 | |||
307 | func fetchIMDSToken(client *http.Client, endpoint string) (string, error) { | ||
308 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
309 | defer cancel() | ||
310 | |||
311 | req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint+TokenPath, nil) | ||
312 | if err != nil { | ||
313 | return "", err | ||
314 | } | ||
315 | req.Header.Add(TokenRequestTTLHeader, TokenTTL) | ||
316 | resp, err := client.Do(req) | ||
317 | if err != nil { | ||
318 | return "", err | ||
319 | } | ||
320 | defer resp.Body.Close() | ||
321 | data, err := io.ReadAll(resp.Body) | ||
322 | if err != nil { | ||
323 | return "", err | ||
324 | } | ||
325 | if resp.StatusCode != http.StatusOK { | ||
326 | return "", errors.New(resp.Status) | ||
327 | } | ||
328 | return string(data), nil | ||
329 | } | ||
330 | |||
331 | // getCredentials - obtains the credentials from the IAM role name associated with | ||
332 | // the current EC2 service. | ||
333 | // | ||
334 | // If the credentials cannot be found, or there is an error | ||
335 | // reading the response an error will be returned. | ||
336 | func getCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, error) { | ||
337 | if endpoint == "" { | ||
338 | endpoint = DefaultIAMRoleEndpoint | ||
339 | } | ||
340 | |||
341 | // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html | ||
342 | token, err := fetchIMDSToken(client, endpoint) | ||
343 | if err != nil { | ||
344 | // Return only errors for valid situations, if the IMDSv2 is not enabled | ||
345 | // we will not be able to get the token, in such a situation we have | ||
346 | // to rely on IMDSv1 behavior as a fallback, this check ensures that. | ||
347 | // Refer https://github.com/minio/minio-go/issues/1866 | ||
348 | if !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, context.Canceled) { | ||
349 | return ec2RoleCredRespBody{}, err | ||
350 | } | ||
351 | } | ||
352 | |||
353 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
354 | u, err := getIAMRoleURL(endpoint) | ||
355 | if err != nil { | ||
356 | return ec2RoleCredRespBody{}, err | ||
357 | } | ||
358 | |||
359 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
360 | roleNames, err := listRoleNames(client, u, token) | ||
361 | if err != nil { | ||
362 | return ec2RoleCredRespBody{}, err | ||
363 | } | ||
364 | |||
365 | if len(roleNames) == 0 { | ||
366 | return ec2RoleCredRespBody{}, errors.New("No IAM roles attached to this EC2 service") | ||
367 | } | ||
368 | |||
369 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
370 | // - An instance profile can contain only one IAM role. This limit cannot be increased. | ||
371 | roleName := roleNames[0] | ||
372 | |||
373 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
374 | // The following command retrieves the security credentials for an | ||
375 | // IAM role named `s3access`. | ||
376 | // | ||
377 | // $ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access | ||
378 | // | ||
379 | u.Path = path.Join(u.Path, roleName) | ||
380 | req, err := http.NewRequest(http.MethodGet, u.String(), nil) | ||
381 | if err != nil { | ||
382 | return ec2RoleCredRespBody{}, err | ||
383 | } | ||
384 | if token != "" { | ||
385 | req.Header.Add(TokenRequestHeader, token) | ||
386 | } | ||
387 | |||
388 | resp, err := client.Do(req) | ||
389 | if err != nil { | ||
390 | return ec2RoleCredRespBody{}, err | ||
391 | } | ||
392 | defer resp.Body.Close() | ||
393 | if resp.StatusCode != http.StatusOK { | ||
394 | return ec2RoleCredRespBody{}, errors.New(resp.Status) | ||
395 | } | ||
396 | |||
397 | respCreds := ec2RoleCredRespBody{} | ||
398 | if err := jsoniter.NewDecoder(resp.Body).Decode(&respCreds); err != nil { | ||
399 | return ec2RoleCredRespBody{}, err | ||
400 | } | ||
401 | |||
402 | if respCreds.Code != "Success" { | ||
403 | // If an error code was returned something failed requesting the role. | ||
404 | return ec2RoleCredRespBody{}, errors.New(respCreds.Message) | ||
405 | } | ||
406 | |||
407 | return respCreds, nil | ||
408 | } | ||
409 | |||
410 | // isLoopback identifies if a uri's host is on a loopback address | ||
411 | func isLoopback(uri string) (bool, error) { | ||
412 | u, err := url.Parse(uri) | ||
413 | if err != nil { | ||
414 | return false, err | ||
415 | } | ||
416 | |||
417 | host := u.Hostname() | ||
418 | if len(host) == 0 { | ||
419 | return false, fmt.Errorf("can't parse host from uri: %s", uri) | ||
420 | } | ||
421 | |||
422 | ips, err := net.LookupHost(host) | ||
423 | if err != nil { | ||
424 | return false, err | ||
425 | } | ||
426 | for _, ip := range ips { | ||
427 | if !net.ParseIP(ip).IsLoopback() { | ||
428 | return false, nil | ||
429 | } | ||
430 | } | ||
431 | |||
432 | return true, nil | ||
433 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/signature_type.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/signature_type.go new file mode 100644 index 0000000..b794333 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/signature_type.go | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import "strings" | ||
21 | |||
22 | // SignatureType is type of Authorization requested for a given HTTP request. | ||
23 | type SignatureType int | ||
24 | |||
25 | // Different types of supported signatures - default is SignatureV4 or SignatureDefault. | ||
26 | const ( | ||
27 | // SignatureDefault is always set to v4. | ||
28 | SignatureDefault SignatureType = iota | ||
29 | SignatureV4 | ||
30 | SignatureV2 | ||
31 | SignatureV4Streaming | ||
32 | SignatureAnonymous // Anonymous signature signifies, no signature. | ||
33 | ) | ||
34 | |||
35 | // IsV2 - is signature SignatureV2? | ||
36 | func (s SignatureType) IsV2() bool { | ||
37 | return s == SignatureV2 | ||
38 | } | ||
39 | |||
40 | // IsV4 - is signature SignatureV4? | ||
41 | func (s SignatureType) IsV4() bool { | ||
42 | return s == SignatureV4 || s == SignatureDefault | ||
43 | } | ||
44 | |||
45 | // IsStreamingV4 - is signature SignatureV4Streaming? | ||
46 | func (s SignatureType) IsStreamingV4() bool { | ||
47 | return s == SignatureV4Streaming | ||
48 | } | ||
49 | |||
50 | // IsAnonymous - is signature empty? | ||
51 | func (s SignatureType) IsAnonymous() bool { | ||
52 | return s == SignatureAnonymous | ||
53 | } | ||
54 | |||
55 | // Stringer humanized version of signature type, | ||
56 | // strings returned here are case insensitive. | ||
57 | func (s SignatureType) String() string { | ||
58 | if s.IsV2() { | ||
59 | return "S3v2" | ||
60 | } else if s.IsV4() { | ||
61 | return "S3v4" | ||
62 | } else if s.IsStreamingV4() { | ||
63 | return "S3v4Streaming" | ||
64 | } | ||
65 | return "Anonymous" | ||
66 | } | ||
67 | |||
68 | func parseSignatureType(str string) SignatureType { | ||
69 | if strings.EqualFold(str, "S3v4") { | ||
70 | return SignatureV4 | ||
71 | } else if strings.EqualFold(str, "S3v2") { | ||
72 | return SignatureV2 | ||
73 | } else if strings.EqualFold(str, "S3v4Streaming") { | ||
74 | return SignatureV4Streaming | ||
75 | } | ||
76 | return SignatureAnonymous | ||
77 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/static.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/static.go new file mode 100644 index 0000000..7dde00b --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/static.go | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2017 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | // A Static is a set of credentials which are set programmatically, | ||
21 | // and will never expire. | ||
22 | type Static struct { | ||
23 | Value | ||
24 | } | ||
25 | |||
26 | // NewStaticV2 returns a pointer to a new Credentials object | ||
27 | // wrapping a static credentials value provider, signature is | ||
28 | // set to v2. If access and secret are not specified then | ||
29 | // regardless of signature type set it Value will return | ||
30 | // as anonymous. | ||
31 | func NewStaticV2(id, secret, token string) *Credentials { | ||
32 | return NewStatic(id, secret, token, SignatureV2) | ||
33 | } | ||
34 | |||
35 | // NewStaticV4 is similar to NewStaticV2 with similar considerations. | ||
36 | func NewStaticV4(id, secret, token string) *Credentials { | ||
37 | return NewStatic(id, secret, token, SignatureV4) | ||
38 | } | ||
39 | |||
40 | // NewStatic returns a pointer to a new Credentials object | ||
41 | // wrapping a static credentials value provider. | ||
42 | func NewStatic(id, secret, token string, signerType SignatureType) *Credentials { | ||
43 | return New(&Static{ | ||
44 | Value: Value{ | ||
45 | AccessKeyID: id, | ||
46 | SecretAccessKey: secret, | ||
47 | SessionToken: token, | ||
48 | SignerType: signerType, | ||
49 | }, | ||
50 | }) | ||
51 | } | ||
52 | |||
53 | // Retrieve returns the static credentials. | ||
54 | func (s *Static) Retrieve() (Value, error) { | ||
55 | if s.AccessKeyID == "" || s.SecretAccessKey == "" { | ||
56 | // Anonymous is not an error | ||
57 | return Value{SignerType: SignatureAnonymous}, nil | ||
58 | } | ||
59 | return s.Value, nil | ||
60 | } | ||
61 | |||
62 | // IsExpired returns if the credentials are expired. | ||
63 | // | ||
64 | // For Static, the credentials never expired. | ||
65 | func (s *Static) IsExpired() bool { | ||
66 | return false | ||
67 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_client_grants.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_client_grants.go new file mode 100644 index 0000000..9e92c1e --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_client_grants.go | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2019-2022 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "bytes" | ||
22 | "encoding/xml" | ||
23 | "errors" | ||
24 | "fmt" | ||
25 | "io" | ||
26 | "net/http" | ||
27 | "net/url" | ||
28 | "strings" | ||
29 | "time" | ||
30 | ) | ||
31 | |||
32 | // AssumedRoleUser - The identifiers for the temporary security credentials that | ||
33 | // the operation returns. Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser | ||
34 | type AssumedRoleUser struct { | ||
35 | Arn string | ||
36 | AssumedRoleID string `xml:"AssumeRoleId"` | ||
37 | } | ||
38 | |||
39 | // AssumeRoleWithClientGrantsResponse contains the result of successful AssumeRoleWithClientGrants request. | ||
40 | type AssumeRoleWithClientGrantsResponse struct { | ||
41 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithClientGrantsResponse" json:"-"` | ||
42 | Result ClientGrantsResult `xml:"AssumeRoleWithClientGrantsResult"` | ||
43 | ResponseMetadata struct { | ||
44 | RequestID string `xml:"RequestId,omitempty"` | ||
45 | } `xml:"ResponseMetadata,omitempty"` | ||
46 | } | ||
47 | |||
48 | // ClientGrantsResult - Contains the response to a successful AssumeRoleWithClientGrants | ||
49 | // request, including temporary credentials that can be used to make MinIO API requests. | ||
50 | type ClientGrantsResult struct { | ||
51 | AssumedRoleUser AssumedRoleUser `xml:",omitempty"` | ||
52 | Audience string `xml:",omitempty"` | ||
53 | Credentials struct { | ||
54 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
55 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
56 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
57 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
58 | } `xml:",omitempty"` | ||
59 | PackedPolicySize int `xml:",omitempty"` | ||
60 | Provider string `xml:",omitempty"` | ||
61 | SubjectFromClientGrantsToken string `xml:",omitempty"` | ||
62 | } | ||
63 | |||
64 | // ClientGrantsToken - client grants token with expiry. | ||
65 | type ClientGrantsToken struct { | ||
66 | Token string | ||
67 | Expiry int | ||
68 | } | ||
69 | |||
70 | // A STSClientGrants retrieves credentials from MinIO service, and keeps track if | ||
71 | // those credentials are expired. | ||
72 | type STSClientGrants struct { | ||
73 | Expiry | ||
74 | |||
75 | // Required http Client to use when connecting to MinIO STS service. | ||
76 | Client *http.Client | ||
77 | |||
78 | // MinIO endpoint to fetch STS credentials. | ||
79 | STSEndpoint string | ||
80 | |||
81 | // getClientGrantsTokenExpiry function to retrieve tokens | ||
82 | // from IDP This function should return two values one is | ||
83 | // accessToken which is a self contained access token (JWT) | ||
84 | // and second return value is the expiry associated with | ||
85 | // this token. This is a customer provided function and | ||
86 | // is mandatory. | ||
87 | GetClientGrantsTokenExpiry func() (*ClientGrantsToken, error) | ||
88 | } | ||
89 | |||
90 | // NewSTSClientGrants returns a pointer to a new | ||
91 | // Credentials object wrapping the STSClientGrants. | ||
92 | func NewSTSClientGrants(stsEndpoint string, getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (*Credentials, error) { | ||
93 | if stsEndpoint == "" { | ||
94 | return nil, errors.New("STS endpoint cannot be empty") | ||
95 | } | ||
96 | if getClientGrantsTokenExpiry == nil { | ||
97 | return nil, errors.New("Client grants access token and expiry retrieval function should be defined") | ||
98 | } | ||
99 | return New(&STSClientGrants{ | ||
100 | Client: &http.Client{ | ||
101 | Transport: http.DefaultTransport, | ||
102 | }, | ||
103 | STSEndpoint: stsEndpoint, | ||
104 | GetClientGrantsTokenExpiry: getClientGrantsTokenExpiry, | ||
105 | }), nil | ||
106 | } | ||
107 | |||
108 | func getClientGrantsCredentials(clnt *http.Client, endpoint string, | ||
109 | getClientGrantsTokenExpiry func() (*ClientGrantsToken, error), | ||
110 | ) (AssumeRoleWithClientGrantsResponse, error) { | ||
111 | accessToken, err := getClientGrantsTokenExpiry() | ||
112 | if err != nil { | ||
113 | return AssumeRoleWithClientGrantsResponse{}, err | ||
114 | } | ||
115 | |||
116 | v := url.Values{} | ||
117 | v.Set("Action", "AssumeRoleWithClientGrants") | ||
118 | v.Set("Token", accessToken.Token) | ||
119 | v.Set("DurationSeconds", fmt.Sprintf("%d", accessToken.Expiry)) | ||
120 | v.Set("Version", STSVersion) | ||
121 | |||
122 | u, err := url.Parse(endpoint) | ||
123 | if err != nil { | ||
124 | return AssumeRoleWithClientGrantsResponse{}, err | ||
125 | } | ||
126 | |||
127 | req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(v.Encode())) | ||
128 | if err != nil { | ||
129 | return AssumeRoleWithClientGrantsResponse{}, err | ||
130 | } | ||
131 | |||
132 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
133 | |||
134 | resp, err := clnt.Do(req) | ||
135 | if err != nil { | ||
136 | return AssumeRoleWithClientGrantsResponse{}, err | ||
137 | } | ||
138 | defer resp.Body.Close() | ||
139 | if resp.StatusCode != http.StatusOK { | ||
140 | var errResp ErrorResponse | ||
141 | buf, err := io.ReadAll(resp.Body) | ||
142 | if err != nil { | ||
143 | return AssumeRoleWithClientGrantsResponse{}, err | ||
144 | } | ||
145 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
146 | if err != nil { | ||
147 | var s3Err Error | ||
148 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
149 | return AssumeRoleWithClientGrantsResponse{}, err | ||
150 | } | ||
151 | errResp.RequestID = s3Err.RequestID | ||
152 | errResp.STSError.Code = s3Err.Code | ||
153 | errResp.STSError.Message = s3Err.Message | ||
154 | } | ||
155 | return AssumeRoleWithClientGrantsResponse{}, errResp | ||
156 | } | ||
157 | |||
158 | a := AssumeRoleWithClientGrantsResponse{} | ||
159 | if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { | ||
160 | return AssumeRoleWithClientGrantsResponse{}, err | ||
161 | } | ||
162 | return a, nil | ||
163 | } | ||
164 | |||
165 | // Retrieve retrieves credentials from the MinIO service. | ||
166 | // Error will be returned if the request fails. | ||
167 | func (m *STSClientGrants) Retrieve() (Value, error) { | ||
168 | a, err := getClientGrantsCredentials(m.Client, m.STSEndpoint, m.GetClientGrantsTokenExpiry) | ||
169 | if err != nil { | ||
170 | return Value{}, err | ||
171 | } | ||
172 | |||
173 | // Expiry window is set to 10secs. | ||
174 | m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
175 | |||
176 | return Value{ | ||
177 | AccessKeyID: a.Result.Credentials.AccessKey, | ||
178 | SecretAccessKey: a.Result.Credentials.SecretKey, | ||
179 | SessionToken: a.Result.Credentials.SessionToken, | ||
180 | SignerType: SignatureV4, | ||
181 | }, nil | ||
182 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_custom_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_custom_identity.go new file mode 100644 index 0000000..e1f9ce4 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_custom_identity.go | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2015-2022 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "encoding/xml" | ||
22 | "errors" | ||
23 | "fmt" | ||
24 | "net/http" | ||
25 | "net/url" | ||
26 | "time" | ||
27 | ) | ||
28 | |||
29 | // CustomTokenResult - Contains temporary creds and user metadata. | ||
30 | type CustomTokenResult struct { | ||
31 | Credentials struct { | ||
32 | AccessKey string `xml:"AccessKeyId"` | ||
33 | SecretKey string `xml:"SecretAccessKey"` | ||
34 | Expiration time.Time `xml:"Expiration"` | ||
35 | SessionToken string `xml:"SessionToken"` | ||
36 | } `xml:",omitempty"` | ||
37 | |||
38 | AssumedUser string `xml:",omitempty"` | ||
39 | } | ||
40 | |||
41 | // AssumeRoleWithCustomTokenResponse contains the result of a successful | ||
42 | // AssumeRoleWithCustomToken request. | ||
43 | type AssumeRoleWithCustomTokenResponse struct { | ||
44 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithCustomTokenResponse" json:"-"` | ||
45 | Result CustomTokenResult `xml:"AssumeRoleWithCustomTokenResult"` | ||
46 | Metadata struct { | ||
47 | RequestID string `xml:"RequestId,omitempty"` | ||
48 | } `xml:"ResponseMetadata,omitempty"` | ||
49 | } | ||
50 | |||
51 | // CustomTokenIdentity - satisfies the Provider interface, and retrieves | ||
52 | // credentials from MinIO using the AssumeRoleWithCustomToken STS API. | ||
53 | type CustomTokenIdentity struct { | ||
54 | Expiry | ||
55 | |||
56 | Client *http.Client | ||
57 | |||
58 | // MinIO server STS endpoint to fetch STS credentials. | ||
59 | STSEndpoint string | ||
60 | |||
61 | // The custom token to use with the request. | ||
62 | Token string | ||
63 | |||
64 | // RoleArn associated with the identity | ||
65 | RoleArn string | ||
66 | |||
67 | // RequestedExpiry is to set the validity of the generated credentials | ||
68 | // (this value bounded by server). | ||
69 | RequestedExpiry time.Duration | ||
70 | } | ||
71 | |||
72 | // Retrieve - to satisfy Provider interface; fetches credentials from MinIO. | ||
73 | func (c *CustomTokenIdentity) Retrieve() (value Value, err error) { | ||
74 | u, err := url.Parse(c.STSEndpoint) | ||
75 | if err != nil { | ||
76 | return value, err | ||
77 | } | ||
78 | |||
79 | v := url.Values{} | ||
80 | v.Set("Action", "AssumeRoleWithCustomToken") | ||
81 | v.Set("Version", STSVersion) | ||
82 | v.Set("RoleArn", c.RoleArn) | ||
83 | v.Set("Token", c.Token) | ||
84 | if c.RequestedExpiry != 0 { | ||
85 | v.Set("DurationSeconds", fmt.Sprintf("%d", int(c.RequestedExpiry.Seconds()))) | ||
86 | } | ||
87 | |||
88 | u.RawQuery = v.Encode() | ||
89 | |||
90 | req, err := http.NewRequest(http.MethodPost, u.String(), nil) | ||
91 | if err != nil { | ||
92 | return value, err | ||
93 | } | ||
94 | |||
95 | resp, err := c.Client.Do(req) | ||
96 | if err != nil { | ||
97 | return value, err | ||
98 | } | ||
99 | |||
100 | defer resp.Body.Close() | ||
101 | if resp.StatusCode != http.StatusOK { | ||
102 | return value, errors.New(resp.Status) | ||
103 | } | ||
104 | |||
105 | r := AssumeRoleWithCustomTokenResponse{} | ||
106 | if err = xml.NewDecoder(resp.Body).Decode(&r); err != nil { | ||
107 | return | ||
108 | } | ||
109 | |||
110 | cr := r.Result.Credentials | ||
111 | c.SetExpiration(cr.Expiration, DefaultExpiryWindow) | ||
112 | return Value{ | ||
113 | AccessKeyID: cr.AccessKey, | ||
114 | SecretAccessKey: cr.SecretKey, | ||
115 | SessionToken: cr.SessionToken, | ||
116 | SignerType: SignatureV4, | ||
117 | }, nil | ||
118 | } | ||
119 | |||
120 | // NewCustomTokenCredentials - returns credentials using the | ||
121 | // AssumeRoleWithCustomToken STS API. | ||
122 | func NewCustomTokenCredentials(stsEndpoint, token, roleArn string, optFuncs ...CustomTokenOpt) (*Credentials, error) { | ||
123 | c := CustomTokenIdentity{ | ||
124 | Client: &http.Client{Transport: http.DefaultTransport}, | ||
125 | STSEndpoint: stsEndpoint, | ||
126 | Token: token, | ||
127 | RoleArn: roleArn, | ||
128 | } | ||
129 | for _, optFunc := range optFuncs { | ||
130 | optFunc(&c) | ||
131 | } | ||
132 | return New(&c), nil | ||
133 | } | ||
134 | |||
135 | // CustomTokenOpt is a function type to configure the custom-token based | ||
136 | // credentials using NewCustomTokenCredentials. | ||
137 | type CustomTokenOpt func(*CustomTokenIdentity) | ||
138 | |||
139 | // CustomTokenValidityOpt sets the validity duration of the requested | ||
140 | // credentials. This value is ignored if the server enforces a lower validity | ||
141 | // period. | ||
142 | func CustomTokenValidityOpt(d time.Duration) CustomTokenOpt { | ||
143 | return func(c *CustomTokenIdentity) { | ||
144 | c.RequestedExpiry = d | ||
145 | } | ||
146 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_ldap_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_ldap_identity.go new file mode 100644 index 0000000..ec5f3f0 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_ldap_identity.go | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2019-2022 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "bytes" | ||
22 | "encoding/xml" | ||
23 | "fmt" | ||
24 | "io" | ||
25 | "net/http" | ||
26 | "net/url" | ||
27 | "strings" | ||
28 | "time" | ||
29 | ) | ||
30 | |||
31 | // AssumeRoleWithLDAPResponse contains the result of successful | ||
32 | // AssumeRoleWithLDAPIdentity request | ||
33 | type AssumeRoleWithLDAPResponse struct { | ||
34 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithLDAPIdentityResponse" json:"-"` | ||
35 | Result LDAPIdentityResult `xml:"AssumeRoleWithLDAPIdentityResult"` | ||
36 | ResponseMetadata struct { | ||
37 | RequestID string `xml:"RequestId,omitempty"` | ||
38 | } `xml:"ResponseMetadata,omitempty"` | ||
39 | } | ||
40 | |||
41 | // LDAPIdentityResult - contains credentials for a successful | ||
42 | // AssumeRoleWithLDAPIdentity request. | ||
43 | type LDAPIdentityResult struct { | ||
44 | Credentials struct { | ||
45 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
46 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
47 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
48 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
49 | } `xml:",omitempty"` | ||
50 | |||
51 | SubjectFromToken string `xml:",omitempty"` | ||
52 | } | ||
53 | |||
54 | // LDAPIdentity retrieves credentials from MinIO | ||
55 | type LDAPIdentity struct { | ||
56 | Expiry | ||
57 | |||
58 | // Required http Client to use when connecting to MinIO STS service. | ||
59 | Client *http.Client | ||
60 | |||
61 | // Exported STS endpoint to fetch STS credentials. | ||
62 | STSEndpoint string | ||
63 | |||
64 | // LDAP username/password used to fetch LDAP STS credentials. | ||
65 | LDAPUsername, LDAPPassword string | ||
66 | |||
67 | // Session policy to apply to the generated credentials. Leave empty to | ||
68 | // use the full access policy available to the user. | ||
69 | Policy string | ||
70 | |||
71 | // RequestedExpiry is the configured expiry duration for credentials | ||
72 | // requested from LDAP. | ||
73 | RequestedExpiry time.Duration | ||
74 | } | ||
75 | |||
76 | // NewLDAPIdentity returns new credentials object that uses LDAP | ||
77 | // Identity. | ||
78 | func NewLDAPIdentity(stsEndpoint, ldapUsername, ldapPassword string, optFuncs ...LDAPIdentityOpt) (*Credentials, error) { | ||
79 | l := LDAPIdentity{ | ||
80 | Client: &http.Client{Transport: http.DefaultTransport}, | ||
81 | STSEndpoint: stsEndpoint, | ||
82 | LDAPUsername: ldapUsername, | ||
83 | LDAPPassword: ldapPassword, | ||
84 | } | ||
85 | for _, optFunc := range optFuncs { | ||
86 | optFunc(&l) | ||
87 | } | ||
88 | return New(&l), nil | ||
89 | } | ||
90 | |||
91 | // LDAPIdentityOpt is a function type used to configured the LDAPIdentity | ||
92 | // instance. | ||
93 | type LDAPIdentityOpt func(*LDAPIdentity) | ||
94 | |||
95 | // LDAPIdentityPolicyOpt sets the session policy for requested credentials. | ||
96 | func LDAPIdentityPolicyOpt(policy string) LDAPIdentityOpt { | ||
97 | return func(k *LDAPIdentity) { | ||
98 | k.Policy = policy | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // LDAPIdentityExpiryOpt sets the expiry duration for requested credentials. | ||
103 | func LDAPIdentityExpiryOpt(d time.Duration) LDAPIdentityOpt { | ||
104 | return func(k *LDAPIdentity) { | ||
105 | k.RequestedExpiry = d | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // NewLDAPIdentityWithSessionPolicy returns new credentials object that uses | ||
110 | // LDAP Identity with a specified session policy. The `policy` parameter must be | ||
111 | // a JSON string specifying the policy document. | ||
112 | // | ||
113 | // Deprecated: Use the `LDAPIdentityPolicyOpt` with `NewLDAPIdentity` instead. | ||
114 | func NewLDAPIdentityWithSessionPolicy(stsEndpoint, ldapUsername, ldapPassword, policy string) (*Credentials, error) { | ||
115 | return New(&LDAPIdentity{ | ||
116 | Client: &http.Client{Transport: http.DefaultTransport}, | ||
117 | STSEndpoint: stsEndpoint, | ||
118 | LDAPUsername: ldapUsername, | ||
119 | LDAPPassword: ldapPassword, | ||
120 | Policy: policy, | ||
121 | }), nil | ||
122 | } | ||
123 | |||
124 | // Retrieve gets the credential by calling the MinIO STS API for | ||
125 | // LDAP on the configured stsEndpoint. | ||
126 | func (k *LDAPIdentity) Retrieve() (value Value, err error) { | ||
127 | u, err := url.Parse(k.STSEndpoint) | ||
128 | if err != nil { | ||
129 | return value, err | ||
130 | } | ||
131 | |||
132 | v := url.Values{} | ||
133 | v.Set("Action", "AssumeRoleWithLDAPIdentity") | ||
134 | v.Set("Version", STSVersion) | ||
135 | v.Set("LDAPUsername", k.LDAPUsername) | ||
136 | v.Set("LDAPPassword", k.LDAPPassword) | ||
137 | if k.Policy != "" { | ||
138 | v.Set("Policy", k.Policy) | ||
139 | } | ||
140 | if k.RequestedExpiry != 0 { | ||
141 | v.Set("DurationSeconds", fmt.Sprintf("%d", int(k.RequestedExpiry.Seconds()))) | ||
142 | } | ||
143 | |||
144 | req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(v.Encode())) | ||
145 | if err != nil { | ||
146 | return value, err | ||
147 | } | ||
148 | |||
149 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
150 | |||
151 | resp, err := k.Client.Do(req) | ||
152 | if err != nil { | ||
153 | return value, err | ||
154 | } | ||
155 | |||
156 | defer resp.Body.Close() | ||
157 | if resp.StatusCode != http.StatusOK { | ||
158 | var errResp ErrorResponse | ||
159 | buf, err := io.ReadAll(resp.Body) | ||
160 | if err != nil { | ||
161 | return value, err | ||
162 | } | ||
163 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
164 | if err != nil { | ||
165 | var s3Err Error | ||
166 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
167 | return value, err | ||
168 | } | ||
169 | errResp.RequestID = s3Err.RequestID | ||
170 | errResp.STSError.Code = s3Err.Code | ||
171 | errResp.STSError.Message = s3Err.Message | ||
172 | } | ||
173 | return value, errResp | ||
174 | } | ||
175 | |||
176 | r := AssumeRoleWithLDAPResponse{} | ||
177 | if err = xml.NewDecoder(resp.Body).Decode(&r); err != nil { | ||
178 | return | ||
179 | } | ||
180 | |||
181 | cr := r.Result.Credentials | ||
182 | k.SetExpiration(cr.Expiration, DefaultExpiryWindow) | ||
183 | return Value{ | ||
184 | AccessKeyID: cr.AccessKey, | ||
185 | SecretAccessKey: cr.SecretKey, | ||
186 | SessionToken: cr.SessionToken, | ||
187 | SignerType: SignatureV4, | ||
188 | }, nil | ||
189 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go new file mode 100644 index 0000000..dee0a8c --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go | |||
@@ -0,0 +1,211 @@ | |||
1 | // MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
2 | // Copyright 2021 MinIO, Inc. | ||
3 | // | ||
4 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | // you may not use this file except in compliance with the License. | ||
6 | // You may obtain a copy of the License at | ||
7 | // | ||
8 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | // | ||
10 | // Unless required by applicable law or agreed to in writing, software | ||
11 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | // See the License for the specific language governing permissions and | ||
14 | // limitations under the License. | ||
15 | |||
16 | package credentials | ||
17 | |||
18 | import ( | ||
19 | "bytes" | ||
20 | "crypto/tls" | ||
21 | "encoding/xml" | ||
22 | "errors" | ||
23 | "io" | ||
24 | "net" | ||
25 | "net/http" | ||
26 | "net/url" | ||
27 | "strconv" | ||
28 | "time" | ||
29 | ) | ||
30 | |||
31 | // CertificateIdentityOption is an optional AssumeRoleWithCertificate | ||
32 | // parameter - e.g. a custom HTTP transport configuration or S3 credental | ||
33 | // livetime. | ||
34 | type CertificateIdentityOption func(*STSCertificateIdentity) | ||
35 | |||
36 | // CertificateIdentityWithTransport returns a CertificateIdentityOption that | ||
37 | // customizes the STSCertificateIdentity with the given http.RoundTripper. | ||
38 | func CertificateIdentityWithTransport(t http.RoundTripper) CertificateIdentityOption { | ||
39 | return CertificateIdentityOption(func(i *STSCertificateIdentity) { i.Client.Transport = t }) | ||
40 | } | ||
41 | |||
42 | // CertificateIdentityWithExpiry returns a CertificateIdentityOption that | ||
43 | // customizes the STSCertificateIdentity with the given livetime. | ||
44 | // | ||
45 | // Fetched S3 credentials will have the given livetime if the STS server | ||
46 | // allows such credentials. | ||
47 | func CertificateIdentityWithExpiry(livetime time.Duration) CertificateIdentityOption { | ||
48 | return CertificateIdentityOption(func(i *STSCertificateIdentity) { i.S3CredentialLivetime = livetime }) | ||
49 | } | ||
50 | |||
51 | // A STSCertificateIdentity retrieves S3 credentials from the MinIO STS API and | ||
52 | // rotates those credentials once they expire. | ||
53 | type STSCertificateIdentity struct { | ||
54 | Expiry | ||
55 | |||
56 | // STSEndpoint is the base URL endpoint of the STS API. | ||
57 | // For example, https://minio.local:9000 | ||
58 | STSEndpoint string | ||
59 | |||
60 | // S3CredentialLivetime is the duration temp. S3 access | ||
61 | // credentials should be valid. | ||
62 | // | ||
63 | // It represents the access credential livetime requested | ||
64 | // by the client. The STS server may choose to issue | ||
65 | // temp. S3 credentials that have a different - usually | ||
66 | // shorter - livetime. | ||
67 | // | ||
68 | // The default livetime is one hour. | ||
69 | S3CredentialLivetime time.Duration | ||
70 | |||
71 | // Client is the HTTP client used to authenticate and fetch | ||
72 | // S3 credentials. | ||
73 | // | ||
74 | // A custom TLS client configuration can be specified by | ||
75 | // using a custom http.Transport: | ||
76 | // Client: http.Client { | ||
77 | // Transport: &http.Transport{ | ||
78 | // TLSClientConfig: &tls.Config{}, | ||
79 | // }, | ||
80 | // } | ||
81 | Client http.Client | ||
82 | } | ||
83 | |||
84 | var _ Provider = (*STSWebIdentity)(nil) // compiler check | ||
85 | |||
86 | // NewSTSCertificateIdentity returns a STSCertificateIdentity that authenticates | ||
87 | // to the given STS endpoint with the given TLS certificate and retrieves and | ||
88 | // rotates S3 credentials. | ||
89 | func NewSTSCertificateIdentity(endpoint string, certificate tls.Certificate, options ...CertificateIdentityOption) (*Credentials, error) { | ||
90 | if endpoint == "" { | ||
91 | return nil, errors.New("STS endpoint cannot be empty") | ||
92 | } | ||
93 | if _, err := url.Parse(endpoint); err != nil { | ||
94 | return nil, err | ||
95 | } | ||
96 | identity := &STSCertificateIdentity{ | ||
97 | STSEndpoint: endpoint, | ||
98 | Client: http.Client{ | ||
99 | Transport: &http.Transport{ | ||
100 | Proxy: http.ProxyFromEnvironment, | ||
101 | DialContext: (&net.Dialer{ | ||
102 | Timeout: 30 * time.Second, | ||
103 | KeepAlive: 30 * time.Second, | ||
104 | }).DialContext, | ||
105 | ForceAttemptHTTP2: true, | ||
106 | MaxIdleConns: 100, | ||
107 | IdleConnTimeout: 90 * time.Second, | ||
108 | TLSHandshakeTimeout: 10 * time.Second, | ||
109 | ExpectContinueTimeout: 5 * time.Second, | ||
110 | TLSClientConfig: &tls.Config{ | ||
111 | Certificates: []tls.Certificate{certificate}, | ||
112 | }, | ||
113 | }, | ||
114 | }, | ||
115 | } | ||
116 | for _, option := range options { | ||
117 | option(identity) | ||
118 | } | ||
119 | return New(identity), nil | ||
120 | } | ||
121 | |||
122 | // Retrieve fetches a new set of S3 credentials from the configured | ||
123 | // STS API endpoint. | ||
124 | func (i *STSCertificateIdentity) Retrieve() (Value, error) { | ||
125 | endpointURL, err := url.Parse(i.STSEndpoint) | ||
126 | if err != nil { | ||
127 | return Value{}, err | ||
128 | } | ||
129 | livetime := i.S3CredentialLivetime | ||
130 | if livetime == 0 { | ||
131 | livetime = 1 * time.Hour | ||
132 | } | ||
133 | |||
134 | queryValues := url.Values{} | ||
135 | queryValues.Set("Action", "AssumeRoleWithCertificate") | ||
136 | queryValues.Set("Version", STSVersion) | ||
137 | endpointURL.RawQuery = queryValues.Encode() | ||
138 | |||
139 | req, err := http.NewRequest(http.MethodPost, endpointURL.String(), nil) | ||
140 | if err != nil { | ||
141 | return Value{}, err | ||
142 | } | ||
143 | if req.Form == nil { | ||
144 | req.Form = url.Values{} | ||
145 | } | ||
146 | req.Form.Add("DurationSeconds", strconv.FormatUint(uint64(livetime.Seconds()), 10)) | ||
147 | |||
148 | resp, err := i.Client.Do(req) | ||
149 | if err != nil { | ||
150 | return Value{}, err | ||
151 | } | ||
152 | if resp.Body != nil { | ||
153 | defer resp.Body.Close() | ||
154 | } | ||
155 | if resp.StatusCode != http.StatusOK { | ||
156 | var errResp ErrorResponse | ||
157 | buf, err := io.ReadAll(resp.Body) | ||
158 | if err != nil { | ||
159 | return Value{}, err | ||
160 | } | ||
161 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
162 | if err != nil { | ||
163 | var s3Err Error | ||
164 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
165 | return Value{}, err | ||
166 | } | ||
167 | errResp.RequestID = s3Err.RequestID | ||
168 | errResp.STSError.Code = s3Err.Code | ||
169 | errResp.STSError.Message = s3Err.Message | ||
170 | } | ||
171 | return Value{}, errResp | ||
172 | } | ||
173 | |||
174 | const MaxSize = 10 * 1 << 20 | ||
175 | var body io.Reader = resp.Body | ||
176 | if resp.ContentLength > 0 && resp.ContentLength < MaxSize { | ||
177 | body = io.LimitReader(body, resp.ContentLength) | ||
178 | } else { | ||
179 | body = io.LimitReader(body, MaxSize) | ||
180 | } | ||
181 | |||
182 | var response assumeRoleWithCertificateResponse | ||
183 | if err = xml.NewDecoder(body).Decode(&response); err != nil { | ||
184 | return Value{}, err | ||
185 | } | ||
186 | i.SetExpiration(response.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
187 | return Value{ | ||
188 | AccessKeyID: response.Result.Credentials.AccessKey, | ||
189 | SecretAccessKey: response.Result.Credentials.SecretKey, | ||
190 | SessionToken: response.Result.Credentials.SessionToken, | ||
191 | SignerType: SignatureDefault, | ||
192 | }, nil | ||
193 | } | ||
194 | |||
195 | // Expiration returns the expiration time of the current S3 credentials. | ||
196 | func (i *STSCertificateIdentity) Expiration() time.Time { return i.expiration } | ||
197 | |||
198 | type assumeRoleWithCertificateResponse struct { | ||
199 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithCertificateResponse" json:"-"` | ||
200 | Result struct { | ||
201 | Credentials struct { | ||
202 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
203 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
204 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
205 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
206 | } `xml:"Credentials" json:"credentials,omitempty"` | ||
207 | } `xml:"AssumeRoleWithCertificateResult"` | ||
208 | ResponseMetadata struct { | ||
209 | RequestID string `xml:"RequestId,omitempty"` | ||
210 | } `xml:"ResponseMetadata,omitempty"` | ||
211 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_web_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_web_identity.go new file mode 100644 index 0000000..2e2af50 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_web_identity.go | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
3 | * Copyright 2019-2022 MinIO, Inc. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | */ | ||
17 | |||
18 | package credentials | ||
19 | |||
20 | import ( | ||
21 | "bytes" | ||
22 | "encoding/xml" | ||
23 | "errors" | ||
24 | "fmt" | ||
25 | "io" | ||
26 | "net/http" | ||
27 | "net/url" | ||
28 | "strconv" | ||
29 | "strings" | ||
30 | "time" | ||
31 | ) | ||
32 | |||
33 | // AssumeRoleWithWebIdentityResponse contains the result of successful AssumeRoleWithWebIdentity request. | ||
34 | type AssumeRoleWithWebIdentityResponse struct { | ||
35 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithWebIdentityResponse" json:"-"` | ||
36 | Result WebIdentityResult `xml:"AssumeRoleWithWebIdentityResult"` | ||
37 | ResponseMetadata struct { | ||
38 | RequestID string `xml:"RequestId,omitempty"` | ||
39 | } `xml:"ResponseMetadata,omitempty"` | ||
40 | } | ||
41 | |||
42 | // WebIdentityResult - Contains the response to a successful AssumeRoleWithWebIdentity | ||
43 | // request, including temporary credentials that can be used to make MinIO API requests. | ||
44 | type WebIdentityResult struct { | ||
45 | AssumedRoleUser AssumedRoleUser `xml:",omitempty"` | ||
46 | Audience string `xml:",omitempty"` | ||
47 | Credentials struct { | ||
48 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
49 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
50 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
51 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
52 | } `xml:",omitempty"` | ||
53 | PackedPolicySize int `xml:",omitempty"` | ||
54 | Provider string `xml:",omitempty"` | ||
55 | SubjectFromWebIdentityToken string `xml:",omitempty"` | ||
56 | } | ||
57 | |||
58 | // WebIdentityToken - web identity token with expiry. | ||
59 | type WebIdentityToken struct { | ||
60 | Token string | ||
61 | AccessToken string | ||
62 | Expiry int | ||
63 | } | ||
64 | |||
65 | // A STSWebIdentity retrieves credentials from MinIO service, and keeps track if | ||
66 | // those credentials are expired. | ||
67 | type STSWebIdentity struct { | ||
68 | Expiry | ||
69 | |||
70 | // Required http Client to use when connecting to MinIO STS service. | ||
71 | Client *http.Client | ||
72 | |||
73 | // Exported STS endpoint to fetch STS credentials. | ||
74 | STSEndpoint string | ||
75 | |||
76 | // Exported GetWebIDTokenExpiry function which returns ID | ||
77 | // tokens from IDP. This function should return two values | ||
78 | // one is ID token which is a self contained ID token (JWT) | ||
79 | // and second return value is the expiry associated with | ||
80 | // this token. | ||
81 | // This is a customer provided function and is mandatory. | ||
82 | GetWebIDTokenExpiry func() (*WebIdentityToken, error) | ||
83 | |||
84 | // RoleARN is the Amazon Resource Name (ARN) of the role that the caller is | ||
85 | // assuming. | ||
86 | RoleARN string | ||
87 | |||
88 | // roleSessionName is the identifier for the assumed role session. | ||
89 | roleSessionName string | ||
90 | } | ||
91 | |||
92 | // NewSTSWebIdentity returns a pointer to a new | ||
93 | // Credentials object wrapping the STSWebIdentity. | ||
94 | func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { | ||
95 | if stsEndpoint == "" { | ||
96 | return nil, errors.New("STS endpoint cannot be empty") | ||
97 | } | ||
98 | if getWebIDTokenExpiry == nil { | ||
99 | return nil, errors.New("Web ID token and expiry retrieval function should be defined") | ||
100 | } | ||
101 | return New(&STSWebIdentity{ | ||
102 | Client: &http.Client{ | ||
103 | Transport: http.DefaultTransport, | ||
104 | }, | ||
105 | STSEndpoint: stsEndpoint, | ||
106 | GetWebIDTokenExpiry: getWebIDTokenExpiry, | ||
107 | }), nil | ||
108 | } | ||
109 | |||
110 | func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, | ||
111 | getWebIDTokenExpiry func() (*WebIdentityToken, error), | ||
112 | ) (AssumeRoleWithWebIdentityResponse, error) { | ||
113 | idToken, err := getWebIDTokenExpiry() | ||
114 | if err != nil { | ||
115 | return AssumeRoleWithWebIdentityResponse{}, err | ||
116 | } | ||
117 | |||
118 | v := url.Values{} | ||
119 | v.Set("Action", "AssumeRoleWithWebIdentity") | ||
120 | if len(roleARN) > 0 { | ||
121 | v.Set("RoleArn", roleARN) | ||
122 | |||
123 | if len(roleSessionName) == 0 { | ||
124 | roleSessionName = strconv.FormatInt(time.Now().UnixNano(), 10) | ||
125 | } | ||
126 | v.Set("RoleSessionName", roleSessionName) | ||
127 | } | ||
128 | v.Set("WebIdentityToken", idToken.Token) | ||
129 | if idToken.AccessToken != "" { | ||
130 | // Usually set when server is using extended userInfo endpoint. | ||
131 | v.Set("WebIdentityAccessToken", idToken.AccessToken) | ||
132 | } | ||
133 | if idToken.Expiry > 0 { | ||
134 | v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry)) | ||
135 | } | ||
136 | v.Set("Version", STSVersion) | ||
137 | |||
138 | u, err := url.Parse(endpoint) | ||
139 | if err != nil { | ||
140 | return AssumeRoleWithWebIdentityResponse{}, err | ||
141 | } | ||
142 | |||
143 | req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(v.Encode())) | ||
144 | if err != nil { | ||
145 | return AssumeRoleWithWebIdentityResponse{}, err | ||
146 | } | ||
147 | |||
148 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
149 | |||
150 | resp, err := clnt.Do(req) | ||
151 | if err != nil { | ||
152 | return AssumeRoleWithWebIdentityResponse{}, err | ||
153 | } | ||
154 | |||
155 | defer resp.Body.Close() | ||
156 | if resp.StatusCode != http.StatusOK { | ||
157 | var errResp ErrorResponse | ||
158 | buf, err := io.ReadAll(resp.Body) | ||
159 | if err != nil { | ||
160 | return AssumeRoleWithWebIdentityResponse{}, err | ||
161 | } | ||
162 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
163 | if err != nil { | ||
164 | var s3Err Error | ||
165 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
166 | return AssumeRoleWithWebIdentityResponse{}, err | ||
167 | } | ||
168 | errResp.RequestID = s3Err.RequestID | ||
169 | errResp.STSError.Code = s3Err.Code | ||
170 | errResp.STSError.Message = s3Err.Message | ||
171 | } | ||
172 | return AssumeRoleWithWebIdentityResponse{}, errResp | ||
173 | } | ||
174 | |||
175 | a := AssumeRoleWithWebIdentityResponse{} | ||
176 | if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { | ||
177 | return AssumeRoleWithWebIdentityResponse{}, err | ||
178 | } | ||
179 | |||
180 | return a, nil | ||
181 | } | ||
182 | |||
183 | // Retrieve retrieves credentials from the MinIO service. | ||
184 | // Error will be returned if the request fails. | ||
185 | func (m *STSWebIdentity) Retrieve() (Value, error) { | ||
186 | a, err := getWebIdentityCredentials(m.Client, m.STSEndpoint, m.RoleARN, m.roleSessionName, m.GetWebIDTokenExpiry) | ||
187 | if err != nil { | ||
188 | return Value{}, err | ||
189 | } | ||
190 | |||
191 | // Expiry window is set to 10secs. | ||
192 | m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
193 | |||
194 | return Value{ | ||
195 | AccessKeyID: a.Result.Credentials.AccessKey, | ||
196 | SecretAccessKey: a.Result.Credentials.SecretKey, | ||
197 | SessionToken: a.Result.Credentials.SessionToken, | ||
198 | SignerType: SignatureV4, | ||
199 | }, nil | ||
200 | } | ||
201 | |||
202 | // Expiration returns the expiration time of the credentials | ||
203 | func (m *STSWebIdentity) Expiration() time.Time { | ||
204 | return m.expiration | ||
205 | } | ||