package s3 import ( "context" "fmt" "github.com/aws/aws-sdk-go-v2/aws" smithyauth "github.com/aws/smithy-go/auth" ) type endpointAuthResolver struct { EndpointResolver EndpointResolverV2 } var _ AuthSchemeResolver = (*endpointAuthResolver)(nil) func (r *endpointAuthResolver) ResolveAuthSchemes( ctx context.Context, params *AuthResolverParameters, ) ( []*smithyauth.Option, error, ) { if params.endpointParams.Region == nil { // #2502: We're correcting the endpoint binding behavior to treat empty // Region as "unset" (nil), but auth resolution technically doesn't // care and someone could be using V1 or non-default V2 endpoint // resolution, both of which would bypass the required-region check. // They shouldn't be broken because the region is technically required // by this service's endpoint-based auth resolver, so we stub it here. params.endpointParams.Region = aws.String("") } opts, err := r.resolveAuthSchemes(ctx, params) if err != nil { return nil, err } // canonicalize sigv4-s3express ID for _, opt := range opts { if opt.SchemeID == "sigv4-s3express" { opt.SchemeID = "com.amazonaws.s3#sigv4express" } } // preserve pre-SRA behavior where everything technically had anonymous return append(opts, &smithyauth.Option{ SchemeID: smithyauth.SchemeIDAnonymous, }), nil } func (r *endpointAuthResolver) resolveAuthSchemes( ctx context.Context, params *AuthResolverParameters, ) ( []*smithyauth.Option, error, ) { baseOpts, err := (&defaultAuthSchemeResolver{}).ResolveAuthSchemes(ctx, params) if err != nil { return nil, fmt.Errorf("get base options: %w", err) } endpt, err := r.EndpointResolver.ResolveEndpoint(ctx, *params.endpointParams) if err != nil { return nil, fmt.Errorf("resolve endpoint: %w", err) } endptOpts, ok := smithyauth.GetAuthOptions(&endpt.Properties) if !ok { return baseOpts, nil } // the list of options from the endpoint is authoritative, however, the // modeled options have some properties that the endpoint ones don't, so we // start from the latter and merge in for _, endptOpt := range endptOpts { if baseOpt := findScheme(baseOpts, endptOpt.SchemeID); baseOpt != nil { rebaseProps(endptOpt, baseOpt) } } return endptOpts, nil } // rebase the properties of dst, taking src as the base and overlaying those // from dst func rebaseProps(dst, src *smithyauth.Option) { iprops, sprops := src.IdentityProperties, src.SignerProperties iprops.SetAll(&dst.IdentityProperties) sprops.SetAll(&dst.SignerProperties) dst.IdentityProperties = iprops dst.SignerProperties = sprops } func findScheme(opts []*smithyauth.Option, schemeID string) *smithyauth.Option { for _, opt := range opts { if opt.SchemeID == schemeID { return opt } } return nil } func finalizeServiceEndpointAuthResolver(options *Options) { if _, ok := options.AuthSchemeResolver.(*defaultAuthSchemeResolver); !ok { return } options.AuthSchemeResolver = &endpointAuthResolver{ EndpointResolver: options.EndpointResolverV2, } } func finalizeOperationEndpointAuthResolver(options *Options) { resolver, ok := options.AuthSchemeResolver.(*endpointAuthResolver) if !ok { return } if resolver.EndpointResolver == options.EndpointResolverV2 { return } options.AuthSchemeResolver = &endpointAuthResolver{ EndpointResolver: options.EndpointResolverV2, } }