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}