Skip to content

Commit c3e743b

Browse files
authored
DefaultCredentialsProvider reload profile (#3580)
* Misc fixes * Reload credentials by DefaultCredentialsProvider; pass supplier to InstanceProfileCredentialsProvider * Fix code alignment
1 parent 6b186a2 commit c3e743b

File tree

4 files changed

+231
-31
lines changed

4 files changed

+231
-31
lines changed

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

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515

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

18+
import java.util.Optional;
1819
import software.amazon.awssdk.annotations.SdkPublicApi;
1920
import software.amazon.awssdk.auth.credentials.internal.LazyAwsCredentialsProvider;
2021
import software.amazon.awssdk.profiles.ProfileFile;
22+
import software.amazon.awssdk.profiles.ProfileFileSupplier;
2123
import software.amazon.awssdk.utils.SdkAutoCloseable;
2224
import software.amazon.awssdk.utils.ToString;
2325
import software.amazon.awssdk.utils.builder.CopyableBuilder;
@@ -26,8 +28,8 @@
2628
/**
2729
* AWS credentials provider chain that looks for credentials in this order:
2830
* <ol>
29-
* <li>Java System Properties - <code>aws.accessKeyId</code> and <code>aws.secretAccessKey</code></li>
30-
* <li>Environment Variables - <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code></li>
31+
* <li>Java System Properties - {@code aws.accessKeyId} and {@code aws.secretAccessKey}</li>
32+
* <li>Environment Variables - {@code AWS_ACCESS_KEY_ID} and {@code AWS_SECRET_ACCESS_KEY}</li>
3133
* <li>Web Identity Token credentials from system properties or environment variables</li>
3234
* <li>Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI</li>
3335
* <li>Credentials delivered through the Amazon EC2 container service if AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" environment
@@ -51,7 +53,7 @@ public final class DefaultCredentialsProvider
5153

5254
private final LazyAwsCredentialsProvider providerChain;
5355

54-
private final ProfileFile profileFile;
56+
private final ProfileFileSupplier profileFileSupplier;
5557

5658
private final String profileName;
5759

@@ -63,7 +65,7 @@ public final class DefaultCredentialsProvider
6365
* @see #builder()
6466
*/
6567
private DefaultCredentialsProvider(Builder builder) {
66-
this.profileFile = builder.profileFile;
68+
this.profileFileSupplier = builder.profileFileSupplier;
6769
this.profileName = builder.profileName;
6870
this.reuseLastProviderEnabled = builder.reuseLastProviderEnabled;
6971
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
@@ -87,21 +89,21 @@ private static LazyAwsCredentialsProvider createChain(Builder builder) {
8789

8890
return LazyAwsCredentialsProvider.create(() -> {
8991
AwsCredentialsProvider[] credentialsProviders = new AwsCredentialsProvider[] {
90-
SystemPropertyCredentialsProvider.create(),
91-
EnvironmentVariableCredentialsProvider.create(),
92-
WebIdentityTokenFileCredentialsProvider.create(),
93-
ProfileCredentialsProvider.builder()
94-
.profileFile(builder.profileFile)
95-
.profileName(builder.profileName)
96-
.build(),
97-
ContainerCredentialsProvider.builder()
98-
.asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled)
99-
.build(),
100-
InstanceProfileCredentialsProvider.builder()
101-
.asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled)
102-
.profileFile(builder.profileFile)
103-
.profileName(builder.profileName)
104-
.build()
92+
SystemPropertyCredentialsProvider.create(),
93+
EnvironmentVariableCredentialsProvider.create(),
94+
WebIdentityTokenFileCredentialsProvider.create(),
95+
ProfileCredentialsProvider.builder()
96+
.profileFile(builder.profileFileSupplier)
97+
.profileName(builder.profileName)
98+
.build(),
99+
ContainerCredentialsProvider.builder()
100+
.asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled)
101+
.build(),
102+
InstanceProfileCredentialsProvider.builder()
103+
.asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled)
104+
.profileFile(builder.profileFileSupplier)
105+
.profileName(builder.profileName)
106+
.build()
105107
};
106108

107109
return AwsCredentialsProviderChain.builder()
@@ -144,7 +146,7 @@ public Builder toBuilder() {
144146
* Configuration that defines the {@link DefaultCredentialsProvider}'s behavior.
145147
*/
146148
public static final class Builder implements CopyableBuilder<Builder, DefaultCredentialsProvider> {
147-
private ProfileFile profileFile;
149+
private ProfileFileSupplier profileFileSupplier;
148150
private String profileName;
149151
private Boolean reuseLastProviderEnabled = true;
150152
private Boolean asyncCredentialUpdateEnabled = false;
@@ -156,14 +158,20 @@ private Builder() {
156158
}
157159

158160
private Builder(DefaultCredentialsProvider credentialsProvider) {
159-
this.profileFile = credentialsProvider.profileFile;
161+
this.profileFileSupplier = credentialsProvider.profileFileSupplier;
160162
this.profileName = credentialsProvider.profileName;
161163
this.reuseLastProviderEnabled = credentialsProvider.reuseLastProviderEnabled;
162164
this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled;
163165
}
164166

165167
public Builder profileFile(ProfileFile profileFile) {
166-
this.profileFile = profileFile;
168+
return profileFile(Optional.ofNullable(profileFile)
169+
.map(ProfileFileSupplier::fixedProfileFile)
170+
.orElse(null));
171+
}
172+
173+
public Builder profileFile(ProfileFileSupplier profileFileSupplier) {
174+
this.profileFileSupplier = profileFileSupplier;
167175
return this;
168176
}
169177

@@ -198,6 +206,7 @@ public Builder asyncCredentialUpdateEnabled(Boolean asyncCredentialUpdateEnabled
198206
/**
199207
* Create a {@link DefaultCredentialsProvider} using the configuration defined in this builder.
200208
*/
209+
@Override
201210
public DefaultCredentialsProvider build() {
202211
return new DefaultCredentialsProvider(this);
203212
}

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

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.time.Instant;
2727
import java.util.Collections;
2828
import java.util.Map;
29+
import java.util.Optional;
2930
import software.amazon.awssdk.annotations.SdkPublicApi;
3031
import software.amazon.awssdk.annotations.SdkTestInternalApi;
3132
import software.amazon.awssdk.auth.credentials.internal.Ec2MetadataConfigProvider;
@@ -36,6 +37,7 @@
3637
import software.amazon.awssdk.core.exception.SdkClientException;
3738
import software.amazon.awssdk.core.exception.SdkServiceException;
3839
import software.amazon.awssdk.profiles.ProfileFile;
40+
import software.amazon.awssdk.profiles.ProfileFileSupplier;
3941
import software.amazon.awssdk.profiles.ProfileFileSystemSetting;
4042
import software.amazon.awssdk.regions.util.HttpResourcesUtils;
4143
import software.amazon.awssdk.regions.util.ResourcesEndpointProvider;
@@ -77,7 +79,7 @@ public final class InstanceProfileCredentialsProvider
7779

7880
private final String asyncThreadName;
7981

80-
private final ProfileFile profileFile;
82+
private final ProfileFileSupplier profileFileSupplier;
8183

8284
private final String profileName;
8385

@@ -89,14 +91,14 @@ private InstanceProfileCredentialsProvider(BuilderImpl builder) {
8991
this.endpoint = builder.endpoint;
9092
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
9193
this.asyncThreadName = builder.asyncThreadName;
92-
this.profileFile = builder.profileFile;
94+
this.profileFileSupplier = builder.profileFileSupplier;
9395
this.profileName = builder.profileName;
9496

9597
this.httpCredentialsLoader = HttpCredentialsLoader.create();
9698
this.configProvider =
9799
Ec2MetadataConfigProvider.builder()
98-
.profileFile(builder.profileFile == null ? null : () -> builder.profileFile)
99-
.profileName(builder.profileName == null ? null : builder.profileName)
100+
.profileFile(builder.profileFileSupplier)
101+
.profileName(builder.profileName)
100102
.build();
101103

102104
if (Boolean.TRUE.equals(builder.asyncCredentialUpdateEnabled)) {
@@ -279,9 +281,19 @@ public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfile
279281
* Configure the profile file used for loading IMDS-related configuration, like the endpoint mode (IPv4 vs IPv6).
280282
*
281283
* <p>By default, {@link ProfileFile#defaultProfileFile()} is used.
284+
*
285+
* @see #profileFile(ProfileFileSupplier)
282286
*/
283287
Builder profileFile(ProfileFile profileFile);
284288

289+
/**
290+
* Define the mechanism for loading profile files.
291+
*
292+
* @param profileFileSupplier Supplier interface for generating a ProfileFile instance.
293+
* @see #profileFile(ProfileFile)
294+
*/
295+
Builder profileFile(ProfileFileSupplier profileFileSupplier);
296+
285297
/**
286298
* Configure the profile name used for loading IMDS-related configuration, like the endpoint mode (IPv4 vs IPv6).
287299
*
@@ -292,6 +304,7 @@ public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfile
292304
/**
293305
* Build a {@link InstanceProfileCredentialsProvider} from the provided configuration.
294306
*/
307+
@Override
295308
InstanceProfileCredentialsProvider build();
296309
}
297310

@@ -301,7 +314,7 @@ static final class BuilderImpl implements Builder {
301314
private String endpoint;
302315
private Boolean asyncCredentialUpdateEnabled;
303316
private String asyncThreadName;
304-
private ProfileFile profileFile;
317+
private ProfileFileSupplier profileFileSupplier;
305318
private String profileName;
306319

307320
private BuilderImpl() {
@@ -313,7 +326,7 @@ private BuilderImpl(InstanceProfileCredentialsProvider provider) {
313326
this.endpoint = provider.endpoint;
314327
this.asyncCredentialUpdateEnabled = provider.asyncCredentialUpdateEnabled;
315328
this.asyncThreadName = provider.asyncThreadName;
316-
this.profileFile = provider.profileFile;
329+
this.profileFileSupplier = provider.profileFileSupplier;
317330
this.profileName = provider.profileName;
318331
}
319332

@@ -354,14 +367,25 @@ public void setAsyncThreadName(String asyncThreadName) {
354367

355368
@Override
356369
public Builder profileFile(ProfileFile profileFile) {
357-
this.profileFile = profileFile;
358-
return this;
370+
return profileFile(Optional.ofNullable(profileFile)
371+
.map(ProfileFileSupplier::fixedProfileFile)
372+
.orElse(null));
359373
}
360374

361375
public void setProfileFile(ProfileFile profileFile) {
362376
profileFile(profileFile);
363377
}
364378

379+
@Override
380+
public Builder profileFile(ProfileFileSupplier profileFileSupplier) {
381+
this.profileFileSupplier = profileFileSupplier;
382+
return this;
383+
}
384+
385+
public void setProfileFile(ProfileFileSupplier profileFileSupplier) {
386+
profileFile(profileFileSupplier);
387+
}
388+
365389
@Override
366390
public Builder profileName(String profileName) {
367391
this.profileName = profileName;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.auth.credentials;
17+
18+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
19+
20+
import java.util.Arrays;
21+
import java.util.List;
22+
import org.junit.jupiter.api.Test;
23+
import software.amazon.awssdk.profiles.ProfileFile;
24+
import software.amazon.awssdk.profiles.ProfileFileSupplier;
25+
import software.amazon.awssdk.utils.StringInputStream;
26+
27+
class DefaultCredentialsProviderTest {
28+
29+
@Test
30+
void resolveCredentials_requestFallsIntoProfileCredentialsProviderWithProfileFile_returnsCredentials() {
31+
DefaultCredentialsProvider provider = DefaultCredentialsProvider
32+
.builder()
33+
.profileFile(credentialFile("test", "access", "secret"))
34+
.profileName("test")
35+
.build();
36+
37+
assertThat(provider.resolveCredentials()).satisfies(awsCredentials -> {
38+
assertThat(awsCredentials.accessKeyId()).isEqualTo("access");
39+
assertThat(awsCredentials.secretAccessKey()).isEqualTo("secret");
40+
});
41+
}
42+
43+
@Test
44+
void resolveCredentials_requestFallsIntoProfileCredentialsProviderWithProfileFileSupplier_returnsCredentials() {
45+
List<ProfileFile> profileFileList = Arrays.asList(credentialFile("test", "access", "secret"),
46+
credentialFile("test", "modified", "update"));
47+
ProfileFileSupplier profileFileSupplier = supply(profileFileList);
48+
49+
DefaultCredentialsProvider provider = DefaultCredentialsProvider
50+
.builder()
51+
.profileFile(profileFileSupplier)
52+
.profileName("test")
53+
.build();
54+
55+
assertThat(provider.resolveCredentials()).satisfies(awsCredentials -> {
56+
assertThat(awsCredentials.accessKeyId()).isEqualTo("access");
57+
assertThat(awsCredentials.secretAccessKey()).isEqualTo("secret");
58+
});
59+
60+
assertThat(provider.resolveCredentials()).satisfies(awsCredentials -> {
61+
assertThat(awsCredentials.accessKeyId()).isEqualTo("modified");
62+
assertThat(awsCredentials.secretAccessKey()).isEqualTo("update");
63+
});
64+
}
65+
66+
private ProfileFile credentialFile(String credentialFile) {
67+
return ProfileFile.builder()
68+
.content(new StringInputStream(credentialFile))
69+
.type(ProfileFile.Type.CREDENTIALS)
70+
.build();
71+
}
72+
73+
private ProfileFile credentialFile(String name, String accessKeyId, String secretAccessKey) {
74+
String contents = String.format("[%s]\naws_access_key_id = %s\naws_secret_access_key = %s\n",
75+
name, accessKeyId, secretAccessKey);
76+
return credentialFile(contents);
77+
}
78+
79+
private static ProfileFileSupplier supply(Iterable<ProfileFile> iterable) {
80+
return iterable.iterator()::next;
81+
}
82+
83+
}

0 commit comments

Comments
 (0)