...

Source file src/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go

Documentation: github.com/aws/aws-sdk-go-v2/credentials/endpointcreds

     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  //	{
    12  //	    "AccessKeyId" : "MUA...",
    13  //	    "SecretAccessKey" : "/7PC5om....",
    14  //	}
    15  //
    16  // Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
    17  // value in the response. The format of the refreshable credentials response:
    18  //
    19  //	{
    20  //	    "AccessKeyId" : "MUA...",
    21  //	    "SecretAccessKey" : "/7PC5om....",
    22  //	    "Token" : "AQoDY....=",
    23  //	    "Expiration" : "2016-02-25T06:03:31Z"
    24  //	}
    25  //
    26  // Errors should be returned in the following format and only returned with 400
    27  // or 500 HTTP status codes.
    28  //
    29  //	{
    30  //	    "code": "ErrorCode",
    31  //	    "message": "Helpful error message."
    32  //	}
    33  package endpointcreds
    34  
    35  import (
    36  	"context"
    37  	"fmt"
    38  	"net/http"
    39  	"strings"
    40  
    41  	"github.com/aws/aws-sdk-go-v2/aws"
    42  	"github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client"
    43  	"github.com/aws/smithy-go/middleware"
    44  )
    45  
    46  // ProviderName is the name of the credentials provider.
    47  const ProviderName = `CredentialsEndpointProvider`
    48  
    49  type getCredentialsAPIClient interface {
    50  	GetCredentials(context.Context, *client.GetCredentialsInput, ...func(*client.Options)) (*client.GetCredentialsOutput, error)
    51  }
    52  
    53  // Provider satisfies the aws.CredentialsProvider interface, and is a client to
    54  // retrieve credentials from an arbitrary endpoint.
    55  type Provider struct {
    56  	// The AWS Client to make HTTP requests to the endpoint with. The endpoint
    57  	// the request will be made to is provided by the aws.Config's
    58  	// EndpointResolver.
    59  	client getCredentialsAPIClient
    60  
    61  	options Options
    62  }
    63  
    64  // HTTPClient is a client for sending HTTP requests
    65  type HTTPClient interface {
    66  	Do(*http.Request) (*http.Response, error)
    67  }
    68  
    69  // Options is structure of configurable options for Provider
    70  type Options struct {
    71  	// Endpoint to retrieve credentials from. Required
    72  	Endpoint string
    73  
    74  	// HTTPClient to handle sending HTTP requests to the target endpoint.
    75  	HTTPClient HTTPClient
    76  
    77  	// Set of options to modify how the credentials operation is invoked.
    78  	APIOptions []func(*middleware.Stack) error
    79  
    80  	// The Retryer to be used for determining whether a failed requested should be retried
    81  	Retryer aws.Retryer
    82  
    83  	// Optional authorization token value if set will be used as the value of
    84  	// the Authorization header of the endpoint credential request.
    85  	//
    86  	// When constructed from environment, the provider will use the value of
    87  	// AWS_CONTAINER_AUTHORIZATION_TOKEN environment variable as the token
    88  	//
    89  	// Will be overridden if AuthorizationTokenProvider is configured
    90  	AuthorizationToken string
    91  
    92  	// Optional auth provider func to dynamically load the auth token from a file
    93  	// everytime a credential is retrieved
    94  	//
    95  	// When constructed from environment, the provider will read and use the content
    96  	// of the file pointed to by AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE environment variable
    97  	// as the auth token everytime credentials are retrieved
    98  	//
    99  	// Will override AuthorizationToken if configured
   100  	AuthorizationTokenProvider AuthTokenProvider
   101  }
   102  
   103  // AuthTokenProvider defines an interface to dynamically load a value to be passed
   104  // for the Authorization header of a credentials request.
   105  type AuthTokenProvider interface {
   106  	GetToken() (string, error)
   107  }
   108  
   109  // TokenProviderFunc is a func type implementing AuthTokenProvider interface
   110  // and enables customizing token provider behavior
   111  type TokenProviderFunc func() (string, error)
   112  
   113  // GetToken func retrieves auth token according to TokenProviderFunc implementation
   114  func (p TokenProviderFunc) GetToken() (string, error) {
   115  	return p()
   116  }
   117  
   118  // New returns a credentials Provider for retrieving AWS credentials
   119  // from arbitrary endpoint.
   120  func New(endpoint string, optFns ...func(*Options)) *Provider {
   121  	o := Options{
   122  		Endpoint: endpoint,
   123  	}
   124  
   125  	for _, fn := range optFns {
   126  		fn(&o)
   127  	}
   128  
   129  	p := &Provider{
   130  		client: client.New(client.Options{
   131  			HTTPClient: o.HTTPClient,
   132  			Endpoint:   o.Endpoint,
   133  			APIOptions: o.APIOptions,
   134  			Retryer:    o.Retryer,
   135  		}),
   136  		options: o,
   137  	}
   138  
   139  	return p
   140  }
   141  
   142  // Retrieve will attempt to request the credentials from the endpoint the Provider
   143  // was configured for. And error will be returned if the retrieval fails.
   144  func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
   145  	resp, err := p.getCredentials(ctx)
   146  	if err != nil {
   147  		return aws.Credentials{}, fmt.Errorf("failed to load credentials, %w", err)
   148  	}
   149  
   150  	creds := aws.Credentials{
   151  		AccessKeyID:     resp.AccessKeyID,
   152  		SecretAccessKey: resp.SecretAccessKey,
   153  		SessionToken:    resp.Token,
   154  		Source:          ProviderName,
   155  	}
   156  
   157  	if resp.Expiration != nil {
   158  		creds.CanExpire = true
   159  		creds.Expires = *resp.Expiration
   160  	}
   161  
   162  	return creds, nil
   163  }
   164  
   165  func (p *Provider) getCredentials(ctx context.Context) (*client.GetCredentialsOutput, error) {
   166  	authToken, err := p.resolveAuthToken()
   167  	if err != nil {
   168  		return nil, fmt.Errorf("resolve auth token: %v", err)
   169  	}
   170  
   171  	return p.client.GetCredentials(ctx, &client.GetCredentialsInput{
   172  		AuthorizationToken: authToken,
   173  	})
   174  }
   175  
   176  func (p *Provider) resolveAuthToken() (string, error) {
   177  	authToken := p.options.AuthorizationToken
   178  
   179  	var err error
   180  	if p.options.AuthorizationTokenProvider != nil {
   181  		authToken, err = p.options.AuthorizationTokenProvider.GetToken()
   182  		if err != nil {
   183  			return "", err
   184  		}
   185  	}
   186  
   187  	if strings.ContainsAny(authToken, "\r\n") {
   188  		return "", fmt.Errorf("authorization token contains invalid newline sequence")
   189  	}
   190  
   191  	return authToken, nil
   192  }
   193  

View as plain text