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
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,23 @@ public interface ChildProfileCredentialsProviderFactory {
* provider.
* @return The credentials provider with permissions derived from the source credentials provider and profile.
*/
AwsCredentialsProvider create(AwsCredentialsProvider sourceCredentialsProvider, Profile profile);
default AwsCredentialsProvider create(AwsCredentialsProvider sourceCredentialsProvider, Profile profile) {
return create(sourceCredentialsProvider, profile, null);
}

/**
* Create a credentials provider for the provided profile, using the provided source credentials provider to authenticate
* with AWS. In the case of STS, the returned credentials provider is for a role that has been assumed, and the provided
* source credentials provider is the credentials that should be used to authenticate that the user is allowed to assume
* that role.
*
* @param sourceCredentialsProvider The credentials provider that should be used to authenticate the child credentials
* provider. This credentials provider should be closed when it is no longer used.
* @param profile The profile that should be used to load the configuration necessary to create the child credentials
* provider.
* @param source A string list of {@link software.amazon.awssdk.core.useragent.BusinessMetricFeatureId} denoting
* previous credentials providers that are chained with this one.
* @return The credentials provider with permissions derived from the source credentials provider and profile.
*/
AwsCredentialsProvider create(AwsCredentialsProvider sourceCredentialsProvider, Profile profile, String source);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package software.amazon.awssdk.auth.credentials;

import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.utils.SdkAutoCloseable;

/**
Expand Down Expand Up @@ -49,7 +50,8 @@ interface Builder<TypeToBuildT extends HttpCredentialsProvider, BuilderT extends
BuilderT endpoint(String endpoint);

/**
* Configure the source of this credentials provider. This is used for business metrics tracking.
* An optional string list of {@link BusinessMetricFeatureId} denoting previous credentials providers
* that are chained with this one.
*/
default BuilderT source(String source) {
throw new UnsupportedOperationException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider;
import software.amazon.awssdk.core.internal.util.ClassLoaderHelper;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.profiles.Profile;
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.profiles.ProfileProperty;
Expand Down Expand Up @@ -161,6 +162,7 @@ private AwsCredentialsProvider basicProfileCredentialsProvider() {
.accessKeyId(properties.get(ProfileProperty.AWS_ACCESS_KEY_ID))
.secretAccessKey(properties.get(ProfileProperty.AWS_SECRET_ACCESS_KEY))
.accountId(properties.get(ProfileProperty.AWS_ACCOUNT_ID))
.providerName(BusinessMetricFeatureId.CREDENTIALS_PROFILE.value())
.build();
return StaticCredentialsProvider.create(credentials);
}
Expand All @@ -177,6 +179,7 @@ private AwsCredentialsProvider sessionProfileCredentialsProvider() {
.secretAccessKey(properties.get(ProfileProperty.AWS_SECRET_ACCESS_KEY))
.sessionToken(properties.get(ProfileProperty.AWS_SESSION_TOKEN))
.accountId(properties.get(ProfileProperty.AWS_ACCOUNT_ID))
.providerName(BusinessMetricFeatureId.CREDENTIALS_PROFILE.value())
.build();
return StaticCredentialsProvider.create(credentials);
}
Expand All @@ -187,28 +190,36 @@ private AwsCredentialsProvider credentialProcessCredentialsProvider() {
return ProcessCredentialsProvider.builder()
.command(properties.get(ProfileProperty.CREDENTIAL_PROCESS))
.staticAccountId(properties.get(ProfileProperty.AWS_ACCOUNT_ID))
.source(BusinessMetricFeatureId.CREDENTIALS_PROFILE_PROCESS.value())
.build();
}

/**
* Create the SSO credentials provider based on the related profile properties.
*/
private AwsCredentialsProvider ssoProfileCredentialsProvider() {
validateRequiredPropertiesForSsoCredentialsProvider();
boolean isLegacy = validateRequiredPropertiesForSsoCredentialsProvider();
String source = isLegacy ?
BusinessMetricFeatureId.CREDENTIALS_PROFILE_SSO_LEGACY.value() :
BusinessMetricFeatureId.CREDENTIALS_PROFILE_SSO.value();

return ssoCredentialsProviderFactory().create(
ProfileProviderCredentialsContext.builder()
.profile(profile)
.profileFile(profileFile)
.source(source)
.build());
}

private void validateRequiredPropertiesForSsoCredentialsProvider() {
private boolean validateRequiredPropertiesForSsoCredentialsProvider() {
requireProperties(ProfileProperty.SSO_ACCOUNT_ID,
ProfileProperty.SSO_ROLE_NAME);

if (!properties.containsKey(ProfileSection.SSO_SESSION.getPropertyKeyName())) {
requireProperties(ProfileProperty.SSO_REGION, ProfileProperty.SSO_START_URL);
return true;
}
return false;
}

private AwsCredentialsProvider roleAndWebIdentityTokenProfileCredentialsProvider() {
Expand All @@ -223,6 +234,7 @@ private AwsCredentialsProvider roleAndWebIdentityTokenProfileCredentialsProvider
.roleArn(roleArn)
.roleSessionName(roleSessionName)
.webIdentityTokenFile(webIdentityTokenFile)
.source(BusinessMetricFeatureId.CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN.value())
.build();

return WebIdentityCredentialsUtils.factory().create(credentialProperties);
Expand All @@ -249,7 +261,8 @@ private AwsCredentialsProvider roleAndSourceProfileBasedProfileCredentialsProvid
.credentialsProvider(children))
.orElseThrow(this::noSourceCredentialsException);

return stsCredentialsProviderFactory().create(sourceCredentialsProvider, profile);
String source = BusinessMetricFeatureId.CREDENTIALS_PROFILE_SOURCE_PROFILE.value();
return stsCredentialsProviderFactory().create(sourceCredentialsProvider, profile, source);
}

/**
Expand All @@ -260,18 +273,20 @@ private AwsCredentialsProvider roleAndCredentialSourceBasedProfileCredentialsPro
requireProperties(ProfileProperty.CREDENTIAL_SOURCE);

CredentialSourceType credentialSource = CredentialSourceType.parse(properties.get(ProfileProperty.CREDENTIAL_SOURCE));
AwsCredentialsProvider credentialsProvider = credentialSourceCredentialProvider(credentialSource);
return stsCredentialsProviderFactory().create(credentialsProvider, profile);
String source = BusinessMetricFeatureId.CREDENTIALS_PROFILE_NAMED_PROVIDER.value();
AwsCredentialsProvider credentialsProvider = credentialSourceCredentialProvider(credentialSource, source);
return stsCredentialsProviderFactory().create(credentialsProvider, profile, source);
}

private AwsCredentialsProvider credentialSourceCredentialProvider(CredentialSourceType credentialSource) {
private AwsCredentialsProvider credentialSourceCredentialProvider(CredentialSourceType credentialSource, String source) {
switch (credentialSource) {
case ECS_CONTAINER:
return ContainerCredentialsProvider.builder().build();
return ContainerCredentialsProvider.builder().source(source).build();
case EC2_INSTANCE_METADATA:
return InstanceProfileCredentialsProvider.builder()
.profileFile(profileFile)
.profileName(name)
.source(source)
.build();
case ENVIRONMENT:
return AwsCredentialsProviderChain.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.services.sso.SsoClient;
import software.amazon.awssdk.services.sso.internal.SessionCredentialsHolder;
import software.amazon.awssdk.services.sso.model.GetRoleCredentialsRequest;
import software.amazon.awssdk.services.sso.model.RoleCredentials;
import software.amazon.awssdk.utils.SdkAutoCloseable;
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
import software.amazon.awssdk.utils.cache.CachedSupplier;
Expand All @@ -51,14 +53,15 @@
@SdkPublicApi
public final class SsoCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable,
ToCopyableBuilder<SsoCredentialsProvider.Builder, SsoCredentialsProvider> {
private static final String PROVIDER_NAME = "SsoCredentialsProvider";
private static final String PROVIDER_NAME = BusinessMetricFeatureId.CREDENTIALS_SSO.value();

private static final Duration DEFAULT_STALE_TIME = Duration.ofMinutes(1);
private static final Duration DEFAULT_PREFETCH_TIME = Duration.ofMinutes(5);

private static final String ASYNC_THREAD_NAME = "sdk-sso-credentials-provider";

private final Supplier<GetRoleCredentialsRequest> getRoleCredentialsRequestSupplier;
private final String source;

private final SsoClient ssoClient;
private final Duration staleTime;
Expand All @@ -77,6 +80,7 @@ private SsoCredentialsProvider(BuilderImpl builder) {

this.staleTime = Optional.ofNullable(builder.staleTime).orElse(DEFAULT_STALE_TIME);
this.prefetchTime = Optional.ofNullable(builder.prefetchTime).orElse(DEFAULT_PREFETCH_TIME);
this.source = builder.source;

this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
CachedSupplier.Builder<SessionCredentialsHolder> cacheBuilder =
Expand All @@ -95,11 +99,11 @@ private SsoCredentialsProvider(BuilderImpl builder) {
*/
private RefreshResult<SessionCredentialsHolder> updateSsoCredentials() {
SessionCredentialsHolder credentials = getUpdatedCredentials(ssoClient);
Instant acutalTokenExpiration = credentials.sessionCredentialsExpiration();
Instant actualTokenExpiration = credentials.sessionCredentialsExpiration();

return RefreshResult.builder(credentials)
.staleTime(acutalTokenExpiration.minus(staleTime))
.prefetchTime(acutalTokenExpiration.minus(prefetchTime))
.staleTime(actualTokenExpiration.minus(staleTime))
.prefetchTime(actualTokenExpiration.minus(prefetchTime))
.build();
}

Expand All @@ -112,11 +116,19 @@ private SessionCredentialsHolder getUpdatedCredentials(SsoClient ssoClient) {
.secretAccessKey(roleCredentials.secretAccessKey())
.sessionToken(roleCredentials.sessionToken())
.accountId(request.accountId())
.providerName(PROVIDER_NAME)
.providerName(providerName())
.build();
return new SessionCredentialsHolder(sessionCredentials, Instant.ofEpochMilli(roleCredentials.expiration()));
}

private String providerName() {
String providerName = PROVIDER_NAME;
if (!StringUtils.isEmpty(this.source)) {
providerName = String.format("%s,%s", this.source, providerName);
}
return providerName;
}

/**
* The amount of time, relative to session token expiration, that the cached credentials are considered stale and
* should no longer be used. All threads will block until the value is updated.
Expand Down Expand Up @@ -206,6 +218,12 @@ public interface Builder extends CopyableBuilder<Builder, SsoCredentialsProvider
*/
Builder refreshRequest(Supplier<GetRoleCredentialsRequest> getRoleCredentialsRequestSupplier);

/**
* An optional string list of {@link software.amazon.awssdk.core.useragent.BusinessMetricFeatureId} denoting previous
* credentials providers that are chained with this one.
*/
Builder source(String source);

/**
* Create a {@link SsoCredentialsProvider} using the configuration applied to this builder.
* @return
Expand All @@ -220,6 +238,7 @@ protected static final class BuilderImpl implements Builder {
private Duration staleTime;
private Duration prefetchTime;
private Supplier<GetRoleCredentialsRequest> getRoleCredentialsRequestSupplier;
private String source;

BuilderImpl() {

Expand All @@ -231,6 +250,7 @@ public BuilderImpl(SsoCredentialsProvider provider) {
this.staleTime = provider.staleTime;
this.prefetchTime = provider.prefetchTime;
this.getRoleCredentialsRequestSupplier = provider.getRoleCredentialsRequestSupplier;
this.source = provider.source;
}

@Override
Expand Down Expand Up @@ -268,6 +288,12 @@ public Builder refreshRequest(Supplier<GetRoleCredentialsRequest> getRoleCredent
return this;
}

@Override
public Builder source(String source) {
this.source = source;
return this;
}

@Override
public SsoCredentialsProvider build() {
return new SsoCredentialsProvider(this);
Expand Down
Loading