resolve_bearer_token.go raw

   1  package config
   2  
   3  import (
   4  	"context"
   5  	"fmt"
   6  	"time"
   7  
   8  	"github.com/aws/aws-sdk-go-v2/aws"
   9  	"github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
  10  	"github.com/aws/aws-sdk-go-v2/service/ssooidc"
  11  	smithybearer "github.com/aws/smithy-go/auth/bearer"
  12  )
  13  
  14  // resolveBearerAuthToken extracts a token provider from the config sources.
  15  //
  16  // If an explicit bearer authentication token provider is not found the
  17  // resolver will fallback to resolving token provider via other config sources
  18  // such as SharedConfig.
  19  func resolveBearerAuthToken(ctx context.Context, cfg *aws.Config, configs configs) error {
  20  	found, err := resolveBearerAuthTokenProvider(ctx, cfg, configs)
  21  	if found || err != nil {
  22  		return err
  23  	}
  24  
  25  	return resolveBearerAuthTokenProviderChain(ctx, cfg, configs)
  26  }
  27  
  28  // resolveBearerAuthTokenProvider extracts the first instance of
  29  // BearerAuthTokenProvider from the config sources.
  30  //
  31  // The resolved BearerAuthTokenProvider will be wrapped in a cache to ensure
  32  // the Token is only refreshed when needed. This also protects the
  33  // TokenProvider so it can be used concurrently.
  34  //
  35  // Config providers used:
  36  // * bearerAuthTokenProviderProvider
  37  func resolveBearerAuthTokenProvider(ctx context.Context, cfg *aws.Config, configs configs) (bool, error) {
  38  	tokenProvider, found, err := getBearerAuthTokenProvider(ctx, configs)
  39  	if !found || err != nil {
  40  		return false, err
  41  	}
  42  
  43  	cfg.BearerAuthTokenProvider, err = wrapWithBearerAuthTokenCache(
  44  		ctx, configs, tokenProvider)
  45  	if err != nil {
  46  		return false, err
  47  	}
  48  
  49  	return true, nil
  50  }
  51  
  52  func resolveBearerAuthTokenProviderChain(ctx context.Context, cfg *aws.Config, configs configs) (err error) {
  53  	_, sharedConfig, _ := getAWSConfigSources(configs)
  54  
  55  	var provider smithybearer.TokenProvider
  56  
  57  	if sharedConfig.SSOSession != nil {
  58  		provider, err = resolveBearerAuthSSOTokenProvider(
  59  			ctx, cfg, sharedConfig.SSOSession, configs)
  60  	}
  61  
  62  	if err == nil && provider != nil {
  63  		cfg.BearerAuthTokenProvider, err = wrapWithBearerAuthTokenCache(
  64  			ctx, configs, provider)
  65  	}
  66  
  67  	return err
  68  }
  69  
  70  func resolveBearerAuthSSOTokenProvider(ctx context.Context, cfg *aws.Config, session *SSOSession, configs configs) (*ssocreds.SSOTokenProvider, error) {
  71  	ssoTokenProviderOptionsFn, found, err := getSSOTokenProviderOptions(ctx, configs)
  72  	if err != nil {
  73  		return nil, fmt.Errorf("failed to get SSOTokenProviderOptions from config sources, %w", err)
  74  	}
  75  
  76  	var optFns []func(*ssocreds.SSOTokenProviderOptions)
  77  	if found {
  78  		optFns = append(optFns, ssoTokenProviderOptionsFn)
  79  	}
  80  
  81  	cachePath, err := ssocreds.StandardCachedTokenFilepath(session.Name)
  82  	if err != nil {
  83  		return nil, fmt.Errorf("failed to get SSOTokenProvider's cache path, %w", err)
  84  	}
  85  
  86  	client := ssooidc.NewFromConfig(*cfg)
  87  	provider := ssocreds.NewSSOTokenProvider(client, cachePath, optFns...)
  88  
  89  	return provider, nil
  90  }
  91  
  92  // wrapWithBearerAuthTokenCache will wrap provider with an smithy-go
  93  // bearer/auth#TokenCache with the provided options if the provider is not
  94  // already a TokenCache.
  95  func wrapWithBearerAuthTokenCache(
  96  	ctx context.Context,
  97  	cfgs configs,
  98  	provider smithybearer.TokenProvider,
  99  	optFns ...func(*smithybearer.TokenCacheOptions),
 100  ) (smithybearer.TokenProvider, error) {
 101  	_, ok := provider.(*smithybearer.TokenCache)
 102  	if ok {
 103  		return provider, nil
 104  	}
 105  
 106  	tokenCacheConfigOptions, optionsFound, err := getBearerAuthTokenCacheOptions(ctx, cfgs)
 107  	if err != nil {
 108  		return nil, err
 109  	}
 110  
 111  	opts := make([]func(*smithybearer.TokenCacheOptions), 0, 2+len(optFns))
 112  	opts = append(opts, func(o *smithybearer.TokenCacheOptions) {
 113  		o.RefreshBeforeExpires = 5 * time.Minute
 114  		o.RetrieveBearerTokenTimeout = 30 * time.Second
 115  	})
 116  	opts = append(opts, optFns...)
 117  	if optionsFound {
 118  		opts = append(opts, tokenCacheConfigOptions)
 119  	}
 120  
 121  	return smithybearer.NewTokenCache(provider, opts...), nil
 122  }
 123