Skip to content

Commit 1c05fb6

Browse files
authored
Implements IsCredentialsProvider for checking if a provider matches a target provider type. (#1890)
1 parent 0fab39a commit 1c05fb6

File tree

10 files changed

+195
-13
lines changed

10 files changed

+195
-13
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"id": "1b61ec1c-e18c-4cdf-ae74-f8852ecbf877",
3+
"type": "bugfix",
4+
"description": "The SDK client has been updated to utilize the `aws.IsCredentialsProvider` function for determining if `aws.AnonymousCredentials` has been configured for the `CredentialProvider`.",
5+
"modules": [
6+
"service/eventbridge",
7+
"service/s3"
8+
]
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "869890a0-30aa-4f8e-8ddd-5ef80b7a01df",
3+
"type": "feature",
4+
"description": "Adds `aws.IsCredentialsProvider` for inspecting `CredentialProvider` types when needing to determine if the underlying implementation type matches a target type. This resolves an issue where `CredentialsCache` could mask `AnonymousCredentials` providers, breaking downstream detection logic.",
5+
"modules": [
6+
"."
7+
]
8+
}

aws/credential_cache.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ func (p *CredentialsCache) Invalidate() {
178178
p.creds.Store((*Credentials)(nil))
179179
}
180180

181+
// IsCredentialsProvider returns whether credential provider wrapped by CredentialsCache
182+
// matches the target provider type.
183+
func (p *CredentialsCache) IsCredentialsProvider(target CredentialsProvider) bool {
184+
return IsCredentialsProvider(p.provider, target)
185+
}
186+
181187
// HandleFailRefreshCredentialsCacheStrategy is an interface for
182188
// CredentialsCache to allow CredentialsProvider how failed to refresh
183189
// credentials is handled.

aws/credential_cache_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,3 +617,46 @@ func (m mockAdjustExpiryBy) AdjustExpiresBy(creds Credentials, dur time.Duration
617617
}
618618
return m.creds, m.err
619619
}
620+
621+
func TestCredentialsCache_IsCredentialsProvider(t *testing.T) {
622+
tests := map[string]struct {
623+
provider CredentialsProvider
624+
target CredentialsProvider
625+
want bool
626+
}{
627+
"nil provider and target": {
628+
provider: nil,
629+
target: nil,
630+
want: true,
631+
},
632+
"matches value implementations": {
633+
provider: NewCredentialsCache(AnonymousCredentials{}),
634+
target: AnonymousCredentials{},
635+
want: true,
636+
},
637+
"matches value and pointer implementations, wrapped pointer": {
638+
provider: NewCredentialsCache(&AnonymousCredentials{}),
639+
target: AnonymousCredentials{},
640+
want: true,
641+
},
642+
"matches value and pointer implementations, pointer target": {
643+
provider: NewCredentialsCache(AnonymousCredentials{}),
644+
target: &AnonymousCredentials{},
645+
want: true,
646+
},
647+
"does not match mismatched provider types": {
648+
provider: NewCredentialsCache(AnonymousCredentials{}),
649+
target: &stubCredentialsProvider{},
650+
want: false,
651+
},
652+
}
653+
for name, tt := range tests {
654+
t.Run(name, func(t *testing.T) {
655+
if got := NewCredentialsCache(tt.provider).IsCredentialsProvider(tt.target); got != tt.want {
656+
t.Errorf("IsCredentialsProvider() = %v, want %v", got, tt.want)
657+
}
658+
})
659+
}
660+
}
661+
662+
var _ isCredentialsProvider = (*CredentialsCache)(nil)

aws/credentials.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package aws
33
import (
44
"context"
55
"fmt"
6+
"reflect"
67
"time"
78

89
"github.com/aws/aws-sdk-go-v2/internal/sdk"
@@ -129,3 +130,41 @@ type CredentialsProviderFunc func(context.Context) (Credentials, error)
129130
func (fn CredentialsProviderFunc) Retrieve(ctx context.Context) (Credentials, error) {
130131
return fn(ctx)
131132
}
133+
134+
type isCredentialsProvider interface {
135+
IsCredentialsProvider(CredentialsProvider) bool
136+
}
137+
138+
// IsCredentialsProvider returns whether the target CredentialProvider is the same type as provider when comparing the
139+
// implementation type.
140+
//
141+
// If provider has a method IsCredentialsProvider(CredentialsProvider) bool it will be responsible for validating
142+
// whether target matches the credential provider type.
143+
//
144+
// When comparing the CredentialProvider implementations provider and target for equality, the following rules are used:
145+
//
146+
// If provider is of type T and target is of type V, true if type *T is the same as type *V, otherwise false
147+
// If provider is of type *T and target is of type V, true if type *T is the same as type *V, otherwise false
148+
// If provider is of type T and target is of type *V, true if type *T is the same as type *V, otherwise false
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+
func IsCredentialsProvider(provider, target CredentialsProvider) bool {
151+
if target == nil || provider == nil {
152+
return provider == target
153+
}
154+
155+
if x, ok := provider.(isCredentialsProvider); ok {
156+
return x.IsCredentialsProvider(target)
157+
}
158+
159+
targetType := reflect.TypeOf(target)
160+
if targetType.Kind() != reflect.Ptr {
161+
targetType = reflect.PtrTo(targetType)
162+
}
163+
164+
providerType := reflect.TypeOf(provider)
165+
if providerType.Kind() != reflect.Ptr {
166+
providerType = reflect.PtrTo(providerType)
167+
}
168+
169+
return targetType.AssignableTo(providerType)
170+
}

aws/credentials_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package aws
2+
3+
import (
4+
"context"
5+
"testing"
6+
)
7+
8+
type anonymousNamedType AnonymousCredentials
9+
10+
func (f anonymousNamedType) Retrieve(ctx context.Context) (Credentials, error) {
11+
return AnonymousCredentials(f).Retrieve(ctx)
12+
}
13+
14+
func TestIsCredentialsProvider(t *testing.T) {
15+
tests := map[string]struct {
16+
provider CredentialsProvider
17+
target CredentialsProvider
18+
want bool
19+
}{
20+
"same implementations": {
21+
provider: AnonymousCredentials{},
22+
target: AnonymousCredentials{},
23+
want: true,
24+
},
25+
"same implementations, pointer target": {
26+
provider: AnonymousCredentials{},
27+
target: &AnonymousCredentials{},
28+
want: true,
29+
},
30+
"same implementations, pointer provider": {
31+
provider: &AnonymousCredentials{},
32+
target: AnonymousCredentials{},
33+
want: true,
34+
},
35+
"same implementations, both pointers": {
36+
provider: &AnonymousCredentials{},
37+
target: &AnonymousCredentials{},
38+
want: true,
39+
},
40+
"different implementations, nil target": {
41+
provider: AnonymousCredentials{},
42+
target: nil,
43+
want: false,
44+
},
45+
"different implementations, nil provider": {
46+
provider: nil,
47+
target: AnonymousCredentials{},
48+
want: false,
49+
},
50+
"different implementations": {
51+
provider: AnonymousCredentials{},
52+
target: &stubCredentialsProvider{},
53+
want: false,
54+
},
55+
"nil provider and target": {
56+
provider: nil,
57+
target: nil,
58+
want: true,
59+
},
60+
"implements IsCredentialsProvider, match": {
61+
provider: NewCredentialsCache(AnonymousCredentials{}),
62+
target: AnonymousCredentials{},
63+
want: true,
64+
},
65+
"implements IsCredentialsProvider, no match": {
66+
provider: NewCredentialsCache(AnonymousCredentials{}),
67+
target: &stubCredentialsProvider{},
68+
want: false,
69+
},
70+
"named types aliasing underlying types": {
71+
provider: AnonymousCredentials{},
72+
target: anonymousNamedType{},
73+
want: false,
74+
},
75+
}
76+
for name, tt := range tests {
77+
t.Run(name, func(t *testing.T) {
78+
if got := IsCredentialsProvider(tt.provider, tt.target); got != tt.want {
79+
t.Errorf("IsCredentialsProvider() = %v, want %v", got, tt.want)
80+
}
81+
})
82+
}
83+
}

aws/signer/v4/middleware.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,8 @@ func haveCredentialProvider(p aws.CredentialsProvider) bool {
371371
if p == nil {
372372
return false
373373
}
374-
switch p.(type) {
375-
case aws.AnonymousCredentials,
376-
*aws.AnonymousCredentials:
377-
return false
378-
}
379374

380-
return true
375+
return !aws.IsCredentialsProvider(p, (*aws.AnonymousCredentials)(nil))
381376
}
382377

383378
type payloadHashKey struct{}

codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsSignatureVersion4aUtils.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public static void writeCredentialProviderResolver(GoWriter writer) {
4242
AwsCustomGoDependency.INTERNAL_SIGV4A).build());
4343
writer.putContext("anonType", SymbolUtils.createPointableSymbolBuilder("AnonymousCredentials",
4444
AwsCustomGoDependency.AWS_CORE).build());
45+
writer.putContext("isProvider", SymbolUtils.createValueSymbolBuilder("IsCredentialsProvider",
46+
AwsCustomGoDependency.AWS_CORE).build());
4547
writer.putContext("adapType", SymbolUtils.createPointableSymbolBuilder("SymmetricCredentialAdaptor",
4648
AwsCustomGoDependency.INTERNAL_SIGV4A).build());
4749
writer.write("""
@@ -54,9 +56,8 @@ public static void writeCredentialProviderResolver(GoWriter writer) {
5456
return
5557
}
5658
57-
switch o.$fieldName:L.(type) {
58-
case $anonType:T, $anonType:P:
59-
return
59+
if $isProvider:T(o.$fieldName:L, ($anonType:P)(nil)) {
60+
return
6061
}
6162
6263
o.$fieldName:L = &$adapType:T{SymmetricProvider: o.$fieldName:L}

service/eventbridge/api_client.go

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

service/s3/api_client.go

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)