Skip to content

Adds accountId to STS credentials providers #4040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
import static software.amazon.awssdk.utils.StringUtils.trimToNull;

import java.util.Objects;
import java.util.Optional;
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;

/**
* Provides access to the AWS credentials used for accessing services: AWS access key ID and secret access key. These
* credentials are used to securely sign requests to services (e.g., AWS services) that use them for authentication.
* Provides access to the AWS credentials used for accessing services: AWS access key ID and secret access key. These credentials
* are used to securely sign requests to services (e.g., AWS services) that use them for authentication.
*
* <p>For more details on AWS access keys, see:
* <a href="https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys">
Expand All @@ -39,43 +40,43 @@
public final class AwsBasicCredentials implements AwsCredentials {
/**
* A set of AWS credentials without an access key or secret access key, indicating that anonymous access should be used.
*
* <p>
* This should be accessed via {@link AnonymousCredentialsProvider#resolveCredentials()}.
*/
@SdkInternalApi
static final AwsBasicCredentials ANONYMOUS_CREDENTIALS = new AwsBasicCredentials(null, null, false);
static final AwsBasicCredentials ANONYMOUS_CREDENTIALS = builder().build();

private final String accessKeyId;
private final String secretAccessKey;

/**
* Constructs a new credentials object, with the specified AWS access key and AWS secret key.
*
* @param accessKeyId The AWS access key, used to identify the user interacting with AWS.
* @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 final String accountId;

private AwsBasicCredentials(String accessKeyId, String secretAccessKey, boolean validateCredentials) {
this.accessKeyId = trimToNull(accessKeyId);
this.secretAccessKey = trimToNull(secretAccessKey);
private AwsBasicCredentials(Builder builder) {
this.accessKeyId = trimToNull(builder.accessKeyId);
this.secretAccessKey = trimToNull(builder.secretAccessKey);

if (validateCredentials) {
if (builder.validateCredentials) {
Validate.notNull(this.accessKeyId, "Access key ID cannot be blank.");
Validate.notNull(this.secretAccessKey, "Secret access key cannot be blank.");
}
this.accountId = builder.accountId;
}

public static Builder builder() {
return new Builder();
}

/**
* Constructs a new credentials object, with the specified AWS access key and AWS secret key.
*
* @param accessKeyId The AWS access key, used to identify the user interacting with AWS.
* @param accessKeyId The AWS access key, used to identify the user interacting with AWS.
* @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)
.validateCredentials(true)
.build();
}

/**
Expand All @@ -94,10 +95,16 @@ public String secretAccessKey() {
return secretAccessKey;
}

@Override
public Optional<String> accountId() {
return Optional.ofNullable(accountId);
}

@Override
public String toString() {
return ToString.builder("AwsCredentials")
.add("accessKeyId", accessKeyId)
.add("accountId", accountId)
.build();
}

Expand All @@ -111,14 +118,47 @@ public boolean equals(Object o) {
}
AwsBasicCredentials that = (AwsBasicCredentials) o;
return Objects.equals(accessKeyId, that.accessKeyId) &&
Objects.equals(secretAccessKey, that.secretAccessKey);
Objects.equals(secretAccessKey, that.secretAccessKey) &&
Objects.equals(accountId, that.accountId().orElse(null));
}

@Override
public int hashCode() {
int hashCode = 1;
hashCode = 31 * hashCode + Objects.hashCode(accessKeyId());
hashCode = 31 * hashCode + Objects.hashCode(secretAccessKey());
hashCode = 31 * hashCode + Objects.hashCode(accountId);
return hashCode;
}

public static final class Builder {
private String accessKeyId;
private String secretAccessKey;
private String accountId;
private boolean validateCredentials;

public Builder accessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
return this;
}

public Builder secretAccessKey(String secretAccessKey) {
this.secretAccessKey = secretAccessKey;
return this;
}

public Builder accountId(String accountId) {
this.accountId = accountId;
return this;
}

public Builder validateCredentials(boolean validateCredentials) {
this.validateCredentials = validateCredentials;
return this;
}

public AwsBasicCredentials build() {
return new AwsBasicCredentials(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package software.amazon.awssdk.auth.credentials;

import java.util.Objects;
import java.util.Optional;
import software.amazon.awssdk.annotations.Immutable;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity;
Expand All @@ -34,11 +35,17 @@ public final class AwsSessionCredentials implements AwsCredentials, AwsSessionCr
private final String accessKeyId;
private final String secretAccessKey;
private final String sessionToken;
private final String accountId;

private AwsSessionCredentials(String accessKey, String secretKey, String sessionToken) {
this.accessKeyId = Validate.paramNotNull(accessKey, "accessKey");
this.secretAccessKey = Validate.paramNotNull(secretKey, "secretKey");
this.sessionToken = Validate.paramNotNull(sessionToken, "sessionToken");
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.accountId = builder.accountId;
}

public static Builder builder() {
return new Builder();
}

/**
Expand All @@ -50,7 +57,7 @@ private AwsSessionCredentials(String accessKey, String secretKey, String session
* received temporary permission to access some resource.
*/
public static AwsSessionCredentials create(String accessKey, String secretKey, String sessionToken) {
return new AwsSessionCredentials(accessKey, secretKey, sessionToken);
return builder().accessKeyId(accessKey).secretAccessKey(secretKey).sessionToken(sessionToken).build();
}

@Override
Expand All @@ -68,10 +75,16 @@ public String sessionToken() {
return sessionToken;
}

@Override
public Optional<String> accountId() {
return Optional.ofNullable(accountId);
}

@Override
public String toString() {
return ToString.builder("AwsSessionCredentials")
.add("accessKeyId", accessKeyId())
.add("accountId", accountId)
.build();
}

Expand All @@ -87,7 +100,8 @@ public boolean equals(Object o) {
AwsSessionCredentials that = (AwsSessionCredentials) o;
return Objects.equals(accessKeyId, that.accessKeyId) &&
Objects.equals(secretAccessKey, that.secretAccessKey) &&
Objects.equals(sessionToken, that.sessionToken);
Objects.equals(sessionToken, that.sessionToken) &&
Objects.equals(accountId, that.accountId().orElse(null));
}

@Override
Expand All @@ -96,6 +110,38 @@ public int hashCode() {
hashCode = 31 * hashCode + Objects.hashCode(accessKeyId());
hashCode = 31 * hashCode + Objects.hashCode(secretAccessKey());
hashCode = 31 * hashCode + Objects.hashCode(sessionToken());
hashCode = 31 * hashCode + Objects.hashCode(accountId);
return hashCode;
}

public static final class Builder {
private String accessKeyId;
private String secretAccessKey;
private String sessionToken;
private String accountId;

public Builder accessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
return this;
}

public Builder secretAccessKey(String secretAccessKey) {
this.secretAccessKey = secretAccessKey;
return this;
}

public Builder sessionToken(String sessionToken) {
this.sessionToken = sessionToken;
return this;
}

public Builder accountId(String accountId) {
this.accountId = accountId;
return this;
}

public AwsSessionCredentials build() {
return new AwsSessionCredentials(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,21 @@ public static AwsCredentials toCredentials(AwsCredentialsIdentity awsCredentials
// identity-spi defines 2 known types - AwsCredentialsIdentity and a sub-type AwsSessionCredentialsIdentity
if (awsCredentialsIdentity instanceof AwsSessionCredentialsIdentity) {
AwsSessionCredentialsIdentity awsSessionCredentialsIdentity = (AwsSessionCredentialsIdentity) awsCredentialsIdentity;
return AwsSessionCredentials.create(awsSessionCredentialsIdentity.accessKeyId(),
awsSessionCredentialsIdentity.secretAccessKey(),
awsSessionCredentialsIdentity.sessionToken());
return AwsSessionCredentials.builder()
.accessKeyId(awsSessionCredentialsIdentity.accessKeyId())
.secretAccessKey(awsSessionCredentialsIdentity.secretAccessKey())
.sessionToken(awsSessionCredentialsIdentity.sessionToken())
.accountId(awsSessionCredentialsIdentity.accountId().orElse(null))
.build();
}
if (isAnonymous(awsCredentialsIdentity)) {
return AwsBasicCredentials.ANONYMOUS_CREDENTIALS;
}
return AwsBasicCredentials.create(awsCredentialsIdentity.accessKeyId(),
awsCredentialsIdentity.secretAccessKey());
return AwsBasicCredentials.builder()
.accessKeyId(awsCredentialsIdentity.accessKeyId())
.secretAccessKey(awsCredentialsIdentity.secretAccessKey())
.accountId(awsCredentialsIdentity.accountId().orElse(null))
.build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
public class StaticCredentialsProviderTest {
@Test
public void getAwsCredentials_ReturnsSameCredentials() throws Exception {
final AwsCredentials credentials = new AwsBasicCredentials("akid", "skid");
final AwsCredentials credentials = AwsBasicCredentials.create("akid", "skid");
final AwsCredentials actualCredentials =
StaticCredentialsProvider.create(credentials).resolveCredentials();
assertEquals(credentials, actualCredentials);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,74 @@
package software.amazon.awssdk.auth.credentials.internal;


import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity;
import software.amazon.awssdk.identity.spi.internal.DefaultAwsSessionCredentialsIdentity;

public 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 ACCOUNT_ID = "accountId";

@Test
public void equalsHashCode() {
AwsSessionCredentials credentials =
AwsSessionCredentials.create("test", "key", "sessionToken");

AwsSessionCredentials anotherCredentials =
AwsSessionCredentials.create("test", "key", "sessionToken");
assertThat(credentials).isEqualTo(anotherCredentials);
assertThat(credentials.hashCode()).isEqualTo(anotherCredentials.hashCode());
public void equalsHashcode() {
EqualsVerifier.forClass(DefaultAwsSessionCredentialsIdentity.class)
.verify();
}

@Test
public void emptyBuilder_ThrowsException() {
assertThrows(NullPointerException.class, () -> AwsSessionCredentialsIdentity.builder().build());
}

@Test
public void builderMissingSessionToken_ThrowsException() {
assertThrows(NullPointerException.class, () -> AwsSessionCredentialsIdentity.builder()
.accessKeyId(ACCESS_KEY_ID)
.secretAccessKey(SECRET_ACCESS_KEY)
.build());
}

@Test
public void builderMissingAccessKeyId_ThrowsException() {
assertThrows(NullPointerException.class, () -> AwsSessionCredentialsIdentity.builder()
.secretAccessKey(SECRET_ACCESS_KEY)
.sessionToken(SESSION_TOKEN)
.build());
}

@Test
public void create_isSuccessful() {
AwsSessionCredentialsIdentity identity = AwsSessionCredentialsIdentity.create(ACCESS_KEY_ID,
SECRET_ACCESS_KEY,
SESSION_TOKEN);
assertEquals(ACCESS_KEY_ID, identity.accessKeyId());
assertEquals(SECRET_ACCESS_KEY, identity.secretAccessKey());
assertEquals(SESSION_TOKEN, identity.sessionToken());
assertFalse(identity.accountId().isPresent());
}

@Test
public void build_isSuccessful() {
AwsSessionCredentialsIdentity identity = AwsSessionCredentialsIdentity.builder()
.accessKeyId(ACCESS_KEY_ID)
.secretAccessKey(SECRET_ACCESS_KEY)
.sessionToken(SESSION_TOKEN)
.accountId(ACCOUNT_ID)
.build();
assertEquals(ACCESS_KEY_ID, identity.accessKeyId());
assertEquals(SECRET_ACCESS_KEY, identity.secretAccessKey());
assertEquals(SESSION_TOKEN, identity.sessionToken());
assertTrue(identity.accountId().isPresent());
assertEquals(ACCOUNT_ID, identity.accountId().get());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,10 @@ public final class DefaultAwsSessionCredentialsIdentity implements AwsSessionCre


private DefaultAwsSessionCredentialsIdentity(Builder builder) {
this.accessKeyId = builder.accessKeyId;
this.secretAccessKey = builder.secretAccessKey;
this.sessionToken = builder.sessionToken;
this.accessKeyId = Validate.paramNotNull(builder.accessKeyId, "accessKeyId");
this.secretAccessKey = Validate.paramNotNull(builder.secretAccessKey, "secretAccessKey");
this.sessionToken = Validate.paramNotNull(builder.sessionToken, "sessionToken");
this.accountId = builder.accountId;

Validate.paramNotNull(accessKeyId, "accessKeyId");
Validate.paramNotNull(secretAccessKey, "secretAccessKey");
Validate.paramNotNull(sessionToken, "sessionToken");
}

public static AwsSessionCredentialsIdentity.Builder builder() {
Expand Down Expand Up @@ -86,7 +82,7 @@ public boolean equals(Object o) {
return Objects.equals(accessKeyId, that.accessKeyId()) &&
Objects.equals(secretAccessKey, that.secretAccessKey()) &&
Objects.equals(sessionToken, that.sessionToken()) &&
Objects.equals(accountId, that.accountId().orElse(null));
Objects.equals(accountId, that.accountId().orElse(null));
}

@Override
Expand Down
Loading