code.dwrz.net

Go monorepo.
Log | Files | Refs

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 }