Skip to content
Closed
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/feature-AWSSDKforJavav2-aa60cd3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "Amazon S3",
"contributor": "",
"description": "Implemented business metrics tracking for S3_Express_Bucket (featureID \"J\") through User-Agent header."
}
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,12 @@ private MethodSpec setMetricValuesMethod() {
+ "metrics -> endpoint.attribute($T.METRIC_VALUES).forEach(v -> metrics.addMetric(v)))",
SdkInternalExecutionAttribute.class, AwsEndpointAttribute.class);
b.endControlFlow();

if (endpointRulesSpecUtils.isS3()) {
b.addStatement("$T.addS3ExpressBusinessMetricIfApplicable(executionAttributes)",
ClassName.get("software.amazon.awssdk.services.s3.internal.s3express", "S3ExpressUtils"));
}

return b.build();
}
}
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 @@ -39,6 +39,7 @@
import software.amazon.awssdk.auth.credentials.internal.HttpCredentialsLoader.LoadedCredentials;
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.core.util.SdkUserAgent;
import software.amazon.awssdk.regions.util.ResourcesEndpointProvider;
import software.amazon.awssdk.regions.util.ResourcesEndpointRetryPolicy;
Expand Down Expand Up @@ -72,7 +73,8 @@
public final class ContainerCredentialsProvider
implements HttpCredentialsProvider,
ToCopyableBuilder<ContainerCredentialsProvider.Builder, ContainerCredentialsProvider> {
private static final String PROVIDER_NAME = "ContainerCredentialsProvider";
private static final String CLASS_NAME = "ContainerCredentialsProvider";
private static final String PROVIDER_NAME = BusinessMetricFeatureId.CREDENTIALS_HTTP.value();
private static final Predicate<InetAddress> IS_LOOPBACK_ADDRESS = InetAddress::isLoopbackAddress;
private static final Predicate<InetAddress> ALLOWED_HOSTS_RULES = IS_LOOPBACK_ADDRESS;
private static final String HTTPS = "https";
Expand All @@ -90,6 +92,7 @@ public final class ContainerCredentialsProvider
private final Boolean asyncCredentialUpdateEnabled;

private final String asyncThreadName;
private final String source;

/**
* @see #builder()
Expand All @@ -98,7 +101,8 @@ private ContainerCredentialsProvider(BuilderImpl builder) {
this.endpoint = builder.endpoint;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
this.asyncThreadName = builder.asyncThreadName;
this.httpCredentialsLoader = HttpCredentialsLoader.create(PROVIDER_NAME);
this.source = builder.source;
this.httpCredentialsLoader = HttpCredentialsLoader.create(providerName());

if (Boolean.TRUE.equals(builder.asyncCredentialUpdateEnabled)) {
Validate.paramNotBlank(builder.asyncThreadName, "asyncThreadName");
Expand Down Expand Up @@ -126,7 +130,7 @@ public static Builder builder() {

@Override
public String toString() {
return ToString.create(PROVIDER_NAME);
return ToString.create(CLASS_NAME);
}

private RefreshResult<AwsCredentials> refreshCredentials() {
Expand Down Expand Up @@ -160,6 +164,14 @@ private Instant prefetchTime(Instant expiration) {
return ComparableUtils.minimum(oneHourFromNow, fifteenMinutesBeforeExpiration);
}

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

@Override
public AwsCredentials resolveCredentials() {
return credentialsCache.get();
Expand Down Expand Up @@ -318,6 +330,7 @@ private static final class BuilderImpl implements Builder {
private String endpoint;
private Boolean asyncCredentialUpdateEnabled;
private String asyncThreadName;
private String source;

private BuilderImpl() {
asyncThreadName("container-credentials-provider");
Expand All @@ -327,6 +340,7 @@ private BuilderImpl(ContainerCredentialsProvider credentialsProvider) {
this.endpoint = credentialsProvider.endpoint;
this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled;
this.asyncThreadName = credentialsProvider.asyncThreadName;
this.source = credentialsProvider.source;
}

@Override
Expand Down Expand Up @@ -359,6 +373,16 @@ public void setAsyncThreadName(String asyncThreadName) {
asyncThreadName(asyncThreadName);
}

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

public void setSource(String source) {
source(source);
}

@Override
public ContainerCredentialsProvider build() {
return new ContainerCredentialsProvider(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Optional;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.auth.credentials.internal.SystemSettingsCredentialsProvider;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.utils.SystemSetting;
import software.amazon.awssdk.utils.ToString;

Expand All @@ -28,7 +29,8 @@
@SdkPublicApi
public final class EnvironmentVariableCredentialsProvider extends SystemSettingsCredentialsProvider {

private static final String PROVIDER_NAME = "EnvironmentVariableCredentialsProvider";
private static final String CLASS_NAME = "EnvironmentVariableCredentialsProvider";
private static final String PROVIDER_NAME = BusinessMetricFeatureId.CREDENTIALS_ENV_VARS.value();

private EnvironmentVariableCredentialsProvider() {
}
Expand All @@ -52,6 +54,6 @@ protected String provider() {

@Override
public String toString() {
return ToString.create(PROVIDER_NAME);
return ToString.create(CLASS_NAME);
}
}
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 @@ -48,6 +49,14 @@ interface Builder<TypeToBuildT extends HttpCredentialsProvider, BuilderT extends
*/
BuilderT endpoint(String endpoint);

/**
* 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();
}

/**
* Build the credentials provider based on the configuration on this builder.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.core.exception.SdkServiceException;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.profiles.ProfileFileSupplier;
import software.amazon.awssdk.profiles.ProfileFileSystemSetting;
Expand Down Expand Up @@ -67,7 +68,8 @@ public final class InstanceProfileCredentialsProvider
implements HttpCredentialsProvider,
ToCopyableBuilder<InstanceProfileCredentialsProvider.Builder, InstanceProfileCredentialsProvider> {
private static final Logger log = Logger.loggerFor(InstanceProfileCredentialsProvider.class);
private static final String PROVIDER_NAME = "InstanceProfileCredentialsProvider";
private static final String CLASS_NAME = "InstanceProfileCredentialsProvider";
private static final String PROVIDER_NAME = BusinessMetricFeatureId.CREDENTIALS_IMDS.value();
private static final String EC2_METADATA_TOKEN_HEADER = "x-aws-ec2-metadata-token";
private static final String SECURITY_CREDENTIALS_RESOURCE = "/latest/meta-data/iam/security-credentials/";
private static final String TOKEN_RESOURCE = "/latest/api/token";
Expand All @@ -90,6 +92,8 @@ public final class InstanceProfileCredentialsProvider

private final Duration staleTime;

private final String source;

/**
* @see #builder()
*/
Expand All @@ -102,8 +106,9 @@ private InstanceProfileCredentialsProvider(BuilderImpl builder) {
.orElseGet(() -> ProfileFileSupplier.fixedProfileFile(ProfileFile.defaultProfileFile()));
this.profileName = Optional.ofNullable(builder.profileName)
.orElseGet(ProfileFileSystemSetting.AWS_PROFILE::getStringValueOrThrow);
this.source = builder.source;

this.httpCredentialsLoader = HttpCredentialsLoader.create(PROVIDER_NAME);
this.httpCredentialsLoader = HttpCredentialsLoader.create(providerName());
this.configProvider =
Ec2MetadataConfigProvider.builder()
.profileFile(profileFile)
Expand Down Expand Up @@ -202,9 +207,17 @@ public void close() {
credentialsCache.close();
}

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

@Override
public String toString() {
return ToString.create(PROVIDER_NAME);
return ToString.create(CLASS_NAME);
}

private ResourcesEndpointProvider createEndpointProvider() {
Expand Down Expand Up @@ -372,6 +385,7 @@ static final class BuilderImpl implements Builder {
private Supplier<ProfileFile> profileFile;
private String profileName;
private Duration staleTime;
private String source;

private BuilderImpl() {
asyncThreadName("instance-profile-credentials-provider");
Expand All @@ -385,6 +399,7 @@ private BuilderImpl(InstanceProfileCredentialsProvider provider) {
this.profileFile = provider.profileFile;
this.profileName = provider.profileName;
this.staleTime = provider.staleTime;
this.source = provider.source;
}

Builder clock(Clock clock) {
Expand Down Expand Up @@ -463,6 +478,16 @@ public void setStaleTime(Duration duration) {
staleTime(duration);
}

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

public void setSource(String source) {
source(source);
}

@Override
public InstanceProfileCredentialsProvider build() {
return new InstanceProfileCredentialsProvider(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Collections;
import java.util.List;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId;
import software.amazon.awssdk.protocols.jsoncore.JsonNode;
import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser;
import software.amazon.awssdk.utils.DateUtils;
Expand Down Expand Up @@ -64,7 +65,8 @@ public final class ProcessCredentialsProvider
implements AwsCredentialsProvider,
SdkAutoCloseable,
ToCopyableBuilder<ProcessCredentialsProvider.Builder, ProcessCredentialsProvider> {
private static final String PROVIDER_NAME = "ProcessCredentialsProvider";
private static final String CLASS_NAME = "ProcessCredentialsProvider";
private static final String PROVIDER_NAME = BusinessMetricFeatureId.CREDENTIALS_PROCESS.value();
private static final JsonNodeParser PARSER = JsonNodeParser.builder()
.removeErrorLocations(true)
.build();
Expand All @@ -82,6 +84,8 @@ public final class ProcessCredentialsProvider

private final Boolean asyncCredentialUpdateEnabled;

private final String source;

/**
* @see #builder()
*/
Expand All @@ -93,6 +97,7 @@ private ProcessCredentialsProvider(Builder builder) {
this.commandAsListOfStringsFromBuilder = builder.commandAsListOfStrings;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
this.staticAccountId = builder.staticAccountId;
this.source = builder.source;

CachedSupplier.Builder<AwsCredentials> cacheBuilder = CachedSupplier.builder(this::refreshCredentials)
.cachedValueName(toString());
Expand Down Expand Up @@ -171,6 +176,14 @@ private JsonNode parseProcessOutput(String processOutput) {
return credentialsJson;
}

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

/**
* Parse the process output to retrieve the credentials.
*/
Expand All @@ -192,13 +205,13 @@ private AwsCredentials credentials(JsonNode credentialsJson) {
.sessionToken(sessionToken)
.expirationTime(credentialExpirationTime(credentialsJson))
.accountId(resolvedAccountId)
.providerName(PROVIDER_NAME)
.providerName(providerName())
.build() :
AwsBasicCredentials.builder()
.accessKeyId(accessKeyId)
.secretAccessKey(secretAccessKey)
.accountId(resolvedAccountId)
.providerName(PROVIDER_NAME)
.providerName(providerName())
.build();
}

Expand Down Expand Up @@ -270,6 +283,7 @@ public static class Builder implements CopyableBuilder<Builder, ProcessCredentia
private Duration credentialRefreshThreshold = Duration.ofSeconds(15);
private long processOutputLimit = 64000;
private String staticAccountId;
private String source;

/**
* @see #builder()
Expand All @@ -284,6 +298,7 @@ private Builder(ProcessCredentialsProvider provider) {
this.credentialRefreshThreshold = provider.credentialRefreshThreshold;
this.processOutputLimit = provider.processOutputLimit;
this.staticAccountId = provider.staticAccountId;
this.source = provider.source;
}

/**
Expand Down Expand Up @@ -357,14 +372,22 @@ public Builder staticAccountId(String staticAccountId) {
return this;
}

/**
* Configure the source of this credentials provider. This is used for business metrics tracking.
*/
public Builder source(String source) {
this.source = source;
return this;
}

public ProcessCredentialsProvider build() {
return new ProcessCredentialsProvider(this);
}
}

@Override
public String toString() {
return ToString.builder(PROVIDER_NAME)
return ToString.builder(CLASS_NAME)
.add("cmd", executableCommand)
.build();
}
Expand Down
Loading