]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / credentials / endpointcreds / provider.go
CommitLineData
bae9f6d2
JC
1// Package endpointcreds provides support for retrieving credentials from an
2// arbitrary HTTP endpoint.
3//
4// The credentials endpoint Provider can receive both static and refreshable
5// credentials that will expire. Credentials are static when an "Expiration"
6// value is not provided in the endpoint's response.
7//
8// Static credentials will never expire once they have been retrieved. The format
9// of the static credentials response:
10// {
11// "AccessKeyId" : "MUA...",
12// "SecretAccessKey" : "/7PC5om....",
13// }
14//
15// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
16// value in the response. The format of the refreshable credentials response:
17// {
18// "AccessKeyId" : "MUA...",
19// "SecretAccessKey" : "/7PC5om....",
20// "Token" : "AQoDY....=",
21// "Expiration" : "2016-02-25T06:03:31Z"
22// }
23//
24// Errors should be returned in the following format and only returned with 400
25// or 500 HTTP status codes.
26// {
27// "code": "ErrorCode",
28// "message": "Helpful error message."
29// }
30package endpointcreds
31
32import (
33 "encoding/json"
34 "time"
35
36 "github.com/aws/aws-sdk-go/aws"
37 "github.com/aws/aws-sdk-go/aws/awserr"
38 "github.com/aws/aws-sdk-go/aws/client"
39 "github.com/aws/aws-sdk-go/aws/client/metadata"
40 "github.com/aws/aws-sdk-go/aws/credentials"
41 "github.com/aws/aws-sdk-go/aws/request"
863486a6 42 "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
bae9f6d2
JC
43)
44
45// ProviderName is the name of the credentials provider.
46const ProviderName = `CredentialsEndpointProvider`
47
48// Provider satisfies the credentials.Provider interface, and is a client to
49// retrieve credentials from an arbitrary endpoint.
50type Provider struct {
51 staticCreds bool
52 credentials.Expiry
53
54 // Requires a AWS Client to make HTTP requests to the endpoint with.
55 // the Endpoint the request will be made to is provided by the aws.Config's
56 // Endpoint value.
57 Client *client.Client
58
59 // ExpiryWindow will allow the credentials to trigger refreshing prior to
60 // the credentials actually expiring. This is beneficial so race conditions
61 // with expiring credentials do not cause request to fail unexpectedly
62 // due to ExpiredTokenException exceptions.
63 //
64 // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
65 // 10 seconds before the credentials are actually expired.
66 //
67 // If ExpiryWindow is 0 or less it will be ignored.
68 ExpiryWindow time.Duration
107c1cdb
ND
69
70 // Optional authorization token value if set will be used as the value of
71 // the Authorization header of the endpoint credential request.
72 AuthorizationToken string
bae9f6d2
JC
73}
74
75// NewProviderClient returns a credentials Provider for retrieving AWS credentials
76// from arbitrary endpoint.
77func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider {
78 p := &Provider{
79 Client: client.New(
80 cfg,
81 metadata.ClientInfo{
82 ServiceName: "CredentialsEndpoint",
83 Endpoint: endpoint,
84 },
85 handlers,
86 ),
87 }
88
89 p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler)
90 p.Client.Handlers.UnmarshalError.PushBack(unmarshalError)
91 p.Client.Handlers.Validate.Clear()
92 p.Client.Handlers.Validate.PushBack(validateEndpointHandler)
93
94 for _, option := range options {
95 option(p)
96 }
97
98 return p
99}
100
101// NewCredentialsClient returns a Credentials wrapper for retrieving credentials
102// from an arbitrary endpoint concurrently. The client will request the
103func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials {
104 return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...))
105}
106
107// IsExpired returns true if the credentials retrieved are expired, or not yet
108// retrieved.
109func (p *Provider) IsExpired() bool {
110 if p.staticCreds {
111 return false
112 }
113 return p.Expiry.IsExpired()
114}
115
116// Retrieve will attempt to request the credentials from the endpoint the Provider
117// was configured for. And error will be returned if the retrieval fails.
118func (p *Provider) Retrieve() (credentials.Value, error) {
119 resp, err := p.getCredentials()
120 if err != nil {
121 return credentials.Value{ProviderName: ProviderName},
122 awserr.New("CredentialsEndpointError", "failed to load credentials", err)
123 }
124
125 if resp.Expiration != nil {
126 p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
127 } else {
128 p.staticCreds = true
129 }
130
131 return credentials.Value{
132 AccessKeyID: resp.AccessKeyID,
133 SecretAccessKey: resp.SecretAccessKey,
134 SessionToken: resp.Token,
135 ProviderName: ProviderName,
136 }, nil
137}
138
139type getCredentialsOutput struct {
140 Expiration *time.Time
141 AccessKeyID string
142 SecretAccessKey string
143 Token string
144}
145
146type errorOutput struct {
147 Code string `json:"code"`
148 Message string `json:"message"`
149}
150
151func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
152 op := &request.Operation{
153 Name: "GetCredentials",
154 HTTPMethod: "GET",
155 }
156
157 out := &getCredentialsOutput{}
158 req := p.Client.NewRequest(op, nil, out)
159 req.HTTPRequest.Header.Set("Accept", "application/json")
107c1cdb
ND
160 if authToken := p.AuthorizationToken; len(authToken) != 0 {
161 req.HTTPRequest.Header.Set("Authorization", authToken)
162 }
bae9f6d2
JC
163
164 return out, req.Send()
165}
166
167func validateEndpointHandler(r *request.Request) {
168 if len(r.ClientInfo.Endpoint) == 0 {
169 r.Error = aws.ErrMissingEndpoint
170 }
171}
172
173func unmarshalHandler(r *request.Request) {
174 defer r.HTTPResponse.Body.Close()
175
176 out := r.Data.(*getCredentialsOutput)
177 if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
863486a6 178 r.Error = awserr.New(request.ErrCodeSerialization,
bae9f6d2
JC
179 "failed to decode endpoint credentials",
180 err,
181 )
182 }
183}
184
185func unmarshalError(r *request.Request) {
186 defer r.HTTPResponse.Body.Close()
187
188 var errOut errorOutput
863486a6
AG
189 err := jsonutil.UnmarshalJSONError(&errOut, r.HTTPResponse.Body)
190 if err != nil {
191 r.Error = awserr.NewRequestFailure(
192 awserr.New(request.ErrCodeSerialization,
193 "failed to decode error message", err),
194 r.HTTPResponse.StatusCode,
195 r.RequestID,
bae9f6d2 196 )
863486a6 197 return
bae9f6d2
JC
198 }
199
200 // Response body format is not consistent between metadata endpoints.
201 // Grab the error message as a string and include that as the source error
202 r.Error = awserr.New(errOut.Code, errOut.Message, nil)
203}