credentials.go

  1package aws
  2
  3import (
  4	"context"
  5	"fmt"
  6	"reflect"
  7	"time"
  8
  9	"github.com/aws/aws-sdk-go-v2/internal/sdk"
 10)
 11
 12// AnonymousCredentials provides a sentinel CredentialsProvider that should be
 13// used to instruct the SDK's signing middleware to not sign the request.
 14//
 15// Using `nil` credentials when configuring an API client will achieve the same
 16// result. The AnonymousCredentials type allows you to configure the SDK's
 17// external config loading to not attempt to source credentials from the shared
 18// config or environment.
 19//
 20// For example you can use this CredentialsProvider with an API client's
 21// Options to instruct the client not to sign a request for accessing public
 22// S3 bucket objects.
 23//
 24// The following example demonstrates using the AnonymousCredentials to prevent
 25// SDK's external config loading attempt to resolve credentials.
 26//
 27//	cfg, err := config.LoadDefaultConfig(context.TODO(),
 28//	     config.WithCredentialsProvider(aws.AnonymousCredentials{}),
 29//	)
 30//	if err != nil {
 31//	     log.Fatalf("failed to load config, %v", err)
 32//	}
 33//
 34//	client := s3.NewFromConfig(cfg)
 35//
 36// Alternatively you can leave the API client Option's `Credential` member to
 37// nil. If using the `NewFromConfig` constructor you'll need to explicitly set
 38// the `Credentials` member to nil, if the external config resolved a
 39// credential provider.
 40//
 41//	client := s3.New(s3.Options{
 42//	     // Credentials defaults to a nil value.
 43//	})
 44//
 45// This can also be configured for specific operations calls too.
 46//
 47//	cfg, err := config.LoadDefaultConfig(context.TODO())
 48//	if err != nil {
 49//	     log.Fatalf("failed to load config, %v", err)
 50//	}
 51//
 52//	client := s3.NewFromConfig(config)
 53//
 54//	result, err := client.GetObject(context.TODO(), s3.GetObject{
 55//	     Bucket: aws.String("example-bucket"),
 56//	     Key: aws.String("example-key"),
 57//	}, func(o *s3.Options) {
 58//	     o.Credentials = nil
 59//	     // Or
 60//	     o.Credentials = aws.AnonymousCredentials{}
 61//	})
 62type AnonymousCredentials struct{}
 63
 64// Retrieve implements the CredentialsProvider interface, but will always
 65// return error, and cannot be used to sign a request. The AnonymousCredentials
 66// type is used as a sentinel type instructing the AWS request signing
 67// middleware to not sign a request.
 68func (AnonymousCredentials) Retrieve(context.Context) (Credentials, error) {
 69	return Credentials{Source: "AnonymousCredentials"},
 70		fmt.Errorf("the AnonymousCredentials is not a valid credential provider, and cannot be used to sign AWS requests with")
 71}
 72
 73// A Credentials is the AWS credentials value for individual credential fields.
 74type Credentials struct {
 75	// AWS Access key ID
 76	AccessKeyID string
 77
 78	// AWS Secret Access Key
 79	SecretAccessKey string
 80
 81	// AWS Session Token
 82	SessionToken string
 83
 84	// Source of the credentials
 85	Source string
 86
 87	// States if the credentials can expire or not.
 88	CanExpire bool
 89
 90	// The time the credentials will expire at. Should be ignored if CanExpire
 91	// is false.
 92	Expires time.Time
 93
 94	// The ID of the account for the credentials.
 95	AccountID string
 96}
 97
 98// Expired returns if the credentials have expired.
 99func (v Credentials) Expired() bool {
100	if v.CanExpire {
101		// Calling Round(0) on the current time will truncate the monotonic
102		// reading only. Ensures credential expiry time is always based on
103		// reported wall-clock time.
104		return !v.Expires.After(sdk.NowTime().Round(0))
105	}
106
107	return false
108}
109
110// HasKeys returns if the credentials keys are set.
111func (v Credentials) HasKeys() bool {
112	return len(v.AccessKeyID) > 0 && len(v.SecretAccessKey) > 0
113}
114
115// A CredentialsProvider is the interface for any component which will provide
116// credentials Credentials. A CredentialsProvider is required to manage its own
117// Expired state, and what to be expired means.
118//
119// A credentials provider implementation can be wrapped with a CredentialCache
120// to cache the credential value retrieved. Without the cache the SDK will
121// attempt to retrieve the credentials for every request.
122type CredentialsProvider interface {
123	// Retrieve returns nil if it successfully retrieved the value.
124	// Error is returned if the value were not obtainable, or empty.
125	Retrieve(ctx context.Context) (Credentials, error)
126}
127
128// CredentialsProviderFunc provides a helper wrapping a function value to
129// satisfy the CredentialsProvider interface.
130type CredentialsProviderFunc func(context.Context) (Credentials, error)
131
132// Retrieve delegates to the function value the CredentialsProviderFunc wraps.
133func (fn CredentialsProviderFunc) Retrieve(ctx context.Context) (Credentials, error) {
134	return fn(ctx)
135}
136
137type isCredentialsProvider interface {
138	IsCredentialsProvider(CredentialsProvider) bool
139}
140
141// IsCredentialsProvider returns whether the target CredentialProvider is the same type as provider when comparing the
142// implementation type.
143//
144// If provider has a method IsCredentialsProvider(CredentialsProvider) bool it will be responsible for validating
145// whether target matches the credential provider type.
146//
147// When comparing the CredentialProvider implementations provider and target for equality, the following rules are used:
148//
149//	If provider is of type T and target is of type V, true if type *T is the same as type *V, otherwise false
150//	If provider is of type *T and target is of type V, true if type *T is the same as type *V, otherwise false
151//	If provider is of type T and target is of type *V, true if type *T is the same as type *V, otherwise false
152//	If provider is of type *T and target is of type *V,true if type *T is the same as type *V, otherwise false
153func IsCredentialsProvider(provider, target CredentialsProvider) bool {
154	if target == nil || provider == nil {
155		return provider == target
156	}
157
158	if x, ok := provider.(isCredentialsProvider); ok {
159		return x.IsCredentialsProvider(target)
160	}
161
162	targetType := reflect.TypeOf(target)
163	if targetType.Kind() != reflect.Ptr {
164		targetType = reflect.PtrTo(targetType)
165	}
166
167	providerType := reflect.TypeOf(provider)
168	if providerType.Kind() != reflect.Ptr {
169		providerType = reflect.PtrTo(providerType)
170	}
171
172	return targetType.AssignableTo(providerType)
173}