Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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 4 seconds to ensure prefetch completes
Thread.sleep(4_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