Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/bugfix-AWSSTS-bc7dfee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "bugfix",
"category": "AWS STS",
"contributor": "",
"description": "Fix `StsWebIdentityTokenFileCredentialsProvider` not respecting custom `prefetchTime` and `staleTime` configurations."
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ public Duration prefetchTime() {
return prefetchTime;
}

/**
* Whether the provider should fetch credentials asynchronously in the background.
* <p>By default, this is false.</p>
*/
public Boolean asyncCredentialUpdateEnabled() {
return asyncCredentialUpdateEnabled;
}

@Override
public String toString() {
return ToString.create(providerName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,14 @@ private StsWebIdentityTokenFileCredentialsProvider(Builder builder) {
.assumeRoleWithWebIdentityRequest(assumeRoleWithWebIdentityRequest.get())
.webIdentityTokenFile(credentialProperties.webIdentityTokenFile())
.build();

credentialsProviderLocal =
StsAssumeRoleWithWebIdentityCredentialsProvider.builder()
.stsClient(builder.stsClient)
.refreshRequest(supplier)
.staleTime(this.staleTime())
.prefetchTime(this.prefetchTime())
.asyncCredentialUpdateEnabled(this.asyncCredentialUpdateEnabled())
.build();
} catch (RuntimeException e) {
// If we couldn't load the credentials provider for some reason, save an exception describing why. This exception
Expand Down Expand Up @@ -181,7 +185,7 @@ private Builder() {
}

private Builder(StsWebIdentityTokenFileCredentialsProvider provider) {
super(StsWebIdentityTokenFileCredentialsProvider::new);
super(StsWebIdentityTokenFileCredentialsProvider::new, provider);
this.roleArn = provider.roleArn;
this.roleSessionName = provider.roleSessionName;
this.webIdentityTokenFile = provider.webIdentityTokenFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleWithWebIdentityRequest;
import software.amazon.awssdk.services.sts.model.AssumeRoleWithWebIdentityResponse;
import software.amazon.awssdk.services.sts.model.AssumedRoleUser;
import software.amazon.awssdk.services.sts.model.Credentials;

import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import software.amazon.awssdk.testutils.EnvironmentVariableHelper;

import static org.mockito.Mockito.when;
import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(MockitoExtension.class)
class StsWebIdentityTokenCredentialProviderTest {
Expand Down Expand Up @@ -111,4 +114,108 @@ void createAssumeRoleWithWebIdentityTokenCredentialsProvider_raisesInResolveCred
// exception should be raised lazily when resolving credentials, not at creation time.
Assert.assertThrows(IllegalStateException.class, provider::resolveCredentials);
}

@Test
void customPrefetchTime_actuallyTriggersRefreshEarly() throws InterruptedException {
Mockito.reset(stsClient);

Instant tokenExpiration = Instant.now().plusSeconds(5);
Duration customPrefetchTime = Duration.ofSeconds(2);
Duration customStaleTime = Duration.ofSeconds(1);

when(stsClient.assumeRoleWithWebIdentity(Mockito.any(AssumeRoleWithWebIdentityRequest.class)))
.thenReturn(AssumeRoleWithWebIdentityResponse.builder()
.credentials(Credentials.builder()
.accessKeyId("key1")
.secretAccessKey("secret1")
.sessionToken("session1")
.expiration(tokenExpiration)
.build())
.assumedRoleUser(AssumedRoleUser.builder()
.arn("arn:aws:iam::123456789012:role/test-role")
.assumedRoleId("role:session")
.build())
.build())

.thenReturn(AssumeRoleWithWebIdentityResponse.builder()
.credentials(Credentials.builder()
.accessKeyId("key2")
.secretAccessKey("secret2")
.sessionToken("session2")
.expiration(Instant.now().plusSeconds(8))
.build())
.assumedRoleUser(AssumedRoleUser.builder()
.arn("arn:aws:iam::123456789012:role/test-role")
.assumedRoleId("role:session")
.build())
.build());


StsWebIdentityTokenFileCredentialsProvider provider =
StsWebIdentityTokenFileCredentialsProvider.builder()
.stsClient(stsClient)
.asyncCredentialUpdateEnabled(true)
.prefetchTime(customPrefetchTime)
.staleTime(customStaleTime)
.build();

try {
assertThat(provider.prefetchTime()).isEqualTo(customPrefetchTime);
assertThat(provider.staleTime()).isEqualTo(customStaleTime);

provider.resolveCredentials();
Mockito.verify(stsClient, Mockito.times(1)).assumeRoleWithWebIdentity(Mockito.any(AssumeRoleWithWebIdentityRequest.class));

// Wait 5 seconds to ensure prefetch completes
Thread.sleep(5_000);
Mockito.verify(stsClient, Mockito.times(2)).assumeRoleWithWebIdentity(Mockito.any(AssumeRoleWithWebIdentityRequest.class));

} finally {
provider.close();
}
}

@Test
void defaultTiming_usesStandardValues() {
StsWebIdentityTokenFileCredentialsProvider provider =
StsWebIdentityTokenFileCredentialsProvider.builder()
.stsClient(stsClient)
.build();

try {
assertThat(provider.prefetchTime()).isEqualTo(Duration.ofMinutes(5));
assertThat(provider.staleTime()).isEqualTo(Duration.ofMinutes(1));
} finally {
provider.close();
}
}

@Test
void toBuilder_preservesCustomTimingConfiguration() {
Duration customPrefetch = Duration.ofMinutes(10);
Duration customStale = Duration.ofMinutes(3);

StsWebIdentityTokenFileCredentialsProvider originalProvider =
StsWebIdentityTokenFileCredentialsProvider.builder()
.stsClient(stsClient)
.prefetchTime(customPrefetch)
.staleTime(customStale)
.build();

try {
assertThat(originalProvider.prefetchTime()).isEqualTo(customPrefetch);
assertThat(originalProvider.staleTime()).isEqualTo(customStale);

StsWebIdentityTokenFileCredentialsProvider copiedProvider = originalProvider.toBuilder().build();

try {
assertThat(copiedProvider.prefetchTime()).isEqualTo(customPrefetch);
assertThat(copiedProvider.staleTime()).isEqualTo(customStale);
} finally {
copiedProvider.close();
}
} finally {
originalProvider.close();
}
}
}
Loading