Skip to content

Commit bbea89e

Browse files
authored
Update AwsCredentialsProviderChain for new Identity type (#3883)
1 parent d41c517 commit bbea89e

File tree

2 files changed

+128
-28
lines changed

2 files changed

+128
-28
lines changed

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.List;
2323
import software.amazon.awssdk.annotations.SdkPublicApi;
2424
import software.amazon.awssdk.core.exception.SdkClientException;
25+
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
26+
import software.amazon.awssdk.identity.spi.IdentityProvider;
2527
import software.amazon.awssdk.utils.IoUtils;
2628
import software.amazon.awssdk.utils.Logger;
2729
import software.amazon.awssdk.utils.SdkAutoCloseable;
@@ -52,11 +54,11 @@ public final class AwsCredentialsProviderChain
5254
ToCopyableBuilder<AwsCredentialsProviderChain.Builder, AwsCredentialsProviderChain> {
5355
private static final Logger log = Logger.loggerFor(AwsCredentialsProviderChain.class);
5456

55-
private final List<AwsCredentialsProvider> credentialsProviders;
57+
private final List<IdentityProvider<? extends AwsCredentialsIdentity>> credentialsProviders;
5658

5759
private final boolean reuseLastProviderEnabled;
5860

59-
private volatile AwsCredentialsProvider lastUsedProvider;
61+
private volatile IdentityProvider<? extends AwsCredentialsIdentity> lastUsedProvider;
6062

6163
/**
6264
* @see #builder()
@@ -84,21 +86,33 @@ public static AwsCredentialsProviderChain of(AwsCredentialsProvider... awsCreden
8486
return builder().credentialsProviders(awsCredentialsProviders).build();
8587
}
8688

89+
/**
90+
* Create an AWS credentials provider chain with default configuration that checks the given credential providers.
91+
* @param awsCredentialsProviders The credentials providers that should be checked for credentials, in the order they should
92+
* be checked.
93+
* @return A credential provider chain that checks the provided credential providers in order.
94+
*/
95+
public static AwsCredentialsProviderChain of(IdentityProvider<? extends AwsCredentialsIdentity>... awsCredentialsProviders) {
96+
return builder().credentialsProviders(awsCredentialsProviders).build();
97+
}
98+
8799
@Override
88100
public AwsCredentials resolveCredentials() {
89101
if (reuseLastProviderEnabled && lastUsedProvider != null) {
90-
return lastUsedProvider.resolveCredentials();
102+
// TODO: Exception handling for join?
103+
return CredentialUtils.toCredentials(lastUsedProvider.resolveIdentity().join());
91104
}
92105

93106
List<String> exceptionMessages = null;
94-
for (AwsCredentialsProvider provider : credentialsProviders) {
107+
for (IdentityProvider<? extends AwsCredentialsIdentity> provider : credentialsProviders) {
95108
try {
96-
AwsCredentials credentials = provider.resolveCredentials();
109+
// TODO: Exception handling for join?
110+
AwsCredentialsIdentity credentials = provider.resolveIdentity().join();
97111

98112
log.debug(() -> "Loading credentials from " + provider);
99113

100114
lastUsedProvider = provider;
101-
return credentials;
115+
return CredentialUtils.toCredentials(credentials);
102116
} catch (RuntimeException e) {
103117
// Ignore any exceptions and move onto the next provider
104118
String message = provider + ": " + e.getMessage();
@@ -156,19 +170,43 @@ public interface Builder extends CopyableBuilder<Builder, AwsCredentialsProvider
156170
/**
157171
* Configure the credentials providers that should be checked for credentials, in the order they should be checked.
158172
*/
159-
Builder credentialsProviders(AwsCredentialsProvider... credentialsProviders);
173+
Builder credentialsIdentityProviders(
174+
Collection<? extends IdentityProvider<? extends AwsCredentialsIdentity>> credentialsProviders);
175+
176+
/**
177+
* Configure the credentials providers that should be checked for credentials, in the order they should be checked.
178+
*/
179+
default Builder credentialsProviders(AwsCredentialsProvider... credentialsProviders) {
180+
return credentialsProviders((IdentityProvider<? extends AwsCredentialsIdentity>[]) credentialsProviders);
181+
}
182+
183+
/**
184+
* Configure the credentials providers that should be checked for credentials, in the order they should be checked.
185+
*/
186+
default Builder credentialsProviders(IdentityProvider<? extends AwsCredentialsIdentity>... credentialsProviders) {
187+
throw new UnsupportedOperationException();
188+
}
189+
190+
/**
191+
* Add a credential provider to the chain, after the credential providers that have already been configured.
192+
*/
193+
default Builder addCredentialsProvider(AwsCredentialsProvider credentialsProvider) {
194+
return addCredentialsProvider((IdentityProvider<? extends AwsCredentialsIdentity>) credentialsProvider);
195+
}
160196

161197
/**
162198
* Add a credential provider to the chain, after the credential providers that have already been configured.
163199
*/
164-
Builder addCredentialsProvider(AwsCredentialsProvider credentialsProviders);
200+
default Builder addCredentialsProvider(IdentityProvider<? extends AwsCredentialsIdentity> credentialsProvider) {
201+
throw new UnsupportedOperationException();
202+
}
165203

166204
AwsCredentialsProviderChain build();
167205
}
168206

169207
private static final class BuilderImpl implements Builder {
170208
private Boolean reuseLastProviderEnabled = true;
171-
private List<AwsCredentialsProvider> credentialsProviders = new ArrayList<>();
209+
private List<IdentityProvider<? extends AwsCredentialsIdentity>> credentialsProviders = new ArrayList<>();
172210

173211
private BuilderImpl() {
174212
}
@@ -199,13 +237,25 @@ public void setCredentialsProviders(Collection<? extends AwsCredentialsProvider>
199237
}
200238

201239
@Override
202-
public Builder credentialsProviders(AwsCredentialsProvider... credentialsProviders) {
203-
return credentialsProviders(Arrays.asList(credentialsProviders));
240+
public Builder credentialsIdentityProviders(
241+
Collection<? extends IdentityProvider<? extends AwsCredentialsIdentity>> credentialsProviders) {
242+
this.credentialsProviders = new ArrayList<>(credentialsProviders);
243+
return this;
244+
}
245+
246+
public void setCredentialsIdentityProviders(
247+
Collection<? extends IdentityProvider<? extends AwsCredentialsIdentity>> credentialsProviders) {
248+
credentialsIdentityProviders(credentialsProviders);
249+
}
250+
251+
@Override
252+
public Builder credentialsProviders(IdentityProvider<? extends AwsCredentialsIdentity>... credentialsProviders) {
253+
return credentialsIdentityProviders(Arrays.asList(credentialsProviders));
204254
}
205255

206256
@Override
207-
public Builder addCredentialsProvider(AwsCredentialsProvider credentialsProviders) {
208-
this.credentialsProviders.add(credentialsProviders);
257+
public Builder addCredentialsProvider(IdentityProvider<? extends AwsCredentialsIdentity> credentialsProvider) {
258+
this.credentialsProviders.add(credentialsProvider);
209259
return this;
210260
}
211261

core/auth/src/test/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChainTest.java

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,28 @@
1515

1616
package software.amazon.awssdk.auth.credentials;
1717

18-
import static org.junit.Assert.assertEquals;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
import static org.junit.jupiter.api.Assertions.assertThrows;
1921

20-
import org.junit.Rule;
22+
import java.util.Arrays;
2123
import org.junit.Test;
22-
import org.junit.rules.ExpectedException;
24+
import org.junit.jupiter.api.function.Executable;
2325
import software.amazon.awssdk.core.exception.SdkClientException;
26+
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
27+
import software.amazon.awssdk.identity.spi.IdentityProvider;
2428
import software.amazon.awssdk.profiles.ProfileFile;
2529
import software.amazon.awssdk.utils.StringInputStream;
2630

2731
public class AwsCredentialsProviderChainTest {
2832

29-
@Rule
30-
public ExpectedException thrown = ExpectedException.none();
31-
3233
/**
3334
* Tests that, by default, the chain remembers which provider was able to
3435
* provide credentials, and only calls that provider for any additional
3536
* calls to getCredentials.
3637
*/
3738
@Test
38-
public void testReusingLastProvider() throws Exception {
39+
public void resolveCredentials_reuseEnabled_reusesLastProvider() throws Exception {
3940
MockCredentialsProvider provider1 = new MockCredentialsProvider("Failed!");
4041
MockCredentialsProvider provider2 = new MockCredentialsProvider();
4142
AwsCredentialsProviderChain chain = AwsCredentialsProviderChain.builder()
@@ -64,7 +65,7 @@ public void testReusingLastProvider() throws Exception {
6465
* provider that can return credentials.
6566
*/
6667
@Test
67-
public void testDisableReusingLastProvider() throws Exception {
68+
public void resolveCredentials_reuseDisabled_alwaysGoesThroughChain() throws Exception {
6869
MockCredentialsProvider provider1 = new MockCredentialsProvider("Failed!");
6970
MockCredentialsProvider provider2 = new MockCredentialsProvider();
7071
AwsCredentialsProviderChain chain = AwsCredentialsProviderChain.builder()
@@ -85,7 +86,7 @@ public void testDisableReusingLastProvider() throws Exception {
8586
}
8687

8788
@Test
88-
public void testMissingProfileUsesNextProvider() {
89+
public void resolveCredentials_missingProfile_usesNextProvider() {
8990
ProfileCredentialsProvider provider =
9091
new ProfileCredentialsProvider.BuilderImpl()
9192
.defaultProfileFileLoader(() -> ProfileFile.builder()
@@ -103,24 +104,73 @@ public void testMissingProfileUsesNextProvider() {
103104
}
104105

105106
/**
106-
* Tests that getCredentials throws an thrown if all providers in the
107+
* Tests that resolveCredentials throws an thrown if all providers in the
107108
* chain fail to provide credentials.
108109
*/
109110
@Test
110-
public void testGetCredentialsException() {
111+
public void resolveCredentials_allProvidersFail_throwsExceptionWithMessageFromAllProviders() {
111112
MockCredentialsProvider provider1 = new MockCredentialsProvider("Failed!");
112113
MockCredentialsProvider provider2 = new MockCredentialsProvider("Bad!");
113114
AwsCredentialsProviderChain chain = AwsCredentialsProviderChain.builder()
114115
.credentialsProviders(provider1, provider2)
115116
.build();
116117

117-
thrown.expect(SdkClientException.class);
118-
thrown.expectMessage(provider1.exceptionMessage);
119-
thrown.expectMessage(provider2.exceptionMessage);
118+
SdkClientException e = assertThrows(SdkClientException.class, () -> chain.resolveCredentials());
119+
assertThat(e.getMessage()).contains(provider1.exceptionMessage);
120+
assertThat(e.getMessage()).contains(provider2.exceptionMessage);
121+
}
120122

121-
chain.resolveCredentials();
123+
@Test
124+
public void resolveCredentials_emptyChain_throwsException() {
125+
assertThrowsIllegalArgument(() -> AwsCredentialsProviderChain.of());
126+
127+
assertThrowsIllegalArgument(() -> AwsCredentialsProviderChain
128+
.builder()
129+
.credentialsProviders()
130+
.build());
131+
132+
assertThrowsIllegalArgument(() -> AwsCredentialsProviderChain
133+
.builder()
134+
.credentialsProviders(Arrays.asList())
135+
.build());
122136
}
123137

138+
private void assertThrowsIllegalArgument(Executable executable) {
139+
IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable);
140+
assertThat(e.getMessage()).contains("No credential providers were specified.");
141+
}
142+
143+
/**
144+
* Tests that the chain is setup correctly with the overloaded methods that accept the AwsCredentialsProvider type.
145+
*/
146+
@Test
147+
public void createMethods_withOldCredentialsType_work() {
148+
AwsCredentialsProvider provider = StaticCredentialsProvider.create(AwsBasicCredentials.create(
149+
"accessKey", "secretKey"));
150+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.of(provider));
151+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.builder().credentialsProviders(provider).build());
152+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.builder().credentialsProviders(Arrays.asList(provider)).build());
153+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.builder().addCredentialsProvider(provider).build());
154+
}
155+
156+
/**
157+
* Tests that the chain is setup correctly with the overloaded methods that accept the IdentityProvider type.
158+
*/
159+
@Test
160+
public void createMethods_withNewCredentialsType_work() {
161+
IdentityProvider<AwsCredentialsIdentity> provider = StaticCredentialsProvider.create(AwsBasicCredentials.create(
162+
"accessKey", "secretKey"));
163+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.of(provider));
164+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.builder().credentialsProviders(provider).build());
165+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.builder().credentialsIdentityProviders(Arrays.asList(provider)).build());
166+
assertChainResolvesCorrectly(AwsCredentialsProviderChain.builder().addCredentialsProvider(provider).build());
167+
}
168+
169+
private static void assertChainResolvesCorrectly(AwsCredentialsProviderChain chain) {
170+
AwsCredentials credentials = chain.resolveCredentials();
171+
assertThat(credentials.accessKeyId()).isEqualTo("accessKey");
172+
assertThat(credentials.secretAccessKey()).isEqualTo("secretKey");
173+
}
124174

125175
private static final class MockCredentialsProvider implements AwsCredentialsProvider {
126176
private final StaticCredentialsProvider staticCredentialsProvider;

0 commit comments

Comments
 (0)