...

Source file src/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go

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

     1  package ssocreds
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/aws/aws-sdk-go-v2/aws"
     8  	"github.com/aws/aws-sdk-go-v2/internal/sdk"
     9  	"github.com/aws/aws-sdk-go-v2/service/sso"
    10  )
    11  
    12  // ProviderName is the name of the provider used to specify the source of
    13  // credentials.
    14  const ProviderName = "SSOProvider"
    15  
    16  // GetRoleCredentialsAPIClient is a API client that implements the
    17  // GetRoleCredentials operation.
    18  type GetRoleCredentialsAPIClient interface {
    19  	GetRoleCredentials(context.Context, *sso.GetRoleCredentialsInput, ...func(*sso.Options)) (
    20  		*sso.GetRoleCredentialsOutput, error,
    21  	)
    22  }
    23  
    24  // Options is the Provider options structure.
    25  type Options struct {
    26  	// The Client which is configured for the AWS Region where the AWS SSO user
    27  	// portal is located.
    28  	Client GetRoleCredentialsAPIClient
    29  
    30  	// The AWS account that is assigned to the user.
    31  	AccountID string
    32  
    33  	// The role name that is assigned to the user.
    34  	RoleName string
    35  
    36  	// The URL that points to the organization's AWS Single Sign-On (AWS SSO)
    37  	// user portal.
    38  	StartURL string
    39  
    40  	// The filepath the cached token will be retrieved from. If unset Provider will
    41  	// use the startURL to determine the filepath at.
    42  	//
    43  	//    ~/.aws/sso/cache/<sha1-hex-encoded-startURL>.json
    44  	//
    45  	// If custom cached token filepath is used, the Provider's startUrl
    46  	// parameter will be ignored.
    47  	CachedTokenFilepath string
    48  
    49  	// Used by the SSOCredentialProvider if a token configuration
    50  	// profile is used in the shared config
    51  	SSOTokenProvider *SSOTokenProvider
    52  }
    53  
    54  // Provider is an AWS credential provider that retrieves temporary AWS
    55  // credentials by exchanging an SSO login token.
    56  type Provider struct {
    57  	options Options
    58  
    59  	cachedTokenFilepath string
    60  }
    61  
    62  // New returns a new AWS Single Sign-On (AWS SSO) credential provider. The
    63  // provided client is expected to be configured for the AWS Region where the
    64  // AWS SSO user portal is located.
    65  func New(client GetRoleCredentialsAPIClient, accountID, roleName, startURL string, optFns ...func(options *Options)) *Provider {
    66  	options := Options{
    67  		Client:    client,
    68  		AccountID: accountID,
    69  		RoleName:  roleName,
    70  		StartURL:  startURL,
    71  	}
    72  
    73  	for _, fn := range optFns {
    74  		fn(&options)
    75  	}
    76  
    77  	return &Provider{
    78  		options:             options,
    79  		cachedTokenFilepath: options.CachedTokenFilepath,
    80  	}
    81  }
    82  
    83  // Retrieve retrieves temporary AWS credentials from the configured Amazon
    84  // Single Sign-On (AWS SSO) user portal by exchanging the accessToken present
    85  // in ~/.aws/sso/cache. However, if a token provider configuration exists
    86  // in the shared config, then we ought to use the token provider rather then
    87  // direct access on the cached token.
    88  func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
    89  	var accessToken *string
    90  	if p.options.SSOTokenProvider != nil {
    91  		token, err := p.options.SSOTokenProvider.RetrieveBearerToken(ctx)
    92  		if err != nil {
    93  			return aws.Credentials{}, err
    94  		}
    95  		accessToken = &token.Value
    96  	} else {
    97  		if p.cachedTokenFilepath == "" {
    98  			cachedTokenFilepath, err := StandardCachedTokenFilepath(p.options.StartURL)
    99  			if err != nil {
   100  				return aws.Credentials{}, &InvalidTokenError{Err: err}
   101  			}
   102  			p.cachedTokenFilepath = cachedTokenFilepath
   103  		}
   104  
   105  		tokenFile, err := loadCachedToken(p.cachedTokenFilepath)
   106  		if err != nil {
   107  			return aws.Credentials{}, &InvalidTokenError{Err: err}
   108  		}
   109  
   110  		if tokenFile.ExpiresAt == nil || sdk.NowTime().After(time.Time(*tokenFile.ExpiresAt)) {
   111  			return aws.Credentials{}, &InvalidTokenError{}
   112  		}
   113  		accessToken = &tokenFile.AccessToken
   114  	}
   115  
   116  	output, err := p.options.Client.GetRoleCredentials(ctx, &sso.GetRoleCredentialsInput{
   117  		AccessToken: accessToken,
   118  		AccountId:   &p.options.AccountID,
   119  		RoleName:    &p.options.RoleName,
   120  	})
   121  	if err != nil {
   122  		return aws.Credentials{}, err
   123  	}
   124  
   125  	return aws.Credentials{
   126  		AccessKeyID:     aws.ToString(output.RoleCredentials.AccessKeyId),
   127  		SecretAccessKey: aws.ToString(output.RoleCredentials.SecretAccessKey),
   128  		SessionToken:    aws.ToString(output.RoleCredentials.SessionToken),
   129  		CanExpire:       true,
   130  		Expires:         time.Unix(0, output.RoleCredentials.Expiration*int64(time.Millisecond)).UTC(),
   131  		Source:          ProviderName,
   132  	}, nil
   133  }
   134  
   135  // InvalidTokenError is the error type that is returned if loaded token has
   136  // expired or is otherwise invalid. To refresh the SSO session run AWS SSO
   137  // login with the corresponding profile.
   138  type InvalidTokenError struct {
   139  	Err error
   140  }
   141  
   142  func (i *InvalidTokenError) Unwrap() error {
   143  	return i.Err
   144  }
   145  
   146  func (i *InvalidTokenError) Error() string {
   147  	const msg = "the SSO session has expired or is invalid"
   148  	if i.Err == nil {
   149  		return msg
   150  	}
   151  	return msg + ": " + i.Err.Error()
   152  }
   153  

View as plain text