client.go (4707B)
1 package client 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "time" 8 9 "github.com/aws/aws-sdk-go-v2/aws" 10 "github.com/aws/aws-sdk-go-v2/aws/middleware" 11 "github.com/aws/aws-sdk-go-v2/aws/retry" 12 awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" 13 "github.com/aws/smithy-go" 14 smithymiddleware "github.com/aws/smithy-go/middleware" 15 smithyhttp "github.com/aws/smithy-go/transport/http" 16 ) 17 18 // ServiceID is the client identifer 19 const ServiceID = "endpoint-credentials" 20 21 // HTTPClient is a client for sending HTTP requests 22 type HTTPClient interface { 23 Do(*http.Request) (*http.Response, error) 24 } 25 26 // Options is the endpoint client configurable options 27 type Options struct { 28 // The endpoint to retrieve credentials from 29 Endpoint string 30 31 // The HTTP client to invoke API calls with. Defaults to client's default HTTP 32 // implementation if nil. 33 HTTPClient HTTPClient 34 35 // Retryer guides how HTTP requests should be retried in case of recoverable 36 // failures. When nil the API client will use a default retryer. 37 Retryer aws.Retryer 38 39 // Set of options to modify how the credentials operation is invoked. 40 APIOptions []func(*smithymiddleware.Stack) error 41 } 42 43 // Copy creates a copy of the API options. 44 func (o Options) Copy() Options { 45 to := o 46 to.APIOptions = make([]func(*smithymiddleware.Stack) error, len(o.APIOptions)) 47 copy(to.APIOptions, o.APIOptions) 48 return to 49 } 50 51 // Client is an client for retrieving AWS credentials from an endpoint 52 type Client struct { 53 options Options 54 } 55 56 // New constructs a new Client from the given options 57 func New(options Options, optFns ...func(*Options)) *Client { 58 options = options.Copy() 59 60 if options.HTTPClient == nil { 61 options.HTTPClient = awshttp.NewBuildableClient() 62 } 63 64 if options.Retryer == nil { 65 // Amazon-owned implementations of this endpoint are known to sometimes 66 // return plaintext responses (i.e. no Code) like normal, add a few 67 // additional status codes 68 options.Retryer = retry.NewStandard(func(o *retry.StandardOptions) { 69 o.Retryables = append(o.Retryables, retry.RetryableHTTPStatusCode{ 70 Codes: map[int]struct{}{ 71 http.StatusTooManyRequests: {}, 72 }, 73 }) 74 }) 75 } 76 77 for _, fn := range optFns { 78 fn(&options) 79 } 80 81 client := &Client{ 82 options: options, 83 } 84 85 return client 86 } 87 88 // GetCredentialsInput is the input to send with the endpoint service to receive credentials. 89 type GetCredentialsInput struct { 90 AuthorizationToken string 91 } 92 93 // GetCredentials retrieves credentials from credential endpoint 94 func (c *Client) GetCredentials(ctx context.Context, params *GetCredentialsInput, optFns ...func(*Options)) (*GetCredentialsOutput, error) { 95 stack := smithymiddleware.NewStack("GetCredentials", smithyhttp.NewStackRequest) 96 options := c.options.Copy() 97 for _, fn := range optFns { 98 fn(&options) 99 } 100 101 stack.Serialize.Add(&serializeOpGetCredential{}, smithymiddleware.After) 102 stack.Build.Add(&buildEndpoint{Endpoint: options.Endpoint}, smithymiddleware.After) 103 stack.Deserialize.Add(&deserializeOpGetCredential{}, smithymiddleware.After) 104 addProtocolFinalizerMiddlewares(stack, options, "GetCredentials") 105 retry.AddRetryMiddlewares(stack, retry.AddRetryMiddlewaresOptions{Retryer: options.Retryer}) 106 middleware.AddSDKAgentKey(middleware.FeatureMetadata, ServiceID) 107 108 for _, fn := range options.APIOptions { 109 if err := fn(stack); err != nil { 110 return nil, err 111 } 112 } 113 114 handler := smithymiddleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack) 115 result, _, err := handler.Handle(ctx, params) 116 if err != nil { 117 return nil, err 118 } 119 120 return result.(*GetCredentialsOutput), err 121 } 122 123 // GetCredentialsOutput is the response from the credential endpoint 124 type GetCredentialsOutput struct { 125 Expiration *time.Time 126 AccessKeyID string 127 SecretAccessKey string 128 Token string 129 AccountID string 130 } 131 132 // EndpointError is an error returned from the endpoint service 133 type EndpointError struct { 134 Code string `json:"code"` 135 Message string `json:"message"` 136 Fault smithy.ErrorFault `json:"-"` 137 statusCode int `json:"-"` 138 } 139 140 // Error is the error mesage string 141 func (e *EndpointError) Error() string { 142 return fmt.Sprintf("%s: %s", e.Code, e.Message) 143 } 144 145 // ErrorCode is the error code returned by the endpoint 146 func (e *EndpointError) ErrorCode() string { 147 return e.Code 148 } 149 150 // ErrorMessage is the error message returned by the endpoint 151 func (e *EndpointError) ErrorMessage() string { 152 return e.Message 153 } 154 155 // ErrorFault indicates error fault classification 156 func (e *EndpointError) ErrorFault() smithy.ErrorFault { 157 return e.Fault 158 } 159 160 // HTTPStatusCode implements retry.HTTPStatusCode. 161 func (e *EndpointError) HTTPStatusCode() int { 162 return e.statusCode 163 }