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