resolve_bearer_token.go (4175B)
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 || (sharedConfig.SSORegion != "" && sharedConfig.SSOStartURL != "") { 58 ssoSession := sharedConfig.SSOSession 59 if ssoSession == nil { 60 // Fallback to legacy SSO session config parameters, if the 61 // sso-session section wasn't used. 62 ssoSession = &SSOSession{ 63 Name: sharedConfig.SSOStartURL, 64 SSORegion: sharedConfig.SSORegion, 65 SSOStartURL: sharedConfig.SSOStartURL, 66 } 67 } 68 69 provider, err = resolveBearerAuthSSOTokenProvider( 70 ctx, cfg, ssoSession, configs) 71 } 72 73 if err == nil && provider != nil { 74 cfg.BearerAuthTokenProvider, err = wrapWithBearerAuthTokenCache( 75 ctx, configs, provider) 76 } 77 78 return err 79 } 80 81 func resolveBearerAuthSSOTokenProvider(ctx context.Context, cfg *aws.Config, session *SSOSession, configs configs) (*ssocreds.SSOTokenProvider, error) { 82 ssoTokenProviderOptionsFn, found, err := getSSOTokenProviderOptions(ctx, configs) 83 if err != nil { 84 return nil, fmt.Errorf("failed to get SSOTokenProviderOptions from config sources, %w", err) 85 } 86 87 var optFns []func(*ssocreds.SSOTokenProviderOptions) 88 if found { 89 optFns = append(optFns, ssoTokenProviderOptionsFn) 90 } 91 92 cachePath, err := ssocreds.StandardCachedTokenFilepath(session.Name) 93 if err != nil { 94 return nil, fmt.Errorf("failed to get SSOTokenProvider's cache path, %w", err) 95 } 96 97 client := ssooidc.NewFromConfig(*cfg) 98 provider := ssocreds.NewSSOTokenProvider(client, cachePath, optFns...) 99 100 return provider, nil 101 } 102 103 // wrapWithBearerAuthTokenCache will wrap provider with an smithy-go 104 // bearer/auth#TokenCache with the provided options if the provider is not 105 // already a TokenCache. 106 func wrapWithBearerAuthTokenCache( 107 ctx context.Context, 108 cfgs configs, 109 provider smithybearer.TokenProvider, 110 optFns ...func(*smithybearer.TokenCacheOptions), 111 ) (smithybearer.TokenProvider, error) { 112 _, ok := provider.(*smithybearer.TokenCache) 113 if ok { 114 return provider, nil 115 } 116 117 tokenCacheConfigOptions, optionsFound, err := getBearerAuthTokenCacheOptions(ctx, cfgs) 118 if err != nil { 119 return nil, err 120 } 121 122 opts := make([]func(*smithybearer.TokenCacheOptions), 0, 2+len(optFns)) 123 opts = append(opts, func(o *smithybearer.TokenCacheOptions) { 124 o.RefreshBeforeExpires = 5 * time.Minute 125 o.RetrieveBearerTokenTimeout = 30 * time.Second 126 }) 127 opts = append(opts, optFns...) 128 if optionsFound { 129 opts = append(opts, tokenCacheConfigOptions) 130 } 131 132 return smithybearer.NewTokenCache(provider, opts...), nil 133 }