]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / credentials / endpointcreds / provider.go
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 // }
30 package endpointcreds
31
32 import (
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"
42 )
43
44 // ProviderName is the name of the credentials provider.
45 const ProviderName = `CredentialsEndpointProvider`
46
47 // Provider satisfies the credentials.Provider interface, and is a client to
48 // retrieve credentials from an arbitrary endpoint.
49 type Provider struct {
50 staticCreds bool
51 credentials.Expiry
52
53 // Requires a AWS Client to make HTTP requests to the endpoint with.
54 // the Endpoint the request will be made to is provided by the aws.Config's
55 // Endpoint value.
56 Client *client.Client
57
58 // ExpiryWindow will allow the credentials to trigger refreshing prior to
59 // the credentials actually expiring. This is beneficial so race conditions
60 // with expiring credentials do not cause request to fail unexpectedly
61 // due to ExpiredTokenException exceptions.
62 //
63 // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
64 // 10 seconds before the credentials are actually expired.
65 //
66 // If ExpiryWindow is 0 or less it will be ignored.
67 ExpiryWindow time.Duration
68
69 // Optional authorization token value if set will be used as the value of
70 // the Authorization header of the endpoint credential request.
71 AuthorizationToken string
72 }
73
74 // NewProviderClient returns a credentials Provider for retrieving AWS credentials
75 // from arbitrary endpoint.
76 func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider {
77 p := &Provider{
78 Client: client.New(
79 cfg,
80 metadata.ClientInfo{
81 ServiceName: "CredentialsEndpoint",
82 Endpoint: endpoint,
83 },
84 handlers,
85 ),
86 }
87
88 p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler)
89 p.Client.Handlers.UnmarshalError.PushBack(unmarshalError)
90 p.Client.Handlers.Validate.Clear()
91 p.Client.Handlers.Validate.PushBack(validateEndpointHandler)
92
93 for _, option := range options {
94 option(p)
95 }
96
97 return p
98 }
99
100 // NewCredentialsClient returns a Credentials wrapper for retrieving credentials
101 // from an arbitrary endpoint concurrently. The client will request the
102 func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials {
103 return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...))
104 }
105
106 // IsExpired returns true if the credentials retrieved are expired, or not yet
107 // retrieved.
108 func (p *Provider) IsExpired() bool {
109 if p.staticCreds {
110 return false
111 }
112 return p.Expiry.IsExpired()
113 }
114
115 // Retrieve will attempt to request the credentials from the endpoint the Provider
116 // was configured for. And error will be returned if the retrieval fails.
117 func (p *Provider) Retrieve() (credentials.Value, error) {
118 resp, err := p.getCredentials()
119 if err != nil {
120 return credentials.Value{ProviderName: ProviderName},
121 awserr.New("CredentialsEndpointError", "failed to load credentials", err)
122 }
123
124 if resp.Expiration != nil {
125 p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
126 } else {
127 p.staticCreds = true
128 }
129
130 return credentials.Value{
131 AccessKeyID: resp.AccessKeyID,
132 SecretAccessKey: resp.SecretAccessKey,
133 SessionToken: resp.Token,
134 ProviderName: ProviderName,
135 }, nil
136 }
137
138 type getCredentialsOutput struct {
139 Expiration *time.Time
140 AccessKeyID string
141 SecretAccessKey string
142 Token string
143 }
144
145 type errorOutput struct {
146 Code string `json:"code"`
147 Message string `json:"message"`
148 }
149
150 func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
151 op := &request.Operation{
152 Name: "GetCredentials",
153 HTTPMethod: "GET",
154 }
155
156 out := &getCredentialsOutput{}
157 req := p.Client.NewRequest(op, nil, out)
158 req.HTTPRequest.Header.Set("Accept", "application/json")
159 if authToken := p.AuthorizationToken; len(authToken) != 0 {
160 req.HTTPRequest.Header.Set("Authorization", authToken)
161 }
162
163 return out, req.Send()
164 }
165
166 func validateEndpointHandler(r *request.Request) {
167 if len(r.ClientInfo.Endpoint) == 0 {
168 r.Error = aws.ErrMissingEndpoint
169 }
170 }
171
172 func unmarshalHandler(r *request.Request) {
173 defer r.HTTPResponse.Body.Close()
174
175 out := r.Data.(*getCredentialsOutput)
176 if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
177 r.Error = awserr.New("SerializationError",
178 "failed to decode endpoint credentials",
179 err,
180 )
181 }
182 }
183
184 func unmarshalError(r *request.Request) {
185 defer r.HTTPResponse.Body.Close()
186
187 var errOut errorOutput
188 if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil {
189 r.Error = awserr.New("SerializationError",
190 "failed to decode endpoint credentials",
191 err,
192 )
193 }
194
195 // Response body format is not consistent between metadata endpoints.
196 // Grab the error message as a string and include that as the source error
197 r.Error = awserr.New(errOut.Code, errOut.Message, nil)
198 }