Skip to content

Commit e2b31bb

Browse files
committed
Addition additional tests and replacing initialization
1 parent 5079073 commit e2b31bb

File tree

2 files changed

+145
-19
lines changed

2 files changed

+145
-19
lines changed

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

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import software.amazon.awssdk.profiles.ProfileProperty;
4545
import software.amazon.awssdk.regions.util.HttpResourcesUtils;
4646
import software.amazon.awssdk.regions.util.ResourcesEndpointProvider;
47-
import software.amazon.awssdk.utils.Lazy;
4847
import software.amazon.awssdk.utils.Logger;
4948
import software.amazon.awssdk.utils.ToString;
5049
import software.amazon.awssdk.utils.Validate;
@@ -83,8 +82,8 @@ private enum ApiVersion {
8382

8483
private static final String EC2_METADATA_TOKEN_TTL_HEADER = "x-aws-ec2-metadata-token-ttl-seconds";
8584
private static final String DEFAULT_TOKEN_TTL = "21600";
86-
private Lazy<ApiVersion> apiVersion = new Lazy<>(() -> ApiVersion.UNKNOWN);
87-
private Lazy<String> resolvedProfile = new Lazy<>(() -> null);
85+
private ApiVersion apiVersion = ApiVersion.UNKNOWN;
86+
private String resolvedProfile = null;
8887

8988
private final Clock clock;
9089
private final String endpoint;
@@ -169,9 +168,8 @@ private RefreshResult<AwsCredentials> refreshCredentials() {
169168

170169
try {
171170
LoadedCredentials credentials = httpCredentialsLoader.loadCredentials(createEndpointProvider());
172-
ApiVersion currentVersion = apiVersion.getValue();
173-
if (currentVersion == ApiVersion.UNKNOWN) {
174-
apiVersion = Lazy.withValue(ApiVersion.EXTENDED);
171+
if (apiVersion == ApiVersion.UNKNOWN) {
172+
apiVersion = ApiVersion.EXTENDED;
175173
}
176174

177175
Instant expiration = credentials.getExpiration().orElse(null);
@@ -182,14 +180,13 @@ private RefreshResult<AwsCredentials> refreshCredentials() {
182180
.prefetchTime(prefetchTime(expiration))
183181
.build();
184182
} catch (Ec2MetadataClientException e) {
185-
if (apiVersion.getValue() == ApiVersion.UNKNOWN) {
186-
apiVersion = Lazy.withValue(ApiVersion.LEGACY);
187-
resolvedProfile = new Lazy<>(() -> null);
183+
if (apiVersion == ApiVersion.UNKNOWN) {
184+
apiVersion = ApiVersion.LEGACY;
185+
resolvedProfile = null;
188186
return refreshCredentials();
189187
}
190188
throw SdkClientException.create("Failed to load credentials from IMDS.", e);
191189
} catch (RuntimeException e) {
192-
resolvedProfile = new Lazy<>(() -> null);
193190
throw SdkClientException.create("Failed to load credentials from IMDS.", e);
194191
}
195192
}
@@ -233,7 +230,7 @@ public String toString() {
233230
}
234231

235232
private String getSecurityCredentialsResource() {
236-
return apiVersion.getValue() == ApiVersion.LEGACY ?
233+
return apiVersion == ApiVersion.LEGACY ?
237234
SECURITY_CREDENTIALS_RESOURCE :
238235
SECURITY_CREDENTIALS_EXTENDED_RESOURCE;
239236
}
@@ -316,8 +313,8 @@ private boolean isInsecureFallbackDisabled() {
316313
}
317314

318315
private String[] getSecurityCredentials(String imdsHostname, String metadataToken) {
319-
if (resolvedProfile.hasValue()) {
320-
return new String[]{resolvedProfile.getValue()};
316+
if (resolvedProfile != null) {
317+
return new String[]{resolvedProfile};
321318
}
322319

323320
String urlBase = getSecurityCredentialsResource();
@@ -337,16 +334,15 @@ private String[] getSecurityCredentials(String imdsHostname, String metadataToke
337334
throw SdkClientException.builder().message("Unable to load credentials path").build();
338335
}
339336

340-
ApiVersion currentVersion = apiVersion.getValue();
341-
if (currentVersion == ApiVersion.UNKNOWN) {
342-
apiVersion = Lazy.withValue(ApiVersion.EXTENDED);
337+
if (apiVersion == ApiVersion.UNKNOWN) {
338+
apiVersion = ApiVersion.EXTENDED;
343339
}
344-
resolvedProfile = new Lazy<>(() -> securityCredentials[0]);
340+
resolvedProfile = securityCredentials[0];
345341
return securityCredentials;
346342

347343
} catch (Ec2MetadataClientException e) {
348-
if (apiVersion.getValue() == ApiVersion.UNKNOWN) {
349-
apiVersion = Lazy.withValue(ApiVersion.LEGACY);
344+
if (apiVersion == ApiVersion.UNKNOWN) {
345+
apiVersion = ApiVersion.LEGACY;
350346
return getSecurityCredentials(imdsHostname, metadataToken);
351347
}
352348
throw SdkClientException.create("Failed to load credentials from IMDS.", e);

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

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
2626
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
2727
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2829

2930
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
3031
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
@@ -33,6 +34,7 @@
3334
import org.junit.jupiter.api.Test;
3435
import org.junit.jupiter.api.extension.RegisterExtension;
3536
import software.amazon.awssdk.core.SdkSystemSetting;
37+
import software.amazon.awssdk.core.exception.SdkClientException;
3638
import software.amazon.awssdk.testutils.EnvironmentVariableHelper;
3739
import software.amazon.awssdk.utils.DateUtils;
3840

@@ -117,6 +119,134 @@ void resolveCredentials_fallsBackToLegacy_noAccountId() {
117119
verifyImdsCallWithToken(false);
118120
}
119121

122+
@Test
123+
void resolveCredentials_withImdsDisabled_returnsNoCredentials() {
124+
environmentVariableHelper.set(SdkSystemSetting.AWS_EC2_METADATA_DISABLED.environmentVariable(), "true");
125+
InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider.builder().build();
126+
127+
assertThatThrownBy(() -> provider.resolveCredentials())
128+
.isInstanceOf(SdkClientException.class)
129+
.hasMessageContaining("IMDS credentials have been disabled");
130+
131+
verify(0, putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)));
132+
verify(0, getRequestedFor(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH)));
133+
verify(0, getRequestedFor(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH)));
134+
}
135+
136+
137+
@Test
138+
void resolveCredentials_withInvalidProfile_throwsException() {
139+
String invalidProfile = "my-profile-0004";
140+
141+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH))
142+
.willReturn(aResponse().withBody(invalidProfile)));
143+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH))
144+
.willReturn(aResponse().withBody(invalidProfile)));
145+
146+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH + invalidProfile))
147+
.willReturn(aResponse().withStatus(404)));
148+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH + invalidProfile))
149+
.willReturn(aResponse().withStatus(404)));
150+
151+
wireMockServer.stubFor(put(urlPathEqualTo(TOKEN_RESOURCE_PATH))
152+
.willReturn(aResponse().withBody(TOKEN_STUB)));
153+
154+
InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider.builder().build();
155+
156+
assertThatThrownBy(() -> provider.resolveCredentials())
157+
.isInstanceOf(SdkClientException.class)
158+
.hasMessageContaining("Failed to load credentials from IMDS.");
159+
}
160+
161+
@Test
162+
void resolveCredentials_withUnstableProfile_noAccountId_refreshesCredentials() {
163+
String firstCredentials = String.format(
164+
"{\"AccessKeyId\":\"ASIAIOSFODNN7EXAMPLE\"," +
165+
"\"SecretAccessKey\":\"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"," +
166+
"\"Token\":\"AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKw\"," +
167+
"\"Expiration\":\"%s\"," +
168+
"\"Code\":\"Success\"," +
169+
"\"Type\":\"AWS-HMAC\"," +
170+
"\"LastUpdated\":\"2025-03-18T20:53:17.832308Z\"," +
171+
"\"UnexpectedElement7\":{\"Name\":\"ignore-me-7\"}}",
172+
DateUtils.formatIso8601Date(Instant.now().plus(Duration.ofDays(1)))
173+
);
174+
175+
String secondCredentials = String.format(
176+
"{\"AccessKeyId\":\"ASIAIOSFODNN7EXAMPLE\"," +
177+
"\"SecretAccessKey\":\"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"," +
178+
"\"Token\":\"AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKw\"," +
179+
"\"Expiration\":\"%s\"," +
180+
"\"Code\":\"Success\"," +
181+
"\"Type\":\"AWS-HMAC\"," +
182+
"\"LastUpdated\":\"2025-03-18T20:53:17.832308Z\"," +
183+
"\"UnexpectedElement7\":{\"Name\":\"ignore-me-7\"}}",
184+
DateUtils.formatIso8601Date(Instant.now().plus(Duration.ofDays(1)))
185+
);
186+
187+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH))
188+
.inScenario("Profile Change No AccountId")
189+
.whenScenarioStateIs("Started")
190+
.willReturn(aResponse().withBody("my-profile-0007"))
191+
.willSetStateTo("First Profile"));
192+
193+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH + "my-profile-0007"))
194+
.inScenario("Profile Change No AccountId")
195+
.whenScenarioStateIs("First Profile")
196+
.willReturn(aResponse().withBody(firstCredentials))
197+
.willSetStateTo("First Profile Done"));
198+
199+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH + "my-profile-0007"))
200+
.inScenario("Profile Change No AccountId")
201+
.whenScenarioStateIs("First Profile Done")
202+
.willReturn(aResponse().withStatus(404))
203+
.willSetStateTo("Profile Changed"));
204+
205+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH))
206+
.inScenario("Profile Change No AccountId")
207+
.whenScenarioStateIs("Profile Changed")
208+
.willReturn(aResponse().withBody("my-profile-0007-b")));
209+
210+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH + "my-profile-0007-b"))
211+
.willReturn(aResponse().withBody(secondCredentials)));
212+
213+
wireMockServer.stubFor(put(urlPathEqualTo(TOKEN_RESOURCE_PATH))
214+
.willReturn(aResponse().withBody(TOKEN_STUB)));
215+
216+
InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider.builder().build();
217+
218+
AwsCredentials creds1 = provider.resolveCredentials();
219+
assertThat(creds1.accountId()).isEmpty();
220+
assertThat(creds1.accessKeyId()).isEqualTo("ASIAIOSFODNN7EXAMPLE");
221+
222+
AwsCredentials creds2 = provider.resolveCredentials();
223+
assertThat(creds2.accountId()).isEmpty();
224+
assertThat(creds2.accessKeyId()).isEqualTo("ASIAIOSFODNN7EXAMPLE");
225+
}
226+
227+
@Test
228+
void resolveCredentials_withDiscoveredInvalidProfile_noAccountId_throwsException() {
229+
String invalidProfile = "my-profile-0008";
230+
231+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH))
232+
.willReturn(aResponse().withBody(invalidProfile)));
233+
234+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_EXTENDED_RESOURCE_PATH + invalidProfile))
235+
.willReturn(aResponse().withStatus(404)));
236+
237+
wireMockServer.stubFor(get(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH + invalidProfile))
238+
.willReturn(aResponse().withStatus(404)));
239+
240+
wireMockServer.stubFor(put(urlPathEqualTo(TOKEN_RESOURCE_PATH))
241+
.willReturn(aResponse().withBody(TOKEN_STUB)));
242+
243+
InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider.builder().build();
244+
245+
assertThatThrownBy(() -> provider.resolveCredentials())
246+
.isInstanceOf(SdkClientException.class)
247+
.hasMessageContaining("Failed to load credentials from IMDS");
248+
}
249+
120250
@Test
121251
void resolveCredentials_cachesProfile_maintainsAccountId() {
122252
String credentialsWithAccountId = String.format(

0 commit comments

Comments
 (0)