Skip to content

Add CopyableBuilder and ToCopyableBuilder interfaces to the credential providers. #3184

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
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;

/**
* {@link AwsCredentialsProvider} implementation that chains together multiple credentials providers.
Expand All @@ -44,7 +46,10 @@
* providers in the chain that need to be closed.</p>
*/
@SdkPublicApi
public final class AwsCredentialsProviderChain implements AwsCredentialsProvider, SdkAutoCloseable {
public final class AwsCredentialsProviderChain
implements AwsCredentialsProvider,
SdkAutoCloseable,
ToCopyableBuilder<AwsCredentialsProviderChain.Builder, AwsCredentialsProviderChain> {
private static final Logger log = Logger.loggerFor(AwsCredentialsProviderChain.class);

private final List<AwsCredentialsProvider> credentialsProviders;
Expand Down Expand Up @@ -124,10 +129,15 @@ public String toString() {
.build();
}

@Override
public Builder toBuilder() {
return new BuilderImpl(this);
}

/**
* A builder for a {@link AwsCredentialsProviderChain} that allows controlling its behavior.
*/
public interface Builder {
public interface Builder extends CopyableBuilder<Builder, AwsCredentialsProviderChain> {

/**
* Controls whether the chain should reuse the last successful credentials provider in the chain. Reusing the last
Expand Down Expand Up @@ -163,6 +173,11 @@ private static final class BuilderImpl implements Builder {
private BuilderImpl() {
}

private BuilderImpl(AwsCredentialsProviderChain provider) {
this.reuseLastProviderEnabled = provider.reuseLastProviderEnabled;
this.credentialsProviders = provider.credentialsProviders;
}

@Override
public Builder reuseLastProviderEnabled(Boolean reuseLastProviderEnabled) {
this.reuseLastProviderEnabled = reuseLastProviderEnabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import software.amazon.awssdk.utils.StringUtils;
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;
import software.amazon.awssdk.utils.cache.CachedSupplier;
import software.amazon.awssdk.utils.cache.NonBlocking;
import software.amazon.awssdk.utils.cache.RefreshResult;
Expand All @@ -60,18 +62,26 @@
* Service (ECS)</a>
*/
@SdkPublicApi
public final class ContainerCredentialsProvider implements HttpCredentialsProvider {
public final class ContainerCredentialsProvider
implements HttpCredentialsProvider,
ToCopyableBuilder<ContainerCredentialsProvider.Builder, ContainerCredentialsProvider> {
private static final Set<String> ALLOWED_HOSTS = unmodifiableSet(new HashSet<>(Arrays.asList("localhost", "127.0.0.1")));

private final String endpoint;
private final HttpCredentialsLoader httpCredentialsLoader;
private final CachedSupplier<AwsCredentials> credentialsCache;

private final Boolean asyncCredentialUpdateEnabled;

private final String asyncThreadName;

/**
* @see #builder()
*/
private ContainerCredentialsProvider(BuilderImpl builder) {
this.endpoint = builder.endpoint;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
this.asyncThreadName = builder.asyncThreadName;
this.httpCredentialsLoader = HttpCredentialsLoader.create();

if (Boolean.TRUE.equals(builder.asyncCredentialUpdateEnabled)) {
Expand Down Expand Up @@ -137,6 +147,11 @@ public void close() {
credentialsCache.close();
}

@Override
public Builder toBuilder() {
return new BuilderImpl(this);
}

static final class ContainerCredentialsEndpointProvider implements ResourcesEndpointProvider {
private final String endpoint;

Expand Down Expand Up @@ -209,18 +224,25 @@ private URI createGenericContainerUrl() {
/**
* A builder for creating a custom a {@link ContainerCredentialsProvider}.
*/
public interface Builder extends HttpCredentialsProvider.Builder<ContainerCredentialsProvider, Builder> {
public interface Builder extends HttpCredentialsProvider.Builder<ContainerCredentialsProvider, Builder>,
CopyableBuilder<Builder, ContainerCredentialsProvider> {
}

private static final class BuilderImpl implements Builder {
private String endpoint;
private Boolean asyncCredentialUpdateEnabled;
private String asyncThreadName;

BuilderImpl() {
private BuilderImpl() {
asyncThreadName("container-credentials-provider");
}

private BuilderImpl(ContainerCredentialsProvider credentialsProvider) {
this.endpoint = credentialsProvider.endpoint;
this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled;
this.asyncThreadName = credentialsProvider.asyncThreadName;
}

@Override
public Builder endpoint(String endpoint) {
this.endpoint = endpoint;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.utils.SdkAutoCloseable;
import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;

/**
* AWS credentials provider chain that looks for credentials in this order:
Expand All @@ -41,16 +43,30 @@
* @see InstanceProfileCredentialsProvider
*/
@SdkPublicApi
public final class DefaultCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable {
public final class DefaultCredentialsProvider
implements AwsCredentialsProvider, SdkAutoCloseable,
ToCopyableBuilder<DefaultCredentialsProvider.Builder, DefaultCredentialsProvider> {

private static final DefaultCredentialsProvider DEFAULT_CREDENTIALS_PROVIDER = new DefaultCredentialsProvider(builder());

private final LazyAwsCredentialsProvider providerChain;

private final ProfileFile profileFile;

private final String profileName;

private final Boolean reuseLastProviderEnabled;

private final Boolean asyncCredentialUpdateEnabled;

/**
* @see #builder()
*/
private DefaultCredentialsProvider(Builder builder) {
this.profileFile = builder.profileFile;
this.profileName = builder.profileName;
this.reuseLastProviderEnabled = builder.reuseLastProviderEnabled;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
this.providerChain = createChain(builder);
}

Expand Down Expand Up @@ -119,10 +135,15 @@ public String toString() {
.build();
}

@Override
public Builder toBuilder() {
return new Builder(this);
}

/**
* Configuration that defines the {@link DefaultCredentialsProvider}'s behavior.
*/
public static final class Builder {
public static final class Builder implements CopyableBuilder<Builder, DefaultCredentialsProvider> {
private ProfileFile profileFile;
private String profileName;
private Boolean reuseLastProviderEnabled = true;
Expand All @@ -134,6 +155,13 @@ public static final class Builder {
private Builder() {
}

private Builder(DefaultCredentialsProvider credentialsProvider) {
this.profileFile = credentialsProvider.profileFile;
this.profileName = credentialsProvider.profileName;
this.reuseLastProviderEnabled = credentialsProvider.reuseLastProviderEnabled;
this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled;
}

public Builder profileFile(ProfileFile profileFile) {
this.profileFile = profileFile;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import software.amazon.awssdk.utils.Logger;
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;
import software.amazon.awssdk.utils.cache.CachedSupplier;
import software.amazon.awssdk.utils.cache.NonBlocking;
import software.amazon.awssdk.utils.cache.RefreshResult;
Expand All @@ -54,7 +56,9 @@
* credentials from EC2 metadata service and will return null.
*/
@SdkPublicApi
public final class InstanceProfileCredentialsProvider implements HttpCredentialsProvider {
public final class InstanceProfileCredentialsProvider
implements HttpCredentialsProvider,
ToCopyableBuilder<InstanceProfileCredentialsProvider.Builder, InstanceProfileCredentialsProvider> {
private static final Logger log = Logger.loggerFor(InstanceProfileCredentialsProvider.class);
private static final String EC2_METADATA_TOKEN_HEADER = "x-aws-ec2-metadata-token";

Expand All @@ -69,6 +73,14 @@ public final class InstanceProfileCredentialsProvider implements HttpCredentials
private final HttpCredentialsLoader httpCredentialsLoader;
private final CachedSupplier<AwsCredentials> credentialsCache;

private final Boolean asyncCredentialUpdateEnabled;

private final String asyncThreadName;

private final ProfileFile profileFile;

private final String profileName;

private volatile LoadedCredentials cachedCredentials;

/**
Expand All @@ -77,6 +89,11 @@ public final class InstanceProfileCredentialsProvider implements HttpCredentials
private InstanceProfileCredentialsProvider(BuilderImpl builder) {
this.clock = builder.clock;
this.endpoint = builder.endpoint;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
this.asyncThreadName = builder.asyncThreadName;
this.profileFile = builder.profileFile;
this.profileName = builder.profileName;

this.httpCredentialsLoader = HttpCredentialsLoader.create();
this.configProvider =
Ec2MetadataConfigProvider.builder()
Expand Down Expand Up @@ -275,10 +292,16 @@ private Map<String, String> getTokenHeaders(String metadataToken) {
return Collections.singletonMap(EC2_METADATA_TOKEN_HEADER, metadataToken);
}

@Override
public Builder toBuilder() {
return new BuilderImpl(this);
}

/**
* A builder for creating a custom a {@link InstanceProfileCredentialsProvider}.
*/
public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfileCredentialsProvider, Builder> {
public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfileCredentialsProvider, Builder>,
CopyableBuilder<Builder, InstanceProfileCredentialsProvider> {
/**
* Configure the profile file used for loading IMDS-related configuration, like the endpoint mode (IPv4 vs IPv6).
*
Expand Down Expand Up @@ -312,6 +335,15 @@ private BuilderImpl() {
asyncThreadName("instance-profile-credentials-provider");
}

private BuilderImpl(InstanceProfileCredentialsProvider provider) {
this.clock = provider.clock;
this.endpoint = provider.endpoint;
this.asyncCredentialUpdateEnabled = provider.asyncCredentialUpdateEnabled;
this.asyncThreadName = provider.asyncThreadName;
this.profileFile = provider.profileFile;
this.profileName = provider.profileName;
}

Builder clock(Clock clock) {
this.clock = clock;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import software.amazon.awssdk.utils.Platform;
import software.amazon.awssdk.utils.SdkAutoCloseable;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
import software.amazon.awssdk.utils.cache.CachedSupplier;
import software.amazon.awssdk.utils.cache.NonBlocking;
import software.amazon.awssdk.utils.cache.RefreshResult;
Expand All @@ -54,17 +56,24 @@
* </ul>
*/
@SdkPublicApi
public final class ProcessCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable {
public final class ProcessCredentialsProvider
implements AwsCredentialsProvider,
SdkAutoCloseable,
ToCopyableBuilder<ProcessCredentialsProvider.Builder, ProcessCredentialsProvider> {
private static final JsonNodeParser PARSER = JsonNodeParser.builder()
.removeErrorLocations(true)
.build();

private final List<String> command;
private final List<String> executableCommand;
private final Duration credentialRefreshThreshold;
private final long processOutputLimit;

private final CachedSupplier<AwsCredentials> processCredentialCache;

private final String commandFromBuilder;

private final Boolean asyncCredentialUpdateEnabled;

/**
* @see #builder()
*/
Expand All @@ -83,9 +92,11 @@ private ProcessCredentialsProvider(Builder builder) {

cmd.add(builderCommand);

this.command = Collections.unmodifiableList(cmd);
this.executableCommand = Collections.unmodifiableList(cmd);
this.processOutputLimit = Validate.isPositive(builder.processOutputLimit, "processOutputLimit");
this.credentialRefreshThreshold = Validate.isPositive(builder.credentialRefreshThreshold, "expirationBuffer");
this.commandFromBuilder = builder.command;
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;

CachedSupplier.Builder<AwsCredentials> cacheBuilder = CachedSupplier.builder(this::refreshCredentials);
if (builder.asyncCredentialUpdateEnabled) {
Expand Down Expand Up @@ -185,7 +196,7 @@ private String getText(JsonNode jsonObject, String nodeName) {
* Execute the external process to retrieve credentials.
*/
private String executeCommand() throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(command);
ProcessBuilder processBuilder = new ProcessBuilder(executableCommand);

ByteArrayOutputStream commandOutput = new ByteArrayOutputStream();

Expand All @@ -210,10 +221,15 @@ public void close() {
processCredentialCache.close();
}

@Override
public Builder toBuilder() {
return new Builder(this);
}

/**
* Used to configure and create a {@link ProcessCredentialsProvider}. See {@link #builder()} creation.
*/
public static class Builder {
public static class Builder implements CopyableBuilder<Builder, ProcessCredentialsProvider> {
private Boolean asyncCredentialUpdateEnabled = false;
private String command;
private Duration credentialRefreshThreshold = Duration.ofSeconds(15);
Expand All @@ -225,6 +241,13 @@ public static class Builder {
private Builder() {
}

private Builder(ProcessCredentialsProvider provider) {
this.asyncCredentialUpdateEnabled = provider.asyncCredentialUpdateEnabled;
this.command = provider.commandFromBuilder;
this.credentialRefreshThreshold = provider.credentialRefreshThreshold;
this.processOutputLimit = provider.processOutputLimit;
}

/**
* Configure whether the provider should fetch credentials asynchronously in the background. If this is true, threads are
* less likely to block when credentials are loaded, but additional resources are used to maintain the provider.
Expand Down
Loading