resolve_bearer_token.go

  1package config
  2
  3import (
  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.
 19func 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
 37func 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
 52func 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
 70func 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.
 95func 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}