diff --git a/.changes/next-release/feature-AWSSDKforJavav2-5ae2bad.json b/.changes/next-release/feature-AWSSDKforJavav2-5ae2bad.json
new file mode 100644
index 000000000000..eb26897c7cb4
--- /dev/null
+++ b/.changes/next-release/feature-AWSSDKforJavav2-5ae2bad.json
@@ -0,0 +1,6 @@
+{
+ "type": "feature",
+ "category": "AWS SDK for Java v2",
+ "contributor": "",
+ "description": "Records identity provider names in a resolved identity and adds this information to the user agent string"
+}
diff --git a/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml b/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml
index 85fb5754cd6f..9ece65ccac3a 100644
--- a/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml
+++ b/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml
@@ -293,6 +293,11 @@
+
+
+
+
+
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProvider.java
index b4d7d22f4580..b547f5d84b34 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProvider.java
@@ -25,6 +25,8 @@
@SdkPublicApi
public final class AnonymousCredentialsProvider implements AwsCredentialsProvider {
+ private static final String PROVIDER_NAME = "AnonymousCredentialsProvider";
+
private AnonymousCredentialsProvider() {
}
@@ -34,11 +36,14 @@ public static AnonymousCredentialsProvider create() {
@Override
public AwsCredentials resolveCredentials() {
- return AwsBasicCredentials.ANONYMOUS_CREDENTIALS;
+ return AwsBasicCredentials.builder()
+ .validateCredentials(false)
+ .providerName(PROVIDER_NAME)
+ .build();
}
@Override
public String toString() {
- return ToString.create("AnonymousCredentialsProvider");
+ return ToString.create(PROVIDER_NAME);
}
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsBasicCredentials.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsBasicCredentials.java
index 1c8b32cd928e..52c2ec149ad6 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsBasicCredentials.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsBasicCredentials.java
@@ -18,11 +18,15 @@
import static software.amazon.awssdk.utils.StringUtils.trimToNull;
import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
import software.amazon.awssdk.annotations.Immutable;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
+import software.amazon.awssdk.utils.builder.CopyableBuilder;
+import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
/**
* Provides access to the AWS credentials used for accessing services: AWS access key ID and secret access key. These
@@ -36,17 +40,31 @@
*/
@Immutable
@SdkPublicApi
-public final class AwsBasicCredentials implements AwsCredentials {
+public final class AwsBasicCredentials implements AwsCredentials,
+ ToCopyableBuilder {
/**
* A set of AWS credentials without an access key or secret access key, indicating that anonymous access should be used.
- *
- * This should be accessed via {@link AnonymousCredentialsProvider#resolveCredentials()}.
*/
+ // TODO(sra-identity-and-auth): Check if this static member can be removed after cleanup
@SdkInternalApi
- static final AwsBasicCredentials ANONYMOUS_CREDENTIALS = new AwsBasicCredentials(null, null, false);
+ static final AwsBasicCredentials ANONYMOUS_CREDENTIALS = builder().validateCredentials(false).build();
private final String accessKeyId;
private final String secretAccessKey;
+ private final boolean validateCredentials;
+ private final String providerName;
+
+ private AwsBasicCredentials(Builder builder) {
+ this.accessKeyId = trimToNull(builder.accessKeyId);
+ this.secretAccessKey = trimToNull(builder.secretAccessKey);
+ this.validateCredentials = builder.validateCredentials;
+ this.providerName = builder.providerName;
+
+ if (builder.validateCredentials) {
+ Validate.notNull(this.accessKeyId, "Access key ID cannot be blank.");
+ Validate.notNull(this.secretAccessKey, "Secret access key cannot be blank.");
+ }
+ }
/**
* Constructs a new credentials object, with the specified AWS access key and AWS secret key.
@@ -55,17 +73,14 @@ public final class AwsBasicCredentials implements AwsCredentials {
* @param secretAccessKey The AWS secret access key, used to authenticate the user interacting with AWS.
*/
protected AwsBasicCredentials(String accessKeyId, String secretAccessKey) {
- this(accessKeyId, secretAccessKey, true);
- }
-
- private AwsBasicCredentials(String accessKeyId, String secretAccessKey, boolean validateCredentials) {
this.accessKeyId = trimToNull(accessKeyId);
this.secretAccessKey = trimToNull(secretAccessKey);
+ this.validateCredentials = false;
+ this.providerName = null;
+ }
- if (validateCredentials) {
- Validate.notNull(this.accessKeyId, "Access key ID cannot be blank.");
- Validate.notNull(this.secretAccessKey, "Secret access key cannot be blank.");
- }
+ public static Builder builder() {
+ return new Builder();
}
/**
@@ -75,7 +90,9 @@ private AwsBasicCredentials(String accessKeyId, String secretAccessKey, boolean
* @param secretAccessKey The AWS secret access key, used to authenticate the user interacting with AWS.
* */
public static AwsBasicCredentials create(String accessKeyId, String secretAccessKey) {
- return new AwsBasicCredentials(accessKeyId, secretAccessKey);
+ return builder().accessKeyId(accessKeyId)
+ .secretAccessKey(secretAccessKey)
+ .build();
}
/**
@@ -94,10 +111,19 @@ public String secretAccessKey() {
return secretAccessKey;
}
+ /**
+ * The name of the identity provider that created this credential identity.
+ */
+ @Override
+ public Optional providerName() {
+ return Optional.ofNullable(providerName);
+ }
+
@Override
public String toString() {
return ToString.builder("AwsCredentials")
.add("accessKeyId", accessKeyId)
+ .add("providerName", providerName)
.build();
}
@@ -121,4 +147,69 @@ public int hashCode() {
hashCode = 31 * hashCode + Objects.hashCode(secretAccessKey());
return hashCode;
}
+
+ @Override
+ public Builder toBuilder() {
+ return builder().accessKeyId(accessKeyId)
+ .secretAccessKey(secretAccessKey)
+ .validateCredentials(validateCredentials)
+ .providerName(providerName);
+ }
+
+ @Override
+ public AwsBasicCredentials copy(Consumer super AwsBasicCredentials.Builder> modifier) {
+ return ToCopyableBuilder.super.copy(modifier);
+ }
+
+ /**
+ * A builder for creating an instance of {@link AwsBasicCredentials}. This can be created with the static
+ * {@link #builder()} method.
+ */
+ public static final class Builder implements CopyableBuilder {
+ private String accessKeyId;
+ private String secretAccessKey;
+ private String providerName;
+ private boolean validateCredentials = true;
+
+ private Builder() {
+ }
+
+ /**
+ * The AWS access key, used to identify the user interacting with services.
+ */
+ public Builder accessKeyId(String accessKeyId) {
+ this.accessKeyId = accessKeyId;
+ return this;
+ }
+
+ /**
+ * The AWS secret access key, used to authenticate the user interacting with services.
+ */
+ public Builder secretAccessKey(String secretAccessKey) {
+ this.secretAccessKey = secretAccessKey;
+ return this;
+ }
+
+ /**
+ * The name of the identity provider that created this credential identity.
+ */
+ public Builder providerName(String providerName) {
+ this.providerName = providerName;
+ return this;
+ }
+
+ /**
+ * Whether this class should verify that accessKeyId and secretAccessKey are not null.
+ * Used internally by the SDK for legacy reasons.
+ */
+ @SdkInternalApi
+ public Builder validateCredentials(Boolean validateCredentials) {
+ this.validateCredentials = validateCredentials;
+ return this;
+ }
+
+ public AwsBasicCredentials build() {
+ return new AwsBasicCredentials(this);
+ }
+ }
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsSessionCredentials.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsSessionCredentials.java
index a63c3e9e7b00..9eb8bd62e3fa 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsSessionCredentials.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsSessionCredentials.java
@@ -18,11 +18,14 @@
import java.time.Instant;
import java.util.Objects;
import java.util.Optional;
+import java.util.function.Consumer;
import software.amazon.awssdk.annotations.Immutable;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity;
import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
+import software.amazon.awssdk.utils.builder.CopyableBuilder;
+import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
/**
* A special type of {@link AwsCredentials} that provides a session token to be used in service authentication. Session
@@ -31,19 +34,21 @@
*/
@Immutable
@SdkPublicApi
-public final class AwsSessionCredentials implements AwsCredentials, AwsSessionCredentialsIdentity {
-
+public final class AwsSessionCredentials implements AwsCredentials, AwsSessionCredentialsIdentity,
+ ToCopyableBuilder {
private final String accessKeyId;
private final String secretAccessKey;
private final String sessionToken;
private final Instant expirationTime;
+ private final String providerName;
private AwsSessionCredentials(Builder builder) {
this.accessKeyId = Validate.paramNotNull(builder.accessKeyId, "accessKey");
this.secretAccessKey = Validate.paramNotNull(builder.secretAccessKey, "secretKey");
this.sessionToken = Validate.paramNotNull(builder.sessionToken, "sessionToken");
this.expirationTime = builder.expirationTime;
+ this.providerName = builder.providerName;
}
/**
@@ -93,14 +98,24 @@ public Optional expirationTime() {
* Retrieve the AWS session token. This token is retrieved from an AWS token service, and is used for authenticating that this
* user has received temporary permission to access some resource.
*/
+ @Override
public String sessionToken() {
return sessionToken;
}
+ /**
+ * The name of the identity provider that created this credential identity.
+ */
+ @Override
+ public Optional providerName() {
+ return Optional.ofNullable(providerName);
+ }
+
@Override
public String toString() {
return ToString.builder("AwsSessionCredentials")
.add("accessKeyId", accessKeyId())
+ .add("providerName", providerName)
.build();
}
@@ -130,15 +145,30 @@ public int hashCode() {
return hashCode;
}
+ @Override
+ public Builder toBuilder() {
+ return builder().accessKeyId(accessKeyId)
+ .secretAccessKey(secretAccessKey)
+ .sessionToken(sessionToken)
+ .expirationTime(expirationTime)
+ .providerName(providerName);
+ }
+
+ @Override
+ public AwsSessionCredentials copy(Consumer super Builder> modifier) {
+ return ToCopyableBuilder.super.copy(modifier);
+ }
+
/**
* A builder for creating an instance of {@link AwsSessionCredentials}. This can be created with the static
* {@link #builder()} method.
*/
- public static final class Builder {
+ public static final class Builder implements CopyableBuilder {
private String accessKeyId;
private String secretAccessKey;
private String sessionToken;
private Instant expirationTime;
+ private String providerName;
/**
* The AWS access key, used to identify the user interacting with services. Required.
@@ -175,6 +205,14 @@ public Builder expirationTime(Instant expirationTime) {
return this;
}
+ /**
+ * The name of the identity provider that created this credential identity.
+ */
+ public Builder providerName(String providerName) {
+ this.providerName = providerName;
+ return this;
+ }
+
public AwsSessionCredentials build() {
return new AwsSessionCredentials(this);
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProvider.java
index a728024db243..41df4d250738 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProvider.java
@@ -72,6 +72,7 @@
public final class ContainerCredentialsProvider
implements HttpCredentialsProvider,
ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "ContainerCredentialsProvider";
private static final Predicate IS_LOOPBACK_ADDRESS = InetAddress::isLoopbackAddress;
private static final Predicate ALLOWED_HOSTS_RULES = IS_LOOPBACK_ADDRESS;
private static final String HTTPS = "https";
@@ -97,7 +98,7 @@ private ContainerCredentialsProvider(BuilderImpl builder) {
this.endpoint = builder.endpoint;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
this.asyncThreadName = builder.asyncThreadName;
- this.httpCredentialsLoader = HttpCredentialsLoader.create();
+ this.httpCredentialsLoader = HttpCredentialsLoader.create(PROVIDER_NAME);
if (Boolean.TRUE.equals(builder.asyncCredentialUpdateEnabled)) {
Validate.paramNotBlank(builder.asyncThreadName, "asyncThreadName");
@@ -121,7 +122,7 @@ public static Builder builder() {
@Override
public String toString() {
- return ToString.create("ContainerCredentialsProvider");
+ return ToString.create(PROVIDER_NAME);
}
private RefreshResult refreshCredentials() {
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.java
index 965d68b29ec6..e05c24eed05a 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.java
@@ -28,6 +28,8 @@
@SdkPublicApi
public final class EnvironmentVariableCredentialsProvider extends SystemSettingsCredentialsProvider {
+ private static final String PROVIDER_NAME = "EnvironmentVariableCredentialsProvider";
+
private EnvironmentVariableCredentialsProvider() {
}
@@ -43,8 +45,13 @@ protected Optional loadSetting(SystemSetting setting) {
// CHECKSTYLE:ON
}
+ @Override
+ protected String provider() {
+ return PROVIDER_NAME;
+ }
+
@Override
public String toString() {
- return ToString.create("EnvironmentVariableCredentialsProvider");
+ return ToString.create(PROVIDER_NAME);
}
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.java
index db84a1b13ecf..72c825c9fdcf 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.java
@@ -68,8 +68,8 @@ public final class InstanceProfileCredentialsProvider
implements HttpCredentialsProvider,
ToCopyableBuilder {
private static final Logger log = Logger.loggerFor(InstanceProfileCredentialsProvider.class);
+ private static final String PROVIDER_NAME = "InstanceProfileCredentialsProvider";
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";
private static final String EC2_METADATA_TOKEN_TTL_HEADER = "x-aws-ec2-metadata-token-ttl-seconds";
@@ -103,7 +103,7 @@ private InstanceProfileCredentialsProvider(BuilderImpl builder) {
this.profileName = Optional.ofNullable(builder.profileName)
.orElseGet(ProfileFileSystemSetting.AWS_PROFILE::getStringValueOrThrow);
- this.httpCredentialsLoader = HttpCredentialsLoader.create();
+ this.httpCredentialsLoader = HttpCredentialsLoader.create(PROVIDER_NAME);
this.configProvider =
Ec2MetadataConfigProvider.builder()
.profileFile(profileFile)
@@ -203,7 +203,7 @@ public void close() {
@Override
public String toString() {
- return ToString.create("InstanceProfileCredentialsProvider");
+ return ToString.create(PROVIDER_NAME);
}
private ResourcesEndpointProvider createEndpointProvider() {
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProvider.java
index 3e7be883aa82..6bac35476e1a 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProvider.java
@@ -64,6 +64,7 @@ public final class ProcessCredentialsProvider
implements AwsCredentialsProvider,
SdkAutoCloseable,
ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "ProcessCredentialsProvider";
private static final JsonNodeParser PARSER = JsonNodeParser.builder()
.removeErrorLocations(true)
.build();
@@ -170,11 +171,18 @@ private AwsCredentials credentials(JsonNode credentialsJson) {
Validate.notEmpty(accessKeyId, "AccessKeyId cannot be empty.");
Validate.notEmpty(secretAccessKey, "SecretAccessKey cannot be empty.");
- if (sessionToken != null) {
- return AwsSessionCredentials.create(accessKeyId, secretAccessKey, sessionToken);
- } else {
- return AwsBasicCredentials.create(accessKeyId, secretAccessKey);
- }
+ return sessionToken != null ?
+ AwsSessionCredentials.builder()
+ .accessKeyId(accessKeyId)
+ .secretAccessKey(secretAccessKey)
+ .sessionToken(sessionToken)
+ .providerName(PROVIDER_NAME)
+ .build() :
+ AwsBasicCredentials.builder()
+ .accessKeyId(accessKeyId)
+ .secretAccessKey(secretAccessKey)
+ .providerName(PROVIDER_NAME)
+ .build();
}
/**
@@ -307,7 +315,7 @@ public ProcessCredentialsProvider build() {
@Override
public String toString() {
- return ToString.builder("ProcessCredentialsProvider")
+ return ToString.builder(PROVIDER_NAME)
.add("cmd", executableCommand)
.build();
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProvider.java
index aa67c4dd68b4..7e340f634969 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProvider.java
@@ -24,10 +24,22 @@
*/
@SdkPublicApi
public final class StaticCredentialsProvider implements AwsCredentialsProvider {
+ private static final String PROVIDER_NAME = "StaticCredentialsProvider";
private final AwsCredentials credentials;
private StaticCredentialsProvider(AwsCredentials credentials) {
- this.credentials = Validate.notNull(credentials, "Credentials must not be null.");
+ Validate.notNull(credentials, "Credentials must not be null.");
+ this.credentials = withProviderName(credentials);
+ }
+
+ private AwsCredentials withProviderName(AwsCredentials credentials) {
+ if (credentials instanceof AwsBasicCredentials) {
+ return ((AwsBasicCredentials) credentials).copy(c -> c.providerName(PROVIDER_NAME));
+ }
+ if (credentials instanceof AwsSessionCredentials) {
+ return ((AwsSessionCredentials) credentials).copy(c -> c.providerName(PROVIDER_NAME));
+ }
+ return credentials;
}
/**
@@ -44,7 +56,7 @@ public AwsCredentials resolveCredentials() {
@Override
public String toString() {
- return ToString.builder("StaticCredentialsProvider")
+ return ToString.builder(PROVIDER_NAME)
.add("credentials", credentials)
.build();
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/SystemPropertyCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/SystemPropertyCredentialsProvider.java
index 135b6ce88565..d2b5a93973eb 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/SystemPropertyCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/SystemPropertyCredentialsProvider.java
@@ -28,6 +28,8 @@
@SdkPublicApi
public final class SystemPropertyCredentialsProvider extends SystemSettingsCredentialsProvider {
+ private static final String PROVIDER_NAME = "SystemSettingsCredentialsProvider";
+
private SystemPropertyCredentialsProvider() {
}
@@ -43,8 +45,13 @@ protected Optional loadSetting(SystemSetting setting) {
// CHECKSTYLE:ON
}
+ @Override
+ protected String provider() {
+ return PROVIDER_NAME;
+ }
+
@Override
public String toString() {
- return ToString.create("SystemPropertyCredentialsProvider");
+ return ToString.create(PROVIDER_NAME);
}
}
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/HttpCredentialsLoader.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/HttpCredentialsLoader.java
index 77a8c6ddb231..507ae7c6f44f 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/HttpCredentialsLoader.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/HttpCredentialsLoader.java
@@ -45,11 +45,14 @@ public final class HttpCredentialsLoader {
private static final Pattern TRAILING_ZERO_OFFSET_TIME_PATTERN = Pattern.compile("\\+0000$");
- private HttpCredentialsLoader() {
+ private final String providerName;
+
+ private HttpCredentialsLoader(String providerName) {
+ this.providerName = providerName;
}
- public static HttpCredentialsLoader create() {
- return new HttpCredentialsLoader();
+ public static HttpCredentialsLoader create(String providerName) {
+ return new HttpCredentialsLoader(providerName);
}
public LoadedCredentials loadCredentials(ResourcesEndpointProvider endpoint) {
@@ -68,7 +71,8 @@ public LoadedCredentials loadCredentials(ResourcesEndpointProvider endpoint) {
return new LoadedCredentials(accessKey.text(),
secretKey.text(),
token != null ? token.text() : null,
- expiration != null ? expiration.text() : null);
+ expiration != null ? expiration.text() : null,
+ providerName);
} catch (SdkClientException e) {
throw e;
} catch (RuntimeException | IOException e) {
@@ -84,20 +88,29 @@ public static final class LoadedCredentials {
private final String secretKey;
private final String token;
private final Instant expiration;
+ private final String providerName;
- private LoadedCredentials(String accessKeyId, String secretKey, String token, String expiration) {
+ private LoadedCredentials(String accessKeyId, String secretKey, String token, String expiration, String providerName) {
this.accessKeyId = Validate.paramNotBlank(accessKeyId, "accessKeyId");
this.secretKey = Validate.paramNotBlank(secretKey, "secretKey");
this.token = token;
this.expiration = expiration == null ? null : parseExpiration(expiration);
+ this.providerName = providerName;
}
public AwsCredentials getAwsCredentials() {
- if (token == null) {
- return AwsBasicCredentials.create(accessKeyId, secretKey);
- } else {
- return AwsSessionCredentials.create(accessKeyId, secretKey, token);
- }
+ return token != null ?
+ AwsSessionCredentials.builder()
+ .accessKeyId(accessKeyId)
+ .secretAccessKey(secretKey)
+ .sessionToken(token)
+ .providerName(providerName)
+ .build() :
+ AwsBasicCredentials.builder()
+ .accessKeyId(accessKeyId)
+ .secretAccessKey(secretKey)
+ .providerName(providerName)
+ .build();
}
public Optional getExpiration() {
diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/SystemSettingsCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/SystemSettingsCredentialsProvider.java
index 9c4a642c251c..1f980b0b358d 100644
--- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/SystemSettingsCredentialsProvider.java
+++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/internal/SystemSettingsCredentialsProvider.java
@@ -43,6 +43,7 @@
*/
@SdkInternalApi
public abstract class SystemSettingsCredentialsProvider implements AwsCredentialsProvider {
+
@Override
public AwsCredentials resolveCredentials() {
String accessKey = trim(loadSetting(SdkSystemSetting.AWS_ACCESS_KEY_ID).orElse(null));
@@ -67,12 +68,23 @@ public AwsCredentials resolveCredentials() {
.build();
}
- return StringUtils.isBlank(sessionToken) ? AwsBasicCredentials.create(accessKey, secretKey)
- : AwsSessionCredentials.create(accessKey, secretKey, sessionToken);
+ return StringUtils.isBlank(sessionToken) ? AwsBasicCredentials.builder()
+ .accessKeyId(accessKey)
+ .secretAccessKey(secretKey)
+ .providerName(provider())
+ .build()
+ : AwsSessionCredentials.builder()
+ .accessKeyId(accessKey)
+ .secretAccessKey(secretKey)
+ .sessionToken(sessionToken)
+ .providerName(provider())
+ .build();
}
/**
* Implemented by child classes to load the requested setting.
*/
protected abstract Optional loadSetting(SystemSetting setting);
+
+ protected abstract String provider();
}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProviderTest.java
new file mode 100644
index 000000000000..a2e12c9d81b8
--- /dev/null
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProviderTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.auth.credentials;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class AnonymousCredentialsProviderTest {
+
+ @Test
+ void resolveCredentials_returnsAnonymousCredentials() {
+ AwsCredentials credentials = AnonymousCredentialsProvider.create().resolveCredentials();
+ assertThat(credentials.accessKeyId()).isNull();
+ assertThat(credentials.secretAccessKey()).isNull();
+ assertThat(credentials.providerName()).isPresent().contains("AnonymousCredentialsProvider");
+ }
+}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProviderTest.java
index 3de68e16a4c9..0f20fe51a5a6 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProviderTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProviderTest.java
@@ -23,10 +23,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static software.amazon.awssdk.core.SdkSystemSetting.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI;
-import static software.amazon.awssdk.utils.FunctionalUtils.invokeSafely;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import java.net.URI;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.junit.AfterClass;
import org.junit.Before;
@@ -34,7 +32,6 @@
import org.junit.Test;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.core.util.SdkUserAgent;
-import software.amazon.awssdk.regions.util.ResourcesEndpointProvider;
import software.amazon.awssdk.testutils.EnvironmentVariableHelper;
/**
@@ -89,6 +86,7 @@ public void testGetCredentialsReturnsValidResponseFromEcsEndpoint() {
assertThat(credentials.accessKeyId()).isEqualTo(ACCESS_KEY_ID);
assertThat(credentials.secretAccessKey()).isEqualTo(SECRET_ACCESS_KEY);
assertThat(credentials.sessionToken()).isEqualTo(TOKEN);
+ assertThat(credentials.providerName()).isPresent().contains("ContainerCredentialsProvider");
}
/**
@@ -131,20 +129,4 @@ private String getSuccessfulBody() {
"\"Token\":\"TOKEN_TOKEN_TOKEN\"," +
"\"Expiration\":\"3000-05-03T04:55:54Z\"}";
}
-
- /**
- * Dummy CredentialsPathProvider that overrides the endpoint and connects to the WireMock server.
- */
- private static class TestCredentialsEndpointProvider implements ResourcesEndpointProvider {
- private final String host;
-
- public TestCredentialsEndpointProvider(String host) {
- this.host = host;
- }
-
- @Override
- public URI endpoint() {
- return invokeSafely(() -> new URI(host + CREDENTIALS_PATH));
- }
- }
}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/HttpCredentialsLoaderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/HttpCredentialsLoaderTest.java
index afa1ec0fa4df..09d9e0b6a296 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/HttpCredentialsLoaderTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/HttpCredentialsLoaderTest.java
@@ -27,8 +27,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
-import java.time.Duration;
-import java.time.Instant;
import java.util.Date;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@@ -48,6 +46,7 @@ public class HttpCredentialsLoaderTest {
private static final long ONE_MINUTE = 1000L * 60;
/** Environment variable name for the AWS ECS Container credentials path. */
private static final String CREDENTIALS_PATH = "/dummy/credentials/path";
+ private static final String PROVIDER_NAME = "HttpCredentialsProvider";
private static String successResponse;
private static String successResponseWithInvalidBody;
@@ -70,7 +69,7 @@ public static void setup() throws IOException {
public void testLoadCredentialsParsesJsonResponseProperly() {
stubForSuccessResponseWithCustomBody(successResponse);
- HttpCredentialsLoader credentialsProvider = HttpCredentialsLoader.create();
+ HttpCredentialsLoader credentialsProvider = HttpCredentialsLoader.create(PROVIDER_NAME);
AwsSessionCredentials credentials = (AwsSessionCredentials) credentialsProvider.loadCredentials(testEndpointProvider())
.getAwsCredentials();
@@ -88,7 +87,7 @@ public void testLoadCredentialsThrowsAceWhenClientResponseDontHaveKeys() {
// Stub for success response but without keys in the response body
stubForSuccessResponseWithCustomBody(successResponseWithInvalidBody);
- HttpCredentialsLoader credentialsProvider = HttpCredentialsLoader.create();
+ HttpCredentialsLoader credentialsProvider = HttpCredentialsLoader.create(PROVIDER_NAME);
assertThatExceptionOfType(SdkClientException.class).isThrownBy(() -> credentialsProvider.loadCredentials(testEndpointProvider()))
.withMessage("Failed to load credentials from metadata service.");
@@ -102,7 +101,7 @@ public void testLoadCredentialsThrowsAceWhenClientResponseDontHaveKeys() {
public void testNoMetadataService() throws Exception {
stubForErrorResponse();
- HttpCredentialsLoader credentialsProvider = HttpCredentialsLoader.create();
+ HttpCredentialsLoader credentialsProvider = HttpCredentialsLoader.create(PROVIDER_NAME);
// When there are no credentials, the provider should throw an exception if we can't connect
assertThatExceptionOfType(SdkClientException.class).isThrownBy(() -> credentialsProvider.loadCredentials(testEndpointProvider()));
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProviderTest.java
index 05db14c7a2fd..c54a2ca3d4d1 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProviderTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProviderTest.java
@@ -131,10 +131,13 @@ private void verifyImdsCallInsecure() {
}
@Test
- public void resolveCredentials_queriesTokenResource_includesTokenInCredentialsRequests() {
+ public void resolveCredentials_usesTokenByDefault() {
stubSecureCredentialsResponse(aResponse().withBody(STUB_CREDENTIALS));
InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider.builder().build();
- provider.resolveCredentials();
+ AwsCredentials credentials = provider.resolveCredentials();
+ assertThat(credentials.accessKeyId()).isEqualTo("ACCESS_KEY_ID");
+ assertThat(credentials.secretAccessKey()).isEqualTo("SECRET_ACCESS_KEY");
+ assertThat(credentials.providerName()).isPresent().contains("InstanceProfileCredentialsProvider");
verifyImdsCallWithToken();
}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProviderTest.java
index 5d6e36e411b4..d794421c40bf 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProviderTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProcessCredentialsProviderTest.java
@@ -16,39 +16,31 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.Assert.assertNotNull;
+import static software.amazon.awssdk.auth.credentials.internal.ProcessCredentialsTestUtils.copyErrorCaseProcessCredentialsScript;
+import static software.amazon.awssdk.auth.credentials.internal.ProcessCredentialsTestUtils.copyHappyCaseProcessCredentialsScript;
import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UncheckedIOException;
import java.time.Duration;
import java.time.Instant;
-import org.assertj.core.api.Assertions;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
import software.amazon.awssdk.utils.DateUtils;
-import software.amazon.awssdk.utils.IoUtils;
-import software.amazon.awssdk.utils.Platform;
-public class ProcessCredentialsProviderTest {
+class ProcessCredentialsProviderTest {
private static final String PROCESS_RESOURCE_PATH = "/resources/process/";
private static final String RANDOM_SESSION_TOKEN = "RANDOM_TOKEN";
private static String scriptLocation;
private static String errorScriptLocation;
- @BeforeClass
+ @BeforeAll
public static void setup() {
scriptLocation = copyHappyCaseProcessCredentialsScript();
errorScriptLocation = copyErrorCaseProcessCredentialsScript();
}
- @AfterClass
+ @AfterAll
public static void teardown() {
if (scriptLocation != null && !new File(scriptLocation).delete()) {
throw new IllegalStateException("Failed to delete file: " + scriptLocation);
@@ -60,20 +52,21 @@ public static void teardown() {
}
@Test
- public void staticCredentialsCanBeLoaded() {
+ void staticCredentialsCanBeLoaded() {
AwsCredentials credentials =
ProcessCredentialsProvider.builder()
.command(scriptLocation + " accessKeyId secretAccessKey")
.build()
.resolveCredentials();
- Assert.assertFalse(credentials instanceof AwsSessionCredentials);
- Assert.assertEquals("accessKeyId", credentials.accessKeyId());
- Assert.assertEquals("secretAccessKey", credentials.secretAccessKey());
+ assertThat(credentials).isInstanceOf(AwsBasicCredentials.class);
+ assertThat(credentials.accessKeyId()).isEqualTo("accessKeyId");
+ assertThat(credentials.secretAccessKey()).isEqualTo("secretAccessKey");
+ assertThat(credentials.providerName()).isPresent().contains("ProcessCredentialsProvider");
}
@Test
- public void sessionCredentialsCanBeLoaded() {
+ void sessionCredentialsCanBeLoaded() {
ProcessCredentialsProvider credentialsProvider =
ProcessCredentialsProvider.builder()
.command(scriptLocation + " accessKeyId secretAccessKey sessionToken " +
@@ -83,17 +76,17 @@ public void sessionCredentialsCanBeLoaded() {
AwsCredentials credentials = credentialsProvider.resolveCredentials();
- Assert.assertTrue(credentials instanceof AwsSessionCredentials);
+ assertThat(credentials).isInstanceOf(AwsSessionCredentials.class);
AwsSessionCredentials sessionCredentials = (AwsSessionCredentials) credentials;
- Assert.assertEquals("accessKeyId", sessionCredentials.accessKeyId());
- Assert.assertEquals("secretAccessKey", sessionCredentials.secretAccessKey());
- assertNotNull(sessionCredentials.sessionToken());
+ assertThat(credentials.accessKeyId()).isEqualTo("accessKeyId");
+ assertThat(credentials.secretAccessKey()).isEqualTo("secretAccessKey");
+ assertThat(sessionCredentials.sessionToken()).isNotNull();
}
@Test
- public void resultsAreCached() {
+ void resultsAreCached() {
ProcessCredentialsProvider credentialsProvider =
ProcessCredentialsProvider.builder()
.command(scriptLocation + " accessKeyId secretAccessKey sessionToken " +
@@ -103,11 +96,11 @@ public void resultsAreCached() {
AwsCredentials request1 = credentialsProvider.resolveCredentials();
AwsCredentials request2 = credentialsProvider.resolveCredentials();
- Assert.assertEquals(request1, request2);
+ assertThat(request1).isEqualTo(request2);
}
@Test
- public void expirationBufferOverrideIsApplied() {
+ void expirationBufferOverrideIsApplied() {
ProcessCredentialsProvider credentialsProvider =
ProcessCredentialsProvider.builder()
.command(String.format("%s accessKeyId secretAccessKey %s %s",
@@ -120,11 +113,11 @@ public void expirationBufferOverrideIsApplied() {
AwsCredentials request1 = credentialsProvider.resolveCredentials();
AwsCredentials request2 = credentialsProvider.resolveCredentials();
- Assert.assertNotEquals(request1, request2);
+ assertThat(request1).isNotEqualTo(request2);
}
@Test
- public void processFailed_shouldContainErrorMessage() {
+ void processFailed_shouldContainErrorMessage() {
ProcessCredentialsProvider credentialsProvider =
ProcessCredentialsProvider.builder()
.command(errorScriptLocation)
@@ -137,7 +130,7 @@ public void processFailed_shouldContainErrorMessage() {
}
@Test
- public void lackOfExpirationIsCachedForever() {
+ void lackOfExpirationIsCachedForever() {
ProcessCredentialsProvider credentialsProvider =
ProcessCredentialsProvider.builder()
.command(scriptLocation + " accessKeyId secretAccessKey sessionToken")
@@ -147,20 +140,21 @@ public void lackOfExpirationIsCachedForever() {
AwsCredentials request1 = credentialsProvider.resolveCredentials();
AwsCredentials request2 = credentialsProvider.resolveCredentials();
- Assert.assertEquals(request1, request2);
+ assertThat(request1).isEqualTo(request2);
}
- @Test(expected = IllegalStateException.class)
- public void processOutputLimitIsEnforced() {
- ProcessCredentialsProvider.builder()
- .command(scriptLocation + " accessKeyId secretAccessKey")
- .processOutputLimit(1)
- .build()
- .resolveCredentials();
+ @Test
+ void processOutputLimitIsEnforced() {
+ ProcessCredentialsProvider credentialsProvider =
+ ProcessCredentialsProvider.builder()
+ .command(scriptLocation + " accessKeyId secretAccessKey")
+ .processOutputLimit(1)
+ .build();
+ assertThatThrownBy(credentialsProvider::resolveCredentials).isInstanceOf(IllegalStateException.class);
}
@Test
- public void processOutputLimitDefaultPassesLargeInput() {
+ void processOutputLimitDefaultPassesLargeInput() {
String LONG_SESSION_TOKEN = "lYzvmByqdS1E69QQVEavDDHabQ2GuYKYABKRA4xLbAXpdnFtV030UH4" +
"bQoZWCDcfADFvBwBm3ixEFTYMjn5XQozpFV2QAsWHirCVcEJ5DC60KPCNBcDi4KLNJfbsp3r6kKTOmYOeqhEyiC4emDX33X2ppZsa5" +
@@ -181,12 +175,12 @@ public void processOutputLimitDefaultPassesLargeInput() {
AwsSessionCredentials sessionCredentials = (AwsSessionCredentials) credentialsProvider.resolveCredentials();
- Assertions.assertThat(sessionCredentials.accessKeyId()).isEqualTo("accessKeyId");
- Assertions.assertThat(sessionCredentials.sessionToken()).isNotNull();
+ assertThat(sessionCredentials.accessKeyId()).isEqualTo("accessKeyId");
+ assertThat(sessionCredentials.sessionToken()).isNotNull();
}
@Test
- public void closeDoesNotRaise() {
+ void closeDoesNotRaise() {
ProcessCredentialsProvider credentialsProvider =
ProcessCredentialsProvider.builder()
.command(scriptLocation + " accessKeyId secretAccessKey sessionToken")
@@ -194,47 +188,4 @@ public void closeDoesNotRaise() {
credentialsProvider.resolveCredentials();
credentialsProvider.close();
}
-
- public static String copyHappyCaseProcessCredentialsScript() {
- String scriptClasspathFilename = Platform.isWindows() ? "windows-credentials-script.bat"
- : "linux-credentials-script.sh";
-
- return copyProcessCredentialsScript(scriptClasspathFilename);
- }
-
- public static String copyErrorCaseProcessCredentialsScript() {
- String scriptClasspathFilename = Platform.isWindows() ? "windows-credentials-error-script.bat"
- : "linux-credentials-error-script.sh";
-
- return copyProcessCredentialsScript(scriptClasspathFilename);
- }
-
- public static String copyProcessCredentialsScript(String scriptClasspathFilename) {
- String scriptClasspathLocation = PROCESS_RESOURCE_PATH + scriptClasspathFilename;
-
- InputStream scriptInputStream = null;
- OutputStream scriptOutputStream = null;
-
- try {
- scriptInputStream = ProcessCredentialsProviderTest.class.getResourceAsStream(scriptClasspathLocation);
-
- File scriptFileOnDisk = File.createTempFile("ProcessCredentialsProviderTest", scriptClasspathFilename);
- scriptFileOnDisk.deleteOnExit();
-
- if (!scriptFileOnDisk.setExecutable(true)) {
- throw new IllegalStateException("Could not make " + scriptFileOnDisk + " executable.");
- }
-
- scriptOutputStream = new FileOutputStream(scriptFileOnDisk);
-
- IoUtils.copy(scriptInputStream, scriptOutputStream);
-
- return scriptFileOnDisk.getAbsolutePath();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } finally {
- IoUtils.closeQuietly(scriptInputStream, null);
- IoUtils.closeQuietly(scriptOutputStream, null);
- }
- }
}
\ No newline at end of file
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProviderTest.java
index 19c99236eee6..8254e04c0ab1 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProviderTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/StaticCredentialsProviderTest.java
@@ -15,28 +15,32 @@
package software.amazon.awssdk.auth.credentials;
-import static org.junit.Assert.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-public class StaticCredentialsProviderTest {
+class StaticCredentialsProviderTest {
@Test
- public void getAwsCredentials_ReturnsSameCredentials() throws Exception {
- final AwsCredentials credentials = new AwsBasicCredentials("akid", "skid");
- final AwsCredentials actualCredentials =
- StaticCredentialsProvider.create(credentials).resolveCredentials();
- assertEquals(credentials, actualCredentials);
+ void getAwsCredentials_ReturnsSameCredentials() {
+ AwsCredentials credentials = new AwsBasicCredentials("akid", "skid");
+ AwsCredentials actualCredentials = StaticCredentialsProvider.create(credentials).resolveCredentials();
+ assertThat(credentials).isEqualTo(actualCredentials);
+ assertThat(credentials.providerName()).isNotPresent();
+ assertThat(actualCredentials.providerName()).isPresent();
}
@Test
- public void getSessionAwsCredentials_ReturnsSameCredentials() throws Exception {
- final AwsSessionCredentials credentials = AwsSessionCredentials.create("akid", "skid", "token");
- final AwsCredentials actualCredentials = StaticCredentialsProvider.create(credentials).resolveCredentials();
- assertEquals(credentials, actualCredentials);
+ void getSessionAwsCredentials_ReturnsSameCredentials() {
+ AwsSessionCredentials credentials = AwsSessionCredentials.create("akid", "skid", "token");
+ AwsCredentials actualCredentials = StaticCredentialsProvider.create(credentials).resolveCredentials();
+ assertThat(credentials).isEqualTo(actualCredentials);
+ assertThat(credentials.providerName()).isNotPresent();
+ assertThat(actualCredentials.providerName()).isPresent();
}
- @Test(expected = RuntimeException.class)
- public void nullCredentials_ThrowsIllegalArgumentException() {
- StaticCredentialsProvider.create(null);
+ @Test
+ void nullCredentials_ThrowsRuntimeException() {
+ assertThatThrownBy(() -> StaticCredentialsProvider.create(null)).isInstanceOf(RuntimeException.class);
}
}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/SystemSettingsCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/SystemSettingsCredentialsProviderTest.java
new file mode 100644
index 000000000000..615bcb63f1d9
--- /dev/null
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/SystemSettingsCredentialsProviderTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.auth.credentials;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.core.SdkSystemSetting;
+import software.amazon.awssdk.testutils.EnvironmentVariableHelper;
+
+class SystemSettingsCredentialsProviderTest {
+
+ private static final EnvironmentVariableHelper ENVIRONMENT_VARIABLE_HELPER = new EnvironmentVariableHelper();
+
+ @BeforeAll
+ public static void methodSetup() {
+ System.setProperty(SdkSystemSetting.AWS_ACCESS_KEY_ID.property(), "akid1");
+ System.setProperty(SdkSystemSetting.AWS_SECRET_ACCESS_KEY.property(), "skid1");
+ ENVIRONMENT_VARIABLE_HELPER.set(SdkSystemSetting.AWS_ACCESS_KEY_ID.environmentVariable(), "akid2");
+ ENVIRONMENT_VARIABLE_HELPER.set(SdkSystemSetting.AWS_SECRET_ACCESS_KEY.environmentVariable(), "skid2");
+ }
+
+ @AfterAll
+ public static void teardown() {
+ System.clearProperty(SdkSystemSetting.AWS_ACCESS_KEY_ID.property());
+ System.clearProperty(SdkSystemSetting.AWS_SECRET_ACCESS_KEY.property());
+ ENVIRONMENT_VARIABLE_HELPER.reset();
+ }
+
+ @Test
+ void systemPropertyCredentialsProvider_resolveCredentials_returnsCredentialsWithProvider() {
+ AwsCredentials credentials = SystemPropertyCredentialsProvider.create().resolveCredentials();
+ assertThat(credentials.accessKeyId()).isEqualTo("akid1");
+ assertThat(credentials.secretAccessKey()).isEqualTo("skid1");
+ assertThat(credentials.providerName()).isPresent().contains("SystemSettingsCredentialsProvider");
+ }
+
+ @Test
+ void environmentVariableCredentialsProvider_resolveCredentials_returnsCredentialsWithProvider() {
+ AwsCredentials credentials = EnvironmentVariableCredentialsProvider.create().resolveCredentials();
+ assertThat(credentials.accessKeyId()).isEqualTo("akid2");
+ assertThat(credentials.secretAccessKey()).isEqualTo("skid2");
+ assertThat(credentials.providerName()).isPresent().contains("EnvironmentVariableCredentialsProvider");
+ }
+}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsBasicCredentialsTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsBasicCredentialsTest.java
new file mode 100644
index 000000000000..9986118deda3
--- /dev/null
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsBasicCredentialsTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.auth.credentials.internal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+
+class AwsBasicCredentialsTest {
+
+ private static final String ACCESS_KEY_ID = "accessKeyId";
+ private static final String SECRET_ACCESS_KEY = "secretAccessKey";
+ private static final String PROVIDER_NAME = "StaticCredentialsProvider";
+
+ @Test
+ void equalsHashcode() {
+ EqualsVerifier.forClass(AwsBasicCredentials.class)
+ .withIgnoredFields("validateCredentials")
+ .withIgnoredFields("providerName")
+ .verify();
+ }
+
+ @Test
+ void emptyBuilder_ThrowsException() {
+ assertThrows(NullPointerException.class, () -> AwsBasicCredentials.builder().build());
+ }
+
+ @Test
+ void builderMissingAccessKeyId_ThrowsException() {
+ assertThrows(NullPointerException.class, () -> AwsBasicCredentials.builder()
+ .secretAccessKey(SECRET_ACCESS_KEY)
+ .build());
+ }
+
+ @Test
+ void create_isSuccessful() {
+ AwsBasicCredentials identity = AwsBasicCredentials.create(ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY);
+ assertEquals(ACCESS_KEY_ID, identity.accessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, identity.secretAccessKey());
+ }
+
+ @Test
+ void build_isSuccessful() {
+ AwsBasicCredentials identity = AwsBasicCredentials.builder()
+ .accessKeyId(ACCESS_KEY_ID)
+ .secretAccessKey(SECRET_ACCESS_KEY)
+ .build();
+ assertEquals(ACCESS_KEY_ID, identity.accessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, identity.secretAccessKey());
+ }
+
+ @Test
+ void copy_isSuccessful() {
+ AwsBasicCredentials identity = AwsBasicCredentials.builder()
+ .accessKeyId(ACCESS_KEY_ID)
+ .secretAccessKey(SECRET_ACCESS_KEY)
+ .build();
+ AwsBasicCredentials copy = identity.copy(c -> c.providerName(PROVIDER_NAME));
+ assertEquals(ACCESS_KEY_ID, copy.accessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, copy.secretAccessKey());
+ assertEquals(PROVIDER_NAME, copy.providerName().get());
+ }
+}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsSessionCredentialsTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsSessionCredentialsTest.java
index e0ccc19c5954..cb3a62600494 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsSessionCredentialsTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/AwsSessionCredentialsTest.java
@@ -22,24 +22,27 @@
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
-public class AwsSessionCredentialsTest {
+class AwsSessionCredentialsTest {
private static final String ACCESS_KEY_ID = "accessKeyId";
private static final String SECRET_ACCESS_KEY = "secretAccessKey";
private static final String SESSION_TOKEN = "sessionToken";
+ private static final String PROVIDER_NAME = "StaticCredentialsProvider";
- public void equalsHashcode() {
+ @Test
+ void equalsHashcode() {
EqualsVerifier.forClass(AwsSessionCredentials.class)
+ .withIgnoredFields("providerName")
.verify();
}
@Test
- public void emptyBuilder_ThrowsException() {
+ void emptyBuilder_ThrowsException() {
assertThrows(NullPointerException.class, () -> AwsSessionCredentials.builder().build());
}
@Test
- public void builderMissingSessionToken_ThrowsException() {
+ void builderMissingSessionToken_ThrowsException() {
assertThrows(NullPointerException.class, () -> AwsSessionCredentials.builder()
.accessKeyId(ACCESS_KEY_ID)
.secretAccessKey(SECRET_ACCESS_KEY)
@@ -47,7 +50,7 @@ public void builderMissingSessionToken_ThrowsException() {
}
@Test
- public void builderMissingAccessKeyId_ThrowsException() {
+ void builderMissingAccessKeyId_ThrowsException() {
assertThrows(NullPointerException.class, () -> AwsSessionCredentials.builder()
.secretAccessKey(SECRET_ACCESS_KEY)
.sessionToken(SESSION_TOKEN)
@@ -55,7 +58,7 @@ public void builderMissingAccessKeyId_ThrowsException() {
}
@Test
- public void create_isSuccessful() {
+ void create_isSuccessful() {
AwsSessionCredentials identity = AwsSessionCredentials.create(ACCESS_KEY_ID,
SECRET_ACCESS_KEY,
SESSION_TOKEN);
@@ -65,7 +68,7 @@ public void create_isSuccessful() {
}
@Test
- public void build_isSuccessful() {
+ void build_isSuccessful() {
AwsSessionCredentials identity = AwsSessionCredentials.builder()
.accessKeyId(ACCESS_KEY_ID)
.secretAccessKey(SECRET_ACCESS_KEY)
@@ -75,4 +78,18 @@ public void build_isSuccessful() {
assertEquals(SECRET_ACCESS_KEY, identity.secretAccessKey());
assertEquals(SESSION_TOKEN, identity.sessionToken());
}
+
+ @Test
+ void copy_isSuccessful() {
+ AwsSessionCredentials identity = AwsSessionCredentials.builder()
+ .accessKeyId(ACCESS_KEY_ID)
+ .secretAccessKey(SECRET_ACCESS_KEY)
+ .sessionToken(SESSION_TOKEN)
+ .build();
+ AwsSessionCredentials copy = identity.copy(c -> c.providerName(PROVIDER_NAME));
+ assertEquals(ACCESS_KEY_ID, copy.accessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, copy.secretAccessKey());
+ assertEquals(SESSION_TOKEN, copy.sessionToken());
+ assertEquals(PROVIDER_NAME, copy.providerName().get());
+ }
}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProcessCredentialsTestUtils.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProcessCredentialsTestUtils.java
new file mode 100644
index 000000000000..e42fe772fb4b
--- /dev/null
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProcessCredentialsTestUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.auth.credentials.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import software.amazon.awssdk.utils.IoUtils;
+import software.amazon.awssdk.utils.Platform;
+
+public final class ProcessCredentialsTestUtils {
+
+ private static final String PROCESS_RESOURCE_PATH = "/resources/process/";
+
+ private ProcessCredentialsTestUtils() {
+ }
+
+ public static String copyErrorCaseProcessCredentialsScript() {
+ String scriptClasspathFilename = Platform.isWindows() ? "windows-credentials-error-script.bat"
+ : "linux-credentials-error-script.sh";
+
+ return copyProcessCredentialsScript(scriptClasspathFilename);
+ }
+
+ public static String copyHappyCaseProcessCredentialsScript() {
+ String scriptClasspathFilename = Platform.isWindows() ? "windows-credentials-script.bat"
+ : "linux-credentials-script.sh";
+
+ return copyProcessCredentialsScript(scriptClasspathFilename);
+ }
+
+ public static String copyProcessCredentialsScript(String scriptClasspathFilename) {
+ InputStream scriptInputStream = null;
+ OutputStream scriptOutputStream = null;
+
+ try {
+ scriptInputStream = ProcessCredentialsTestUtils.class
+ .getResourceAsStream(PROCESS_RESOURCE_PATH + scriptClasspathFilename);
+
+ File scriptFileOnDisk = File.createTempFile("ProcessCredentialsProviderTest", scriptClasspathFilename);
+ scriptFileOnDisk.deleteOnExit();
+
+ if (!scriptFileOnDisk.setExecutable(true)) {
+ throw new IllegalStateException("Could not make " + scriptFileOnDisk + " executable.");
+ }
+
+ scriptOutputStream = Files.newOutputStream(scriptFileOnDisk.toPath());
+
+ IoUtils.copy(scriptInputStream, scriptOutputStream);
+
+ return scriptFileOnDisk.getAbsolutePath();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } finally {
+ IoUtils.closeQuietly(scriptInputStream, null);
+ IoUtils.closeQuietly(scriptOutputStream, null);
+ }
+ }
+}
diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProfileCredentialsUtilsTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProfileCredentialsUtilsTest.java
index 54d028c98dbb..ef95613e5efc 100644
--- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProfileCredentialsUtilsTest.java
+++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/internal/ProfileCredentialsUtilsTest.java
@@ -17,9 +17,9 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static software.amazon.awssdk.auth.credentials.internal.ProcessCredentialsTestUtils.copyHappyCaseProcessCredentialsScript;
import java.io.File;
-import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
@@ -32,9 +32,6 @@
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
-import software.amazon.awssdk.auth.credentials.ProcessCredentialsProviderTest;
-import software.amazon.awssdk.core.checksums.Algorithm;
-import software.amazon.awssdk.core.checksums.SdkChecksum;
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.profiles.ProfileProperty;
import software.amazon.awssdk.utils.StringInputStream;
@@ -44,7 +41,7 @@ public class ProfileCredentialsUtilsTest {
@BeforeAll
public static void setup() {
- scriptLocation = ProcessCredentialsProviderTest.copyHappyCaseProcessCredentialsScript();
+ scriptLocation = copyHappyCaseProcessCredentialsScript();
}
@AfterAll
diff --git a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentity.java b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentity.java
index d39e7eb53b2b..f738df91fcb0 100644
--- a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentity.java
+++ b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentity.java
@@ -42,6 +42,7 @@ public interface AwsCredentialsIdentity extends Identity {
*/
String secretAccessKey();
+
static Builder builder() {
return DefaultAwsCredentialsIdentity.builder();
}
@@ -69,6 +70,13 @@ interface Builder {
*/
Builder secretAccessKey(String secretAccessKey);
+ /**
+ * The name of the identity provider that created this credential identity.
+ */
+ default Builder providerName(String providerName) {
+ return this;
+ }
+
AwsCredentialsIdentity build();
}
}
diff --git a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentity.java b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentity.java
index 10e0ec0634ce..bf3ae020fbe0 100644
--- a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentity.java
+++ b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentity.java
@@ -66,6 +66,9 @@ interface Builder extends AwsCredentialsIdentity.Builder {
*/
Builder sessionToken(String sessionToken);
+ @Override
+ Builder providerName(String providerName);
+
@Override
AwsSessionCredentialsIdentity build();
}
diff --git a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/Identity.java b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/Identity.java
index 130fc9d67290..ea1e9fed091b 100644
--- a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/Identity.java
+++ b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/Identity.java
@@ -38,4 +38,13 @@ public interface Identity {
default Optional expirationTime() {
return Optional.empty();
}
+
+ /**
+ * The source that resolved this identity, normally an identity provider. Note that
+ * this string value would be set by an identity provider implementation and is
+ * intended to be used for for tracking purposes. Avoid building logic on its value.
+ */
+ default Optional providerName() {
+ return Optional.empty();
+ }
}
diff --git a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsCredentialsIdentity.java b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsCredentialsIdentity.java
index 7cca889709b1..2e38b32ded6a 100644
--- a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsCredentialsIdentity.java
+++ b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsCredentialsIdentity.java
@@ -16,6 +16,7 @@
package software.amazon.awssdk.identity.spi.internal;
import java.util.Objects;
+import java.util.Optional;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
import software.amazon.awssdk.utils.ToString;
@@ -26,10 +27,12 @@ public final class DefaultAwsCredentialsIdentity implements AwsCredentialsIdenti
private final String accessKeyId;
private final String secretAccessKey;
+ private final String providerName;
private DefaultAwsCredentialsIdentity(Builder builder) {
this.accessKeyId = builder.accessKeyId;
this.secretAccessKey = builder.secretAccessKey;
+ this.providerName = builder.providerName;
Validate.paramNotNull(accessKeyId, "accessKeyId");
Validate.paramNotNull(secretAccessKey, "secretAccessKey");
@@ -49,10 +52,16 @@ public String secretAccessKey() {
return secretAccessKey;
}
+ @Override
+ public Optional providerName() {
+ return Optional.ofNullable(providerName);
+ }
+
@Override
public String toString() {
return ToString.builder("AwsCredentialsIdentity")
.add("accessKeyId", accessKeyId)
+ .add("providerName", providerName)
.build();
}
@@ -80,6 +89,7 @@ public int hashCode() {
private static final class Builder implements AwsCredentialsIdentity.Builder {
private String accessKeyId;
private String secretAccessKey;
+ private String providerName;
private Builder() {
}
@@ -96,6 +106,12 @@ public Builder secretAccessKey(String secretAccessKey) {
return this;
}
+ @Override
+ public Builder providerName(String providerName) {
+ this.providerName = providerName;
+ return this;
+ }
+
@Override
public AwsCredentialsIdentity build() {
return new DefaultAwsCredentialsIdentity(this);
diff --git a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsSessionCredentialsIdentity.java b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsSessionCredentialsIdentity.java
index 067d490b3838..7b07dfb4f31c 100644
--- a/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsSessionCredentialsIdentity.java
+++ b/core/identity-spi/src/main/java/software/amazon/awssdk/identity/spi/internal/DefaultAwsSessionCredentialsIdentity.java
@@ -16,6 +16,7 @@
package software.amazon.awssdk.identity.spi.internal;
import java.util.Objects;
+import java.util.Optional;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity;
import software.amazon.awssdk.utils.ToString;
@@ -27,11 +28,13 @@ public final class DefaultAwsSessionCredentialsIdentity implements AwsSessionCre
private final String accessKeyId;
private final String secretAccessKey;
private final String sessionToken;
+ private final String providerName;
private DefaultAwsSessionCredentialsIdentity(Builder builder) {
this.accessKeyId = builder.accessKeyId;
this.secretAccessKey = builder.secretAccessKey;
this.sessionToken = builder.sessionToken;
+ this.providerName = builder.providerName;
Validate.paramNotNull(accessKeyId, "accessKeyId");
Validate.paramNotNull(secretAccessKey, "secretAccessKey");
@@ -57,10 +60,16 @@ public String sessionToken() {
return sessionToken;
}
+ @Override
+ public Optional providerName() {
+ return Optional.ofNullable(providerName);
+ }
+
@Override
public String toString() {
return ToString.builder("AwsSessionCredentialsIdentity")
.add("accessKeyId", accessKeyId)
+ .add("providerName", providerName)
.build();
}
@@ -91,6 +100,7 @@ private static final class Builder implements AwsSessionCredentialsIdentity.Buil
private String accessKeyId;
private String secretAccessKey;
private String sessionToken;
+ private String providerName;
private Builder() {
}
@@ -113,6 +123,12 @@ public Builder sessionToken(String sessionToken) {
return this;
}
+ @Override
+ public Builder providerName(String providerName) {
+ this.providerName = providerName;
+ return this;
+ }
+
@Override
public AwsSessionCredentialsIdentity build() {
return new DefaultAwsSessionCredentialsIdentity(this);
diff --git a/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentityTest.java b/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentityTest.java
index 33974427ab65..a75cfafa340f 100644
--- a/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentityTest.java
+++ b/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsCredentialsIdentityTest.java
@@ -30,6 +30,7 @@ public class AwsCredentialsIdentityTest {
@Test
public void equalsHashcode() {
EqualsVerifier.forClass(DefaultAwsCredentialsIdentity.class)
+ .withIgnoredFields("providerName")
.verify();
}
diff --git a/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentityTest.java b/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentityTest.java
index 3702694e4fdd..b687b7b89348 100644
--- a/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentityTest.java
+++ b/core/identity-spi/src/test/java/software/amazon/awssdk/identity/spi/AwsSessionCredentialsIdentityTest.java
@@ -31,6 +31,7 @@ public class AwsSessionCredentialsIdentityTest {
@Test
public void equalsHashcode() {
EqualsVerifier.forClass(DefaultAwsSessionCredentialsIdentity.class)
+ .withIgnoredFields("providerName")
.verify();
}
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStage.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStage.java
index ee592eaeefde..12acc1a2e665 100644
--- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStage.java
+++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStage.java
@@ -16,43 +16,60 @@
package software.amazon.awssdk.core.internal.http.pipeline.stages;
import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.core.ApiName;
import software.amazon.awssdk.core.ClientType;
import software.amazon.awssdk.core.SdkSystemSetting;
+import software.amazon.awssdk.core.SelectedAuthScheme;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
import software.amazon.awssdk.core.client.config.SdkClientOption;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
import software.amazon.awssdk.core.internal.http.HttpClientDependencies;
import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
import software.amazon.awssdk.core.internal.http.pipeline.MutableRequestToRequestPipeline;
+import software.amazon.awssdk.core.internal.useragent.IdentityProviderNameMapping;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.core.util.SdkUserAgent;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
+import software.amazon.awssdk.identity.spi.Identity;
+import software.amazon.awssdk.utils.CompletableFutureUtils;
import software.amazon.awssdk.utils.Logger;
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.awssdk.utils.http.SdkHttpUtils;
/**
- * Apply any custom user agent supplied, otherwise instrument the user agent with info about the SDK and environment.
+ * A stage for adding the user agent header to the request, after retrieving the current string
+ * from execution attributes and adding any additional information.
*/
@SdkInternalApi
public class ApplyUserAgentStage implements MutableRequestToRequestPipeline {
+
+ public static final String HEADER_USER_AGENT = "User-Agent";
+
private static final Logger log = Logger.loggerFor(ApplyUserAgentStage.class);
private static final String COMMA = ", ";
+ private static final String SLASH = "/";
private static final String SPACE = " ";
-
+ private static final String HASH = "#";
private static final String IO = "io";
private static final String HTTP = "http";
private static final String CONFIG = "cfg";
private static final String RETRY_MODE = "retry-mode";
-
+ private static final String AUTH_HEADER = "auth-source";
private static final String AWS_EXECUTION_ENV_PREFIX = "exec-env/";
- private static final String HEADER_USER_AGENT = "User-Agent";
+ private static final BinaryOperator API_NAMES = (name, version) -> name + "/" + version;
+ private static final BinaryOperator CONFIG_METADATA = (param, name) -> CONFIG + SLASH + param + HASH + name;
+ private static final UnaryOperator AUTH_CONFIG = name -> CONFIG_METADATA.apply(AUTH_HEADER, name);
private final SdkClientConfiguration clientConfig;
@@ -115,10 +132,10 @@ public static String resolveClientUserAgent(String userAgentPrefix,
@Override
public SdkHttpFullRequest.Builder execute(SdkHttpFullRequest.Builder request, RequestExecutionContext context)
throws Exception {
- return request.putHeader(HEADER_USER_AGENT, getUserAgent(clientConfig, context.requestConfig().apiNames()));
+ return request.putHeader(HEADER_USER_AGENT, getUserAgent(clientConfig, context));
}
- private String getUserAgent(SdkClientConfiguration config, List requestApiNames) {
+ private String getUserAgent(SdkClientConfiguration config, RequestExecutionContext context) {
String clientUserAgent = clientConfig.option(SdkClientOption.CLIENT_USER_AGENT);
if (clientUserAgent == null) {
log.warn(() -> "Client user agent configuration is missing, so request user agent will be incomplete.");
@@ -126,12 +143,14 @@ private String getUserAgent(SdkClientConfiguration config, List request
}
StringBuilder userAgent = new StringBuilder(clientUserAgent);
- if (!requestApiNames.isEmpty()) {
- requestApiNames.forEach(apiName -> {
- userAgent.append(SPACE).append(apiName.name()).append("/").append(apiName.version());
- });
- }
+ //additional cfg information
+ identityProviderName(context.executionAttributes())
+ .ifPresent(providerName -> userAgent.append(SPACE).append(AUTH_CONFIG.apply(providerName)));
+
+ //request API names
+ requestApiNames(context.requestConfig().apiNames()).ifPresent(userAgent::append);
+ //suffix
String userDefinedSuffix = config.option(SdkAdvancedClientOption.USER_AGENT_SUFFIX);
if (!StringUtils.isEmpty(userDefinedSuffix)) {
userAgent.append(COMMA).append(userDefinedSuffix.trim());
@@ -140,6 +159,32 @@ private String getUserAgent(SdkClientConfiguration config, List request
return userAgent.toString();
}
+ private static Optional identityProviderName(ExecutionAttributes executionAttributes) {
+ SelectedAuthScheme> selectedAuthScheme = executionAttributes
+ .getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
+ if (selectedAuthScheme == null) {
+ return Optional.empty();
+ }
+ return providerNameFromIdentity(selectedAuthScheme);
+ }
+
+ private static Optional providerNameFromIdentity(SelectedAuthScheme selectedAuthScheme) {
+ CompletableFuture extends T> identityFuture = selectedAuthScheme.identity();
+ T identity = CompletableFutureUtils.joinLikeSync(identityFuture);
+ return identity.providerName().flatMap(IdentityProviderNameMapping::mapFrom);
+ }
+
+ private Optional requestApiNames(List requestApiNames) {
+ if (requestApiNames.isEmpty()) {
+ return Optional.empty();
+ }
+ StringBuilder concatenatedNames = new StringBuilder();
+ requestApiNames.forEach(apiName -> concatenatedNames.append(SPACE)
+ .append(API_NAMES.apply(apiName.name(),
+ apiName.version())));
+ return Optional.of(concatenatedNames.toString());
+ }
+
private static String clientName(ClientType clientType, SdkHttpClient syncHttpClient, SdkAsyncHttpClient asyncHttpClient) {
if (clientType == ClientType.SYNC) {
return syncHttpClient == null ? "null" : syncHttpClient.clientName();
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/useragent/IdentityProviderNameMapping.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/useragent/IdentityProviderNameMapping.java
new file mode 100644
index 000000000000..d76b0b250a42
--- /dev/null
+++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/useragent/IdentityProviderNameMapping.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.core.internal.useragent;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import software.amazon.awssdk.annotations.SdkInternalApi;
+import software.amazon.awssdk.utils.StringUtils;
+import software.amazon.awssdk.utils.internal.EnumUtils;
+
+/**
+ * A enum class representing a short form of identity providers to record in the UA string.
+ */
+@SdkInternalApi
+public enum IdentityProviderNameMapping {
+
+ SYS("SystemPropertyCredentialsProvider"),
+ ENV("EnvironmentVariableCredentialsProvider"),
+ STSWEB("StsAssumeRoleWithWebIdentity"),
+ STSROLE("StsAssumeRoleCredentialsProvider"),
+ STSSAML("StsAssumeRoleWithWebIdentityCredentialsProvider"),
+ STSFED("StsGetFederationTokenCredentialsProvider"),
+ STSSESS("StsGetSessionTokenCredentialsProvider"),
+ SSO("SsoCredentialsProvider"),
+ PROF("ProfileCredentialsProvider"),
+ CONT("ContainerCredentialsProvider"),
+ IMDS("InstanceProfileCredentialsProvider"),
+ STAT("StaticCredentialsProvider"),
+ PROC("ProcessCredentialsProvider"),
+ ANON("AnonymousCredentialsProvider"),
+ UNKNOWN("Unknown");
+
+ private static final Pattern CLASS_NAME_CHARACTERS = Pattern.compile("[a-zA-Z_$\\d]{0,62}");
+ private static final Map VALUE_MAP =
+ EnumUtils.uniqueIndex(IdentityProviderNameMapping.class, IdentityProviderNameMapping::toString);
+ private final String value;
+
+ IdentityProviderNameMapping(String value) {
+ this.value = value;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+ /**
+ * Map the given provider name to a shorter form. If null or empty, return unknown.
+ * If not recognized, use the given string if it conforms to the accepted pattern.
+ */
+ public static Optional mapFrom(String source) {
+ if (StringUtils.isBlank(source)) {
+ return Optional.of(UNKNOWN.name().toLowerCase(Locale.US));
+ }
+ return mappedName(source).map(mapping -> Optional.of(mapping.name().toLowerCase(Locale.US)))
+ .orElseGet(() -> sanitizedProviderOrNull(source));
+ }
+
+ private static Optional mappedName(String value) {
+ if (VALUE_MAP.containsKey(value)) {
+ return Optional.of(VALUE_MAP.get(value));
+ }
+ return Optional.empty();
+ }
+
+ private static Optional sanitizedProviderOrNull(String value) {
+ if (hasAcceptedFormat(value)) {
+ return Optional.of(value);
+ }
+ return Optional.empty();
+ }
+
+ private static boolean hasAcceptedFormat(String input) {
+ return CLASS_NAME_CHARACTERS.matcher(input).matches();
+ }
+}
diff --git a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStageTest.java b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStageTest.java
new file mode 100644
index 000000000000..50b72aa58031
--- /dev/null
+++ b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/ApplyUserAgentStageTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.core.internal.http.pipeline.stages;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static software.amazon.awssdk.core.internal.http.pipeline.stages.ApplyUserAgentStage.HEADER_USER_AGENT;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import software.amazon.awssdk.core.SdkRequest;
+import software.amazon.awssdk.core.SdkRequestOverrideConfiguration;
+import software.amazon.awssdk.core.SelectedAuthScheme;
+import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
+import software.amazon.awssdk.core.client.config.SdkClientOption;
+import software.amazon.awssdk.core.http.ExecutionContext;
+import software.amazon.awssdk.core.http.NoopTestRequest;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
+import software.amazon.awssdk.core.internal.http.HttpClientDependencies;
+import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
+import software.amazon.awssdk.http.SdkHttpFullRequest;
+import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
+import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
+import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
+import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity;
+import software.amazon.awssdk.identity.spi.Identity;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ApplyUserAgentStageTest {
+ private static final SelectedAuthScheme EMPTY_SELECTED_AUTH_SCHEME =
+ new SelectedAuthScheme<>(CompletableFuture.completedFuture(Mockito.mock(Identity.class)),
+ (HttpSigner) Mockito.mock(HttpSigner.class),
+ AuthSchemeOption.builder().schemeId("mock").build());
+
+ private static final String SDK_UA_STRING = "aws-sdk-java/version vendor/unknown";
+ private static final String PROVIDER_SOURCE = "ProcessCredentialsProvider";
+ private static final AwsCredentialsIdentity IDENTITY_WITHOUT_SOURCE =
+ AwsCredentialsIdentity.create("akid", "secret");
+
+ private static final AwsCredentialsIdentity IDENTITY_WITH_SOURCE =
+ AwsSessionCredentialsIdentity.builder().accessKeyId("akid").secretAccessKey("secret").sessionToken("token")
+ .providerName(PROVIDER_SOURCE).build();
+
+ @Test
+ public void when_noAdditionalDataIsPresent_outputStringEqualsInputString() throws Exception {
+ String clientBuildTimeUserAgentString = SDK_UA_STRING;
+
+ ApplyUserAgentStage stage = new ApplyUserAgentStage(dependenciesWithUserAgent(clientBuildTimeUserAgentString));
+
+ RequestExecutionContext ctx = requestExecutionContext(executionAttributes(IDENTITY_WITHOUT_SOURCE), noOpRequest());
+ SdkHttpFullRequest.Builder request = stage.execute(SdkHttpFullRequest.builder(), ctx);
+
+ List userAgentHeaders = request.headers().get(HEADER_USER_AGENT);
+ assertThat(userAgentHeaders).isNotNull().hasSize(1);
+ assertThat(userAgentHeaders.get(0)).isEqualTo(SDK_UA_STRING);
+ }
+
+ @Test
+ public void when_identityContainsProvider_authSourceIsPresent() throws Exception {
+ String clientBuildTimeUserAgentString = SDK_UA_STRING;
+
+ ApplyUserAgentStage stage = new ApplyUserAgentStage(dependenciesWithUserAgent(clientBuildTimeUserAgentString));
+
+ RequestExecutionContext ctx = requestExecutionContext(executionAttributes(IDENTITY_WITH_SOURCE), noOpRequest());
+ SdkHttpFullRequest.Builder request = stage.execute(SdkHttpFullRequest.builder(), ctx);
+
+ List userAgentHeaders = request.headers().get(HEADER_USER_AGENT);
+ assertThat(userAgentHeaders).isNotNull().hasSize(1);
+ assertThat(userAgentHeaders.get(0)).contains("auth-source#proc");
+ }
+
+ @Test
+ public void when_requestContainsApiName_apiNamesArePresent() throws Exception {
+ String clientBuildTimeUserAgentString = SDK_UA_STRING;
+
+ ApplyUserAgentStage stage = new ApplyUserAgentStage(dependenciesWithUserAgent(clientBuildTimeUserAgentString));
+
+ RequestExecutionContext ctx = requestExecutionContext(executionAttributes(IDENTITY_WITH_SOURCE),
+ requestWithApiName("myLib", "1.0"));
+ SdkHttpFullRequest.Builder request = stage.execute(SdkHttpFullRequest.builder(), ctx);
+
+ List userAgentHeaders = request.headers().get(HEADER_USER_AGENT);
+ assertThat(userAgentHeaders).isNotNull().hasSize(1);
+ assertThat(userAgentHeaders.get(0)).contains("myLib/1.0");
+ }
+
+ private static HttpClientDependencies dependenciesWithUserAgent(String userAgent) {
+ SdkClientConfiguration clientConfiguration = SdkClientConfiguration.builder()
+ .option(SdkClientOption.CLIENT_USER_AGENT, userAgent)
+ .build();
+ return HttpClientDependencies.builder()
+ .clientConfiguration(clientConfiguration)
+ .build();
+ }
+
+ private static SdkRequest noOpRequest() {
+ return requestWithOverrideConfig(null);
+ }
+
+ private static SdkRequest requestWithApiName(String apiName, String version) {
+ SdkRequestOverrideConfiguration requestOverrideConfiguration =
+ SdkRequestOverrideConfiguration.builder()
+ .addApiName(a -> a.name(apiName).version(version))
+ .build();
+ return requestWithOverrideConfig(requestOverrideConfiguration);
+ }
+
+ private static SdkRequest requestWithOverrideConfig(SdkRequestOverrideConfiguration overrideConfiguration) {
+ return NoopTestRequest.builder()
+ .overrideConfiguration(overrideConfiguration)
+ .build();
+ }
+
+ private static ExecutionAttributes executionAttributes(AwsCredentialsIdentity identity) {
+ ExecutionAttributes executionAttributes = new ExecutionAttributes();
+ executionAttributes.putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME,
+ new SelectedAuthScheme<>(CompletableFuture.completedFuture(identity),
+ EMPTY_SELECTED_AUTH_SCHEME.signer(),
+ EMPTY_SELECTED_AUTH_SCHEME.authSchemeOption()));
+ return executionAttributes;
+ }
+
+ private RequestExecutionContext requestExecutionContext(ExecutionAttributes executionAttributes,
+ SdkRequest request) {
+ ExecutionContext executionContext = ExecutionContext.builder()
+ .executionAttributes(executionAttributes)
+ .build();
+ return RequestExecutionContext.builder()
+ .executionContext(executionContext)
+ .originalRequest(request).build();
+
+ }
+}
diff --git a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/useragent/IdentityProviderNameMappingTest.java b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/useragent/IdentityProviderNameMappingTest.java
new file mode 100644
index 000000000000..e669ba82917e
--- /dev/null
+++ b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/useragent/IdentityProviderNameMappingTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.core.internal.useragent;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+import org.junit.jupiter.api.Test;
+
+class IdentityProviderNameMappingTest {
+
+ @Test
+ void when_providerIsNull_unknownValueIsReturned() {
+ Optional mappedProviderName = IdentityProviderNameMapping.mapFrom(null);
+ assertThat(mappedProviderName).isPresent().contains("unknown");
+ }
+
+ @Test
+ void when_providerIsEmpty_unknownValueIsReturned() {
+ Optional mappedProviderName = IdentityProviderNameMapping.mapFrom("");
+ assertThat(mappedProviderName).isPresent().contains("unknown");
+ }
+
+ @Test
+ void when_providerIsKnown_shortValueIsReturned() {
+ Optional mappedProviderName = IdentityProviderNameMapping.mapFrom("StaticCredentialsProvider");
+ assertThat(mappedProviderName).isPresent().contains("stat");
+ }
+
+ @Test
+ void when_providerIsUnknown_stringIsReturned() {
+ Optional mappedProviderName = IdentityProviderNameMapping.mapFrom("MyHomebrewedCredentialsProvider");
+ assertThat(mappedProviderName).isPresent().contains("MyHomebrewedCredentialsProvider");
+ }
+
+ @Test
+ void when_providerIsIllegal_noValueIsReturned() {
+ Optional mappedProviderName = IdentityProviderNameMapping.mapFrom("My@#$%$CredentialsProvider");
+ assertThat(mappedProviderName).isNotPresent();
+ }
+
+ @Test
+ void when_providerIsTooLong_noValueIsReturned() {
+ Optional mappedProviderName = IdentityProviderNameMapping.mapFrom(
+ "MyMegaGinormousBubbaBubbaBubbaBubbaBubbaBubbaCredentialsProvider");
+ assertThat(mappedProviderName).isNotPresent();
+ }
+}
diff --git a/services/sso/src/main/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProvider.java b/services/sso/src/main/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProvider.java
index aab6fb110019..6df1de085cba 100644
--- a/services/sso/src/main/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProvider.java
+++ b/services/sso/src/main/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProvider.java
@@ -51,6 +51,7 @@
@SdkPublicApi
public final class SsoCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable,
ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "SsoCredentialsProvider";
private static final Duration DEFAULT_STALE_TIME = Duration.ofMinutes(1);
private static final Duration DEFAULT_PREFETCH_TIME = Duration.ofMinutes(5);
@@ -106,9 +107,12 @@ private SessionCredentialsHolder getUpdatedCredentials(SsoClient ssoClient) {
GetRoleCredentialsRequest request = getRoleCredentialsRequestSupplier.get();
notNull(request, "GetRoleCredentialsRequest can't be null.");
RoleCredentials roleCredentials = ssoClient.getRoleCredentials(request).roleCredentials();
- AwsSessionCredentials sessionCredentials = AwsSessionCredentials.create(roleCredentials.accessKeyId(),
- roleCredentials.secretAccessKey(),
- roleCredentials.sessionToken());
+ AwsSessionCredentials sessionCredentials = AwsSessionCredentials.builder()
+ .accessKeyId(roleCredentials.accessKeyId())
+ .secretAccessKey(roleCredentials.secretAccessKey())
+ .sessionToken(roleCredentials.sessionToken())
+ .providerName(PROVIDER_NAME)
+ .build();
return new SessionCredentialsHolder(sessionCredentials, Instant.ofEpochMilli(roleCredentials.expiration()));
}
diff --git a/services/sso/src/test/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProviderTest.java b/services/sso/src/test/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProviderTest.java
index 98f292ddb790..8d171b4edb23 100644
--- a/services/sso/src/test/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProviderTest.java
+++ b/services/sso/src/test/java/software/amazon/awssdk/services/sso/auth/SsoCredentialsProviderTest.java
@@ -133,6 +133,7 @@ private void callClientWithCredentialsProvider(Instant credentialsExpirationDate
assertThat(actualCredentials.accessKeyId()).isEqualTo("a");
assertThat(actualCredentials.secretAccessKey()).isEqualTo("b");
assertThat(actualCredentials.sessionToken()).isEqualTo("c");
+ assertThat(actualCredentials.providerName()).isPresent().contains("SsoCredentialsProvider");
}
}
diff --git a/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManager.java b/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManager.java
index 914188dcc83d..267385b4d66c 100644
--- a/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManager.java
+++ b/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManager.java
@@ -118,7 +118,7 @@ private SsoOidcToken unmarshalToken(String contents) {
.ifPresent(tokenBuilder::registrationExpiresAt);
node.field("region").map(JsonNode::text).ifPresent(tokenBuilder::region);
node.field("startUrl").map(JsonNode::text).ifPresent(tokenBuilder::startUrl);
-
+ tokenBuilder.providerName(SsoOidcToken.PROVIDER_NAME);
return tokenBuilder.build();
}
diff --git a/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcToken.java b/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcToken.java
index d1e42c8a7ebe..9f50a3154130 100644
--- a/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcToken.java
+++ b/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcToken.java
@@ -41,6 +41,7 @@
*/
@SdkInternalApi
public final class SsoOidcToken implements SdkToken {
+ public static final String PROVIDER_NAME = "SsoOidcTokenProvider";
private final String accessToken;
private final Instant expiresAt;
private final String refreshToken;
@@ -49,6 +50,7 @@ public final class SsoOidcToken implements SdkToken {
private final Instant registrationExpiresAt;
private final String region;
private final String startUrl;
+ private final String providerName;
private SsoOidcToken(BuilderImpl builder) {
Validate.paramNotNull(builder.accessToken, "accessToken");
@@ -61,6 +63,7 @@ private SsoOidcToken(BuilderImpl builder) {
this.registrationExpiresAt = builder.registrationExpiresAt;
this.region = builder.region;
this.startUrl = builder.startUrl;
+ this.providerName = builder.providerName;
}
@Override
@@ -73,6 +76,11 @@ public Optional expirationTime() {
return Optional.of(expiresAt);
}
+ @Override
+ public Optional providerName() {
+ return Optional.of(providerName);
+ }
+
public String refreshToken() {
return refreshToken;
}
@@ -166,6 +174,8 @@ public interface Builder {
Builder startUrl(String startUrl);
+ Builder providerName(String providerName);
+
SsoOidcToken build();
}
@@ -178,6 +188,7 @@ private static class BuilderImpl implements Builder {
private Instant registrationExpiresAt;
private String region;
private String startUrl;
+ private String providerName;
@Override
public Builder accessToken(String accessToken) {
@@ -227,6 +238,12 @@ public Builder startUrl(String startUrl) {
return this;
}
+ @Override
+ public Builder providerName(String providerName) {
+ this.providerName = providerName;
+ return this;
+ }
+
@Override
public SsoOidcToken build() {
return new SsoOidcToken(this);
diff --git a/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTransformer.java b/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTransformer.java
index a0f5e56ddb41..feef372c41f9 100644
--- a/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTransformer.java
+++ b/services/ssooidc/src/main/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTransformer.java
@@ -54,6 +54,7 @@ public SsoOidcToken transform(CreateTokenResponse awsResponse) {
.region(baseToken.region())
.clientSecret(baseToken.clientSecret())
.clientId(baseToken.clientId())
+ .providerName(SsoOidcToken.PROVIDER_NAME)
.build();
}
}
diff --git a/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManagerTest.java b/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManagerTest.java
index 302732ac9eb8..724634980218 100644
--- a/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManagerTest.java
+++ b/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/OnDiskTokenManagerTest.java
@@ -68,6 +68,7 @@ public void loadToken_loadsCorrectFile(String sessionName, String expectedLocati
SsoOidcToken token = SsoOidcToken.builder()
.accessToken("accesstoken")
.expiresAt(expiresAt)
+ .providerName("test")
.build();
String tokenJson = String.format("{\n"
+ " \"accessToken\": \"accesstoken\",\n"
@@ -110,6 +111,7 @@ public void loadToken_maximal() throws IOException {
.registrationExpiresAt(registrationExpiresAt)
.region("region")
.startUrl("starturl")
+ .providerName("test")
.build();
String ssoSession = "admin";
@@ -157,6 +159,7 @@ public void storeToken_maximal() throws IOException {
.registrationExpiresAt(registrationExpiresAt)
.region("region")
.startUrl(startUrl)
+ .providerName("test")
.build();
String expectedFile = "d033e22ae348aeb5660fc2140aec35850c4da997.json";
@@ -188,6 +191,7 @@ public void storeToken_loadToken_roundTrip() {
.registrationExpiresAt(registrationExpiresAt)
.region("region")
.startUrl(startUrl)
+ .providerName("test")
.build();
OnDiskTokenManager onDiskTokenManager = OnDiskTokenManager.create(cache, sessionName);
diff --git a/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenProviderTest.java b/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenProviderTest.java
index 7499fa85f636..627585a58405 100644
--- a/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenProviderTest.java
+++ b/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenProviderTest.java
@@ -19,8 +19,6 @@
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -28,8 +26,6 @@
import static org.mockito.Mockito.when;
import static software.amazon.awssdk.utils.UserHomeDirectoryUtils.userHomeDirectory;
-import com.google.common.jimfs.Configuration;
-import com.google.common.jimfs.Jimfs;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -44,7 +40,6 @@
import java.util.Locale;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.auth.token.credentials.SdkToken;
import software.amazon.awssdk.awscore.internal.token.TokenManager;
@@ -101,7 +96,7 @@ public void teardown() throws IOException {
}
@Test
- public void resolveToken_usesTokenManager() {
+ void resolveToken_usesTokenManager() {
SsoOidcToken ssoOidcToken = SsoOidcToken.builder()
.accessToken("accesstoken")
.expiresAt(Instant.now().plus(Duration.ofDays(1)))
@@ -109,7 +104,9 @@ public void resolveToken_usesTokenManager() {
mockTokenManager.storeToken(ssoOidcToken);
SsoOidcTokenProvider tokenProvider = getDefaultSsoOidcTokenProviderBuilder().build();
- assertThat(tokenProvider.resolveToken()).isEqualTo(ssoOidcToken);
+ SdkToken resolvedToken = tokenProvider.resolveToken();
+ assertThat(resolvedToken).isEqualTo(ssoOidcToken);
+ assertThat(resolvedToken.providerName()).isPresent().contains("SsoOidcTokenProvider");
}
private SsoOidcTokenProvider.Builder getDefaultSsoOidcTokenProviderBuilder() {
@@ -117,7 +114,7 @@ private SsoOidcTokenProvider.Builder getDefaultSsoOidcTokenProviderBuilder() {
}
@Test
- public void resolveToken_cachedValueNotPresent_throws() {
+ void resolveToken_cachedValueNotPresent_throws() {
SsoOidcTokenProvider tokenProvider = getDefaultSsoOidcTokenProviderBuilder().build();
@@ -145,7 +142,7 @@ public void resolveToken_cachedValueNotPresent_throws() {
// }
// },
@Test
- public void standardTest_Valid_token_with_all_fields() {
+ void standardTest_Valid_token_with_all_fields() {
SsoOidcToken token = getDefaultTokenBuilder()
.expiresAt(Instant.now().plusSeconds(10000)).registrationExpiresAt(Instant.now().plusSeconds(90000))
.build();
@@ -160,7 +157,7 @@ public void standardTest_Valid_token_with_all_fields() {
}
@Test
- public void refresh_returns_cached_token_when_service_calls_fails() {
+ void refresh_returns_cached_token_when_service_calls_fails() {
SsoOidcToken nearToExpiryToken = getDefaultTokenBuilder()
.expiresAt(Instant.now().plusSeconds(5000)).registrationExpiresAt(Instant.now().plusSeconds(10000))
.build();
@@ -177,7 +174,7 @@ public void refresh_returns_cached_token_when_service_calls_fails() {
}
@Test
- public void refresh_fails_when_supplier_fails_due_to_Non_service_issues() {
+ void refresh_fails_when_supplier_fails_due_to_Non_service_issues() {
SsoOidcToken nearToExpiryToken = getDefaultTokenBuilder()
.expiresAt(Instant.now().minusSeconds(2)).registrationExpiresAt(Instant.now().minusSeconds(2))
.build();
@@ -201,7 +198,7 @@ public void refresh_fails_when_supplier_fails_due_to_Non_service_issues() {
// }
// },
@Test
- public void standardTest_Minimal_valid_cached_token() {
+ void standardTest_Minimal_valid_cached_token() {
Instant expiresAt = Instant.now().plusSeconds(3600);
SsoOidcToken ssoOidcToken = SsoOidcToken.builder().accessToken("cachedtoken").expiresAt(expiresAt).build();
mockTokenManager.storeToken(ssoOidcToken);
@@ -219,7 +216,7 @@ public void standardTest_Minimal_valid_cached_token() {
// "expectedException": "ExpiredToken"
// }
@Test
- public void standardTest_Minimal_expired_cached_token() {
+ void standardTest_Minimal_expired_cached_token() {
String startUrl = START_URL;
Instant expiresAt = Instant.parse("2021-12-25T13:00:00Z");
SsoOidcToken ssoOidcToken =
@@ -247,7 +244,7 @@ public void standardTest_Minimal_expired_cached_token() {
// "expectedException": "InvalidToken"
// },
@Test
- public void standardTest_Token_missing_the_expiresAt_field() {
+ void standardTest_Token_missing_the_expiresAt_field() {
SsoOidcToken ssoOidcToken = SsoOidcToken.builder()
.startUrl(START_URL)
.accessToken("cachedtoken").clientId("client").clientSecret("secret")
@@ -272,7 +269,7 @@ public void standardTest_Token_missing_the_expiresAt_field() {
// "expectedException": "InvalidToken"
// },
@Test
- public void standardTest_Token_missing_the_accessToken_field() {
+ void standardTest_Token_missing_the_accessToken_field() {
SsoOidcToken ssoOidcToken = SsoOidcToken.builder()
.startUrl(START_URL)
.accessToken("cachedtoken").clientId("client").clientSecret("secret")
@@ -290,7 +287,7 @@ public void standardTest_Token_missing_the_accessToken_field() {
}
@Test
- public void refresh_token_from_service_when_token_outside_expiry_window() {
+ void refresh_token_from_service_when_token_outside_expiry_window() {
SsoOidcToken nearToExpiryToken = getDefaultTokenBuilder()
.expiresAt(Instant.now().plusSeconds(59))
.registrationExpiresAt(Instant.now().plusSeconds(59)).build();
@@ -319,7 +316,7 @@ public void refresh_token_from_service_when_token_outside_expiry_window() {
}
@Test
- public void refresh_token_does_not_fetch_from_service_when_token_inside_expiry_window() {
+ void refresh_token_does_not_fetch_from_service_when_token_inside_expiry_window() {
SsoOidcToken cachedDiskToken = getDefaultTokenBuilder()
.expiresAt(Instant.now().plusSeconds(120)).registrationExpiresAt(Instant.now().plusSeconds(120))
.build();
@@ -333,7 +330,7 @@ public void refresh_token_does_not_fetch_from_service_when_token_inside_expiry_w
}
@Test
- public void token_is_obtained_from_inmemory_when_token_is_within_inmemory_stale_time() {
+ void token_is_obtained_from_inmemory_when_token_is_within_inmemory_stale_time() {
Instant futureExpiryDate = Instant.now().plus(Duration.ofDays(1));
SsoOidcToken cachedDiskToken = getDefaultTokenBuilder()
.expiresAt(futureExpiryDate).registrationExpiresAt(Instant.parse("2022-12-25T11:30:00Z")).build();
@@ -354,7 +351,7 @@ public void token_is_obtained_from_inmemory_when_token_is_within_inmemory_stale_
// Test to make sure cache fetches from Cached values.
@Test
- public void token_is_obtained_from_refresher_and_then_refresher_cache_if_its_within_stale_time() {
+ void token_is_obtained_from_refresher_and_then_refresher_cache_if_its_within_stale_time() {
Instant closeToExpireTime = Instant.now().plus(Duration.ofMinutes(4));
SsoOidcToken cachedDiskToken = getDefaultTokenBuilder().accessToken("fourMinutesToExpire")
.expiresAt(closeToExpireTime)
@@ -383,7 +380,7 @@ public void token_is_obtained_from_refresher_and_then_refresher_cache_if_its_wit
}
@Test
- public void token_is_retrieved_from_service_when_service_returns_tokens_with_short_expiration() {
+ void token_is_retrieved_from_service_when_service_returns_tokens_with_short_expiration() {
Instant closeToExpireTime = Instant.now().plus(Duration.ofSeconds(4));
SsoOidcToken cachedDiskToken = getDefaultTokenBuilder().accessToken("fourMinutesToExpire")
.expiresAt(closeToExpireTime)
@@ -410,7 +407,7 @@ public void token_is_retrieved_from_service_when_service_returns_tokens_with_sho
}
@Test
- public void token_is_retrieved_automatically_when_prefetch_time_is_set() throws InterruptedException {
+ void token_is_retrieved_automatically_when_prefetch_time_is_set() throws InterruptedException {
Instant closeToExpireTime = Instant.now().plus(Duration.ofMillis(3));
SsoOidcToken cachedDiskToken = getDefaultTokenBuilder().accessToken("closeToExpire")
@@ -450,13 +447,13 @@ private CreateTokenResponse someOne(CreateTokenResponse.Builder builder, String
}
@Test
- public void tokenProvider_throws_exception_if_client_is_null() {
+ void tokenProvider_throws_exception_if_client_is_null() {
assertThatExceptionOfType(NullPointerException.class).isThrownBy(
() -> SsoOidcTokenProvider.builder().sessionName(START_URL).build()).withMessage("ssoOidcClient must not be null.");
}
@Test
- public void tokenProvider_throws_exception_if_start_url_is_null() {
+ void tokenProvider_throws_exception_if_start_url_is_null() {
assertThatExceptionOfType(NullPointerException.class).isThrownBy(
() -> SsoOidcTokenProvider.builder().ssoOidcClient(ssoOidcClient).build()).withMessage("sessionName must not be "
+ "null.");
diff --git a/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTest.java b/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTest.java
index 6e1a10b4e93a..b286eb13bac8 100644
--- a/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTest.java
+++ b/services/ssooidc/src/test/java/software/amazon/awssdk/services/ssooidc/internal/SsoOidcTokenTest.java
@@ -26,6 +26,7 @@ public class SsoOidcTokenTest {
@Test
public void equalsAndHashCode_workCorrectly() {
EqualsVerifier.forClass(SsoOidcToken.class)
+ .withIgnoredFields("providerName")
.usingGetClass()
.verify();
}
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProvider.java
index a435d258c2d5..b7e1e3003c4d 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProvider.java
@@ -26,7 +26,6 @@
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
-import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -47,6 +46,7 @@
public final class StsAssumeRoleCredentialsProvider
extends StsCredentialsProvider
implements ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "StsAssumeRoleCredentialsProvider";
private Supplier assumeRoleRequestSupplier;
/**
@@ -70,17 +70,17 @@ public static Builder builder() {
protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) {
AssumeRoleRequest assumeRoleRequest = assumeRoleRequestSupplier.get();
Validate.notNull(assumeRoleRequest, "Assume role request must not be null.");
- return toAwsSessionCredentials(stsClient.assumeRole(assumeRoleRequest).credentials());
+ return toAwsSessionCredentials(stsClient.assumeRole(assumeRoleRequest).credentials(), PROVIDER_NAME);
}
@Override
- public String toString() {
- return ToString.create("StsAssumeRoleCredentialsProvider");
+ public Builder toBuilder() {
+ return new Builder(this);
}
@Override
- public Builder toBuilder() {
- return new Builder(this);
+ String providerName() {
+ return PROVIDER_NAME;
}
/**
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProvider.java
index 6365fa488880..761e0dcb044e 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProvider.java
@@ -26,7 +26,6 @@
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlRequest;
-import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -47,6 +46,7 @@
public final class StsAssumeRoleWithSamlCredentialsProvider
extends StsCredentialsProvider
implements ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "StsAssumeRoleWithSamlCredentialsProvider";
private final Supplier assumeRoleWithSamlRequestSupplier;
@@ -71,12 +71,7 @@ public static Builder builder() {
protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) {
AssumeRoleWithSamlRequest assumeRoleWithSamlRequest = assumeRoleWithSamlRequestSupplier.get();
Validate.notNull(assumeRoleWithSamlRequest, "Assume role with saml request must not be null.");
- return toAwsSessionCredentials(stsClient.assumeRoleWithSAML(assumeRoleWithSamlRequest).credentials());
- }
-
- @Override
- public String toString() {
- return ToString.create("StsAssumeRoleWithSamlCredentialsProvider");
+ return toAwsSessionCredentials(stsClient.assumeRoleWithSAML(assumeRoleWithSamlRequest).credentials(), PROVIDER_NAME);
}
@Override
@@ -84,6 +79,11 @@ public Builder toBuilder() {
return new Builder(this);
}
+ @Override
+ String providerName() {
+ return PROVIDER_NAME;
+ }
+
/**
* A builder (created by {@link StsAssumeRoleWithSamlCredentialsProvider#builder()}) for creating a
* {@link StsAssumeRoleWithSamlCredentialsProvider}.
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProvider.java
index fcc10e5b2878..d5e5a20f5b97 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProvider.java
@@ -27,7 +27,6 @@
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleWithWebIdentityRequest;
-import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
/**
@@ -48,6 +47,7 @@ public final class StsAssumeRoleWithWebIdentityCredentialsProvider
extends StsCredentialsProvider
implements ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "StsAssumeRoleWithWebIdentityCredentialsProvider";
private final Supplier assumeRoleWithWebIdentityRequest;
/**
@@ -71,12 +71,7 @@ public static Builder builder() {
protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) {
AssumeRoleWithWebIdentityRequest request = assumeRoleWithWebIdentityRequest.get();
notNull(request, "AssumeRoleWithWebIdentityRequest can't be null");
- return toAwsSessionCredentials(stsClient.assumeRoleWithWebIdentity(request).credentials());
- }
-
- @Override
- public String toString() {
- return ToString.create("StsAssumeRoleWithWebIdentityCredentialsProvider");
+ return toAwsSessionCredentials(stsClient.assumeRoleWithWebIdentity(request).credentials(), PROVIDER_NAME);
}
@Override
@@ -84,6 +79,11 @@ public Builder toBuilder() {
return new Builder(this);
}
+ @Override
+ String providerName() {
+ return PROVIDER_NAME;
+ }
+
/**
* A builder (created by {@link StsAssumeRoleWithWebIdentityCredentialsProvider#builder()}) for creating a
* {@link StsAssumeRoleWithWebIdentityCredentialsProvider}.
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.java
index a1f4573c60ac..e19a6bf4b9f6 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.java
@@ -28,6 +28,7 @@
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.utils.Logger;
import software.amazon.awssdk.utils.SdkAutoCloseable;
+import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -130,11 +131,18 @@ public Duration prefetchTime() {
return prefetchTime;
}
+ @Override
+ public String toString() {
+ return ToString.create(providerName());
+ }
+
/**
* Implemented by a child class to call STS and get a new set of credentials to be used by this provider.
*/
abstract AwsSessionCredentials getUpdatedCredentials(StsClient stsClient);
+ abstract String providerName();
+
/**
* Extended by child class's builders to share configuration across credential providers.
*/
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProvider.java
index 3dd91b501e8b..77c57147aea9 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProvider.java
@@ -25,7 +25,6 @@
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.GetFederationTokenRequest;
-import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -46,6 +45,8 @@
public class StsGetFederationTokenCredentialsProvider
extends StsCredentialsProvider
implements ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "StsGetFederationTokenCredentialsProvider";
+
private final GetFederationTokenRequest getFederationTokenRequest;
/**
@@ -67,12 +68,7 @@ public static Builder builder() {
@Override
protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) {
- return toAwsSessionCredentials(stsClient.getFederationToken(getFederationTokenRequest).credentials());
- }
-
- @Override
- public String toString() {
- return ToString.create("StsGetFederationTokenCredentialsProvider");
+ return toAwsSessionCredentials(stsClient.getFederationToken(getFederationTokenRequest).credentials(), PROVIDER_NAME);
}
@Override
@@ -80,6 +76,11 @@ public Builder toBuilder() {
return new Builder(this);
}
+ @Override
+ String providerName() {
+ return PROVIDER_NAME;
+ }
+
/**
* A builder (created by {@link StsGetFederationTokenCredentialsProvider#builder()}) for creating a
* {@link StsGetFederationTokenCredentialsProvider}.
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProvider.java
index b4b0717fb9e6..e7942671879c 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProvider.java
@@ -25,7 +25,6 @@
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.GetSessionTokenRequest;
-import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -46,6 +45,8 @@
public class StsGetSessionTokenCredentialsProvider
extends StsCredentialsProvider
implements ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "StsGetSessionTokenCredentialsProvider";
+
private final GetSessionTokenRequest getSessionTokenRequest;
/**
@@ -67,12 +68,7 @@ public static Builder builder() {
@Override
protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) {
- return toAwsSessionCredentials(stsClient.getSessionToken(getSessionTokenRequest).credentials());
- }
-
- @Override
- public String toString() {
- return ToString.create("StsGetSessionTokenCredentialsProvider");
+ return toAwsSessionCredentials(stsClient.getSessionToken(getSessionTokenRequest).credentials(), PROVIDER_NAME);
}
@Override
@@ -80,6 +76,11 @@ public Builder toBuilder() {
return new Builder(this);
}
+ @Override
+ String providerName() {
+ return PROVIDER_NAME;
+ }
+
/**
* A builder (created by {@link StsGetSessionTokenCredentialsProvider#builder()}) for creating a
* {@link StsGetSessionTokenCredentialsProvider}.
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenFileCredentialsProvider.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenFileCredentialsProvider.java
index 703daaa992e7..c1710327fcb8 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenFileCredentialsProvider.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenFileCredentialsProvider.java
@@ -32,7 +32,6 @@
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.internal.AssumeRoleWithWebIdentityRequestSupplier;
import software.amazon.awssdk.services.sts.model.AssumeRoleWithWebIdentityRequest;
-import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
/**
@@ -55,6 +54,7 @@
public final class StsWebIdentityTokenFileCredentialsProvider
extends StsCredentialsProvider
implements ToCopyableBuilder {
+ private static final String PROVIDER_NAME = "StsWebIdentityTokenFileCredentialsProvider";
private final AwsCredentialsProvider credentialsProvider;
private final RuntimeException loadException;
@@ -133,16 +133,11 @@ public AwsCredentials resolveCredentials() {
return credentialsProvider.resolveCredentials();
}
- @Override
- public String toString() {
- return ToString.create("StsWebIdentityTokenFileCredentialsProvider");
- }
-
@Override
protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) {
AssumeRoleWithWebIdentityRequest request = assumeRoleWithWebIdentityRequest.get();
notNull(request, "AssumeRoleWithWebIdentityRequest can't be null");
- return toAwsSessionCredentials(stsClient.assumeRoleWithWebIdentity(request).credentials());
+ return toAwsSessionCredentials(stsClient.assumeRoleWithWebIdentity(request).credentials(), PROVIDER_NAME);
}
@Override
@@ -150,6 +145,11 @@ public Builder toBuilder() {
return new Builder(this);
}
+ @Override
+ String providerName() {
+ return PROVIDER_NAME;
+ }
+
public static final class Builder extends BaseBuilder {
private String roleArn;
private String roleSessionName;
diff --git a/services/sts/src/main/java/software/amazon/awssdk/services/sts/internal/StsAuthUtils.java b/services/sts/src/main/java/software/amazon/awssdk/services/sts/internal/StsAuthUtils.java
index 1f02431e3a64..1de31d7f55ee 100644
--- a/services/sts/src/main/java/software/amazon/awssdk/services/sts/internal/StsAuthUtils.java
+++ b/services/sts/src/main/java/software/amazon/awssdk/services/sts/internal/StsAuthUtils.java
@@ -24,12 +24,13 @@ public final class StsAuthUtils {
private StsAuthUtils() {
}
- public static AwsSessionCredentials toAwsSessionCredentials(Credentials credentials) {
+ public static AwsSessionCredentials toAwsSessionCredentials(Credentials credentials, String provider) {
return AwsSessionCredentials.builder()
.accessKeyId(credentials.accessKeyId())
.secretAccessKey(credentials.secretAccessKey())
.sessionToken(credentials.sessionToken())
.expirationTime(credentials.expiration())
+ .providerName(provider)
.build();
}
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProviderTest.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProviderTest.java
index 03a76ad3d519..2c8a4878b6aa 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProviderTest.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProviderTest.java
@@ -44,4 +44,9 @@ protected StsAssumeRoleCredentialsProvider.Builder createCredentialsProviderBuil
protected AssumeRoleResponse callClient(StsClient client, AssumeRoleRequest request) {
return client.assumeRole(request);
}
+
+ @Override
+ protected String providerName() {
+ return "StsAssumeRoleCredentialsProvider";
+ }
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProviderTest.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProviderTest.java
index efae4de54547..624f4380e670 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProviderTest.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithSamlCredentialsProviderTest.java
@@ -47,4 +47,9 @@ protected Builder createCredentialsProviderBuilder(AssumeRoleWithSamlRequest req
protected AssumeRoleWithSamlResponse callClient(StsClient client, AssumeRoleWithSamlRequest request) {
return client.assumeRoleWithSAML(request);
}
+
+ @Override
+ protected String providerName() {
+ return "StsAssumeRoleWithSamlCredentialsProvider";
+ }
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProviderTest.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProviderTest.java
index d7f5510976d8..dfdcddd8fd45 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProviderTest.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsAssumeRoleWithWebIdentityCredentialsProviderTest.java
@@ -46,4 +46,9 @@ protected Builder createCredentialsProviderBuilder(AssumeRoleWithWebIdentityRequ
protected AssumeRoleWithWebIdentityResponse callClient(StsClient client, AssumeRoleWithWebIdentityRequest request) {
return client.assumeRoleWithWebIdentity(request);
}
+
+ @Override
+ protected String providerName() {
+ return "StsAssumeRoleWithWebIdentityCredentialsProvider";
+ }
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProviderTestBase.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProviderTestBase.java
index 9fae2499c603..f16f564a0a43 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProviderTestBase.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsCredentialsProviderTestBase.java
@@ -20,10 +20,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@@ -98,6 +96,8 @@ public void distantExpiringCredentialsUpdatedInBackground_OverridePrefetchAndSta
protected abstract ResponseT callClient(StsClient client, RequestT request);
+ protected abstract String providerName();
+
public void callClientWithCredentialsProvider(Instant credentialsExpirationDate, int numTimesInvokeCredentialsProvider, boolean overrideStaleAndPrefetchTimes) {
Credentials credentials = Credentials.builder().accessKeyId("a").secretAccessKey("b").sessionToken("c").expiration(credentialsExpirationDate).build();
RequestT request = getRequest();
@@ -129,6 +129,7 @@ public void callClientWithCredentialsProvider(Instant credentialsExpirationDate,
assertThat(providedCredentials.accessKeyId()).isEqualTo("a");
assertThat(providedCredentials.secretAccessKey()).isEqualTo("b");
assertThat(providedCredentials.sessionToken()).isEqualTo("c");
+ assertThat(providedCredentials.providerName()).isPresent().contains(providerName());
}
}
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProviderTest.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProviderTest.java
index 2663afacf18d..9d04a3c17baf 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProviderTest.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetFederationTokenCredentialsProviderTest.java
@@ -46,4 +46,9 @@ protected Builder createCredentialsProviderBuilder(GetFederationTokenRequest req
protected GetFederationTokenResponse callClient(StsClient client, GetFederationTokenRequest request) {
return client.getFederationToken(request);
}
+
+ @Override
+ protected String providerName() {
+ return "StsGetFederationTokenCredentialsProvider";
+ }
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProviderTest.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProviderTest.java
index ee2679ec1bf6..3dd7aaac267f 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProviderTest.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsGetSessionTokenCredentialsProviderTest.java
@@ -46,4 +46,9 @@ protected Builder createCredentialsProviderBuilder(GetSessionTokenRequest reques
protected GetSessionTokenResponse callClient(StsClient client, GetSessionTokenRequest request) {
return client.getSessionToken(request);
}
+
+ @Override
+ protected String providerName() {
+ return "StsGetSessionTokenCredentialsProvider";
+ }
}
diff --git a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenCredentialsProviderBaseTest.java b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenCredentialsProviderBaseTest.java
index f2498c8d3c52..eb08a86f7b6a 100644
--- a/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenCredentialsProviderBaseTest.java
+++ b/services/sts/src/test/java/software/amazon/awssdk/services/sts/auth/StsWebIdentityTokenCredentialsProviderBaseTest.java
@@ -77,6 +77,11 @@ protected AssumeRoleWithWebIdentityResponse callClient(StsClient client, AssumeR
return client.assumeRoleWithWebIdentity(request);
}
+ @Override
+ protected String providerName() {
+ return "StsAssumeRoleWithWebIdentityCredentialsProvider";
+ }
+
private String getToken(Path file) {
try (InputStream webIdentityTokenStream = Files.newInputStream(file)) {
return IoUtils.toUtf8String(webIdentityTokenStream);
diff --git a/test/auth-tests/pom.xml b/test/auth-tests/pom.xml
index 20178fad6c47..c03f087795e7 100644
--- a/test/auth-tests/pom.xml
+++ b/test/auth-tests/pom.xml
@@ -47,6 +47,18 @@
${awsjavasdk.version}
test
+
+ software.amazon.awssdk
+ identity-spi
+ ${awsjavasdk.version}
+ test
+
+
+ software.amazon.awssdk
+ http-client-spi
+ ${awsjavasdk.version}
+ test
+
software.amazon.awssdk
sts
@@ -98,6 +110,17 @@
junit-jupiter
test
+
+ org.mockito
+ mockito-core
+ test
+
+
+ software.amazon.awssdk
+ service-test-utils
+ ${awsjavasdk.version}
+ test
+
com.github.tomakehurst
wiremock-jre8
diff --git a/test/auth-tests/src/it/java/software/amazon/awssdk/auth/source/UserAgentProviderTest.java b/test/auth-tests/src/it/java/software/amazon/awssdk/auth/source/UserAgentProviderTest.java
new file mode 100644
index 000000000000..00671ed58238
--- /dev/null
+++ b/test/auth-tests/src/it/java/software/amazon/awssdk/auth/source/UserAgentProviderTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.auth.source;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static software.amazon.awssdk.core.internal.http.pipeline.stages.ApplyUserAgentStage.HEADER_USER_AGENT;
+
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.AwsCredentials;
+import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.http.AbortableInputStream;
+import software.amazon.awssdk.http.HttpExecuteResponse;
+import software.amazon.awssdk.http.SdkHttpClient;
+import software.amazon.awssdk.http.SdkHttpRequest;
+import software.amazon.awssdk.http.SdkHttpResponse;
+import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
+import software.amazon.awssdk.identity.spi.IdentityProvider;
+import software.amazon.awssdk.services.sts.StsClient;
+import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient;
+import software.amazon.awssdk.utils.StringInputStream;
+
+class UserAgentProviderTest {
+ private static final AwsCredentials BASIC_IDENTITY = basicCredentialsBuilder().build();
+ private static final AwsCredentials SESSION_IDENTITY = sessionCredentialsBuilder().build();
+
+ private MockSyncHttpClient mockHttpClient;
+
+ @BeforeEach
+ public void setup() throws UnsupportedEncodingException {
+ mockHttpClient = new MockSyncHttpClient();
+ mockHttpClient.stubNextResponse(mockResponse());
+ }
+
+ public static HttpExecuteResponse mockResponse() {
+ return HttpExecuteResponse.builder()
+ .response(SdkHttpResponse.builder().statusCode(200).build())
+ .responseBody(AbortableInputStream.create(new StringInputStream("")))
+ .build();
+ }
+
+ @ParameterizedTest
+ @MethodSource("credentialProviders")
+ void userAgentString_containsCredentialProviderNames_IfPresent(IdentityProvider extends AwsCredentialsIdentity> provider,
+ String expected) throws Exception {
+ stsClient(provider, mockHttpClient).getCallerIdentity();
+
+ SdkHttpRequest lastRequest = mockHttpClient.getLastRequest();
+ assertThat(lastRequest).isNotNull();
+
+ List userAgentHeaders = lastRequest.headers().get(HEADER_USER_AGENT);
+ assertThat(userAgentHeaders).isNotNull().hasSize(1);
+ assertThat(userAgentHeaders.get(0)).contains(expected);
+ }
+
+ private static Stream credentialProviders() {
+ return Stream.of(
+ Arguments.of(StaticCredentialsProvider.create(SESSION_IDENTITY), "stat"),
+ Arguments.of(StaticCredentialsProvider.create(BASIC_IDENTITY), "stat")
+ );
+ }
+
+ private static StsClient stsClient(IdentityProvider extends AwsCredentialsIdentity> provider, SdkHttpClient httpClient) {
+ return StsClient.builder()
+ .credentialsProvider(provider)
+ .httpClient(httpClient)
+ .build();
+ }
+
+ private static AwsSessionCredentials.Builder sessionCredentialsBuilder() {
+ return AwsSessionCredentials.builder()
+ .accessKeyId("akid")
+ .secretAccessKey("secret")
+ .sessionToken("token");
+ }
+
+ private static AwsBasicCredentials.Builder basicCredentialsBuilder() {
+ return AwsBasicCredentials.builder()
+ .accessKeyId("akid")
+ .secretAccessKey("secret");
+ }
+}