From 468fce7d920c35c3e8a63cef0d7ef89c78da89a2 Mon Sep 17 00:00:00 2001 From: David Negrete Date: Thu, 8 Dec 2022 08:16:55 -0700 Subject: [PATCH] Update public APIs to Supplier instead of ProfileFileSupplier --- .../DefaultCredentialsProvider.java | 17 ++++---- .../InstanceProfileCredentialsProvider.java | 21 +++++----- .../ProfileCredentialsProvider.java | 31 +++++++------- .../DefaultCredentialsProviderTest.java | 38 ++++++++++++++++- ...nstanceProfileCredentialsProviderTest.java | 42 +++++++++++++++++++ .../ProfileCredentialsProviderTest.java | 21 +++++++++- 6 files changed, 134 insertions(+), 36 deletions(-) diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.java index 4887deb2fac0..248a130c5864 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.java @@ -16,6 +16,7 @@ package software.amazon.awssdk.auth.credentials; import java.util.Optional; +import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.auth.credentials.internal.LazyAwsCredentialsProvider; import software.amazon.awssdk.profiles.ProfileFile; @@ -53,7 +54,7 @@ public final class DefaultCredentialsProvider private final LazyAwsCredentialsProvider providerChain; - private final ProfileFileSupplier profileFileSupplier; + private final Supplier profileFile; private final String profileName; @@ -65,7 +66,7 @@ public final class DefaultCredentialsProvider * @see #builder() */ private DefaultCredentialsProvider(Builder builder) { - this.profileFileSupplier = builder.profileFileSupplier; + this.profileFile = builder.profileFile; this.profileName = builder.profileName; this.reuseLastProviderEnabled = builder.reuseLastProviderEnabled; this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled; @@ -93,7 +94,7 @@ private static LazyAwsCredentialsProvider createChain(Builder builder) { EnvironmentVariableCredentialsProvider.create(), WebIdentityTokenFileCredentialsProvider.create(), ProfileCredentialsProvider.builder() - .profileFile(builder.profileFileSupplier) + .profileFile(builder.profileFile) .profileName(builder.profileName) .build(), ContainerCredentialsProvider.builder() @@ -101,7 +102,7 @@ private static LazyAwsCredentialsProvider createChain(Builder builder) { .build(), InstanceProfileCredentialsProvider.builder() .asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled) - .profileFile(builder.profileFileSupplier) + .profileFile(builder.profileFile) .profileName(builder.profileName) .build() }; @@ -146,7 +147,7 @@ public Builder toBuilder() { * Configuration that defines the {@link DefaultCredentialsProvider}'s behavior. */ public static final class Builder implements CopyableBuilder { - private ProfileFileSupplier profileFileSupplier; + private Supplier profileFile; private String profileName; private Boolean reuseLastProviderEnabled = true; private Boolean asyncCredentialUpdateEnabled = false; @@ -158,7 +159,7 @@ private Builder() { } private Builder(DefaultCredentialsProvider credentialsProvider) { - this.profileFileSupplier = credentialsProvider.profileFileSupplier; + this.profileFile = credentialsProvider.profileFile; this.profileName = credentialsProvider.profileName; this.reuseLastProviderEnabled = credentialsProvider.reuseLastProviderEnabled; this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled; @@ -170,8 +171,8 @@ public Builder profileFile(ProfileFile profileFile) { .orElse(null)); } - public Builder profileFile(ProfileFileSupplier profileFileSupplier) { - this.profileFileSupplier = profileFileSupplier; + public Builder profileFile(Supplier profileFileSupplier) { + this.profileFile = profileFileSupplier; return this; } 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 eb7e0f97b7bf..3fd3e7368c19 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 @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.Map; import java.util.Optional; +import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; import software.amazon.awssdk.auth.credentials.internal.Ec2MetadataConfigProvider; @@ -79,7 +80,7 @@ public final class InstanceProfileCredentialsProvider private final String asyncThreadName; - private final ProfileFileSupplier profileFileSupplier; + private final Supplier profileFile; private final String profileName; @@ -91,13 +92,13 @@ private InstanceProfileCredentialsProvider(BuilderImpl builder) { this.endpoint = builder.endpoint; this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled; this.asyncThreadName = builder.asyncThreadName; - this.profileFileSupplier = builder.profileFileSupplier; + this.profileFile = builder.profileFile; this.profileName = builder.profileName; this.httpCredentialsLoader = HttpCredentialsLoader.create(); this.configProvider = Ec2MetadataConfigProvider.builder() - .profileFile(builder.profileFileSupplier) + .profileFile(builder.profileFile) .profileName(builder.profileName) .build(); @@ -282,7 +283,7 @@ public interface Builder extends HttpCredentialsProvider.BuilderBy default, {@link ProfileFile#defaultProfileFile()} is used. * - * @see #profileFile(ProfileFileSupplier) + * @see #profileFile(Supplier) */ Builder profileFile(ProfileFile profileFile); @@ -292,7 +293,7 @@ public interface Builder extends HttpCredentialsProvider.Builder profileFileSupplier); /** * Configure the profile name used for loading IMDS-related configuration, like the endpoint mode (IPv4 vs IPv6). @@ -314,7 +315,7 @@ static final class BuilderImpl implements Builder { private String endpoint; private Boolean asyncCredentialUpdateEnabled; private String asyncThreadName; - private ProfileFileSupplier profileFileSupplier; + private Supplier profileFile; private String profileName; private BuilderImpl() { @@ -326,7 +327,7 @@ private BuilderImpl(InstanceProfileCredentialsProvider provider) { this.endpoint = provider.endpoint; this.asyncCredentialUpdateEnabled = provider.asyncCredentialUpdateEnabled; this.asyncThreadName = provider.asyncThreadName; - this.profileFileSupplier = provider.profileFileSupplier; + this.profileFile = provider.profileFile; this.profileName = provider.profileName; } @@ -377,12 +378,12 @@ public void setProfileFile(ProfileFile profileFile) { } @Override - public Builder profileFile(ProfileFileSupplier profileFileSupplier) { - this.profileFileSupplier = profileFileSupplier; + public Builder profileFile(Supplier profileFileSupplier) { + this.profileFile = profileFileSupplier; return this; } - public void setProfileFile(ProfileFileSupplier profileFileSupplier) { + public void setProfileFile(Supplier profileFileSupplier) { profileFile(profileFileSupplier); } diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProvider.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProvider.java index 34c0e2352a7b..b870b4f2b814 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProvider.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProvider.java @@ -51,7 +51,7 @@ public final class ProfileCredentialsProvider private AwsCredentialsProvider credentialsProvider; private final RuntimeException loadException; - private final ProfileFileSupplier profileFileSupplier; + private final Supplier profileFile; private volatile ProfileFile currentProfileFile; private final String profileName; private final Supplier defaultProfileFileLoader; @@ -64,15 +64,14 @@ private ProfileCredentialsProvider(BuilderImpl builder) { RuntimeException thrownException = null; String selectedProfileName = null; - ProfileFileSupplier selectedProfileSupplier = null; + Supplier selectedProfileSupplier = null; try { selectedProfileName = Optional.ofNullable(builder.profileName) .orElseGet(ProfileFileSystemSetting.AWS_PROFILE::getStringValueOrThrow); - selectedProfileSupplier = Optional.ofNullable(builder.profileFileSupplier) - .orElseGet(() -> ProfileFileSupplier - .fixedProfileFile(builder.defaultProfileFileLoader.get())); + selectedProfileSupplier = Optional.ofNullable(builder.profileFile) + .orElseGet(() -> builder.defaultProfileFileLoader); } catch (RuntimeException e) { // If we couldn't load the credentials provider for some reason, save an exception describing why. This exception @@ -83,7 +82,7 @@ private ProfileCredentialsProvider(BuilderImpl builder) { this.loadException = thrownException; this.profileName = selectedProfileName; - this.profileFileSupplier = selectedProfileSupplier; + this.profileFile = selectedProfileSupplier; } /** @@ -131,7 +130,7 @@ private void handleProfileFileReload(ProfileFile profileFile) { } private ProfileFile refreshProfileFile() { - return profileFileSupplier.get(); + return profileFile.get(); } private boolean isNewProfileFile(ProfileFile profileFile) { @@ -148,7 +147,9 @@ public String toString() { @Override public void close() { - profileFileSupplier.close(); + if (profileFile instanceof SdkAutoCloseable) { + ((SdkAutoCloseable) profileFile).close(); + } // The delegate credentials provider may be closeable (eg. if it's an STS credentials provider). In this case, we should // clean it up when this credentials provider is closed. IoUtils.closeIfCloseable(credentialsProvider, null); @@ -178,7 +179,7 @@ public interface Builder extends CopyableBuilder profileFileSupplier); /** * Define the name of the profile that should be used by this credentials provider. By default, the value in @@ -210,7 +211,7 @@ public interface Builder extends CopyableBuilder profileFile; private String profileName; private Supplier defaultProfileFileLoader = ProfileFile::defaultProfileFile; @@ -220,7 +221,7 @@ static final class BuilderImpl implements Builder { BuilderImpl(ProfileCredentialsProvider provider) { this.profileName = provider.profileName; this.defaultProfileFileLoader = provider.defaultProfileFileLoader; - this.profileFileSupplier = provider.profileFileSupplier; + this.profileFile = provider.profileFile; } @Override @@ -240,12 +241,12 @@ public Builder profileFile(Consumer profileFile) { } @Override - public Builder profileFile(ProfileFileSupplier profileFileSupplier) { - this.profileFileSupplier = profileFileSupplier; + public Builder profileFile(Supplier profileFileSupplier) { + this.profileFile = profileFileSupplier; return this; } - public void setProfileFile(ProfileFileSupplier supplier) { + public void setProfileFile(Supplier supplier) { profileFile(supplier); } diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProviderTest.java index a3f12a605c45..1c1c44bd140c 100644 --- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProviderTest.java +++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProviderTest.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSupplier; @@ -27,7 +28,7 @@ class DefaultCredentialsProviderTest { @Test - void resolveCredentials_requestFallsIntoProfileCredentialsProviderWithProfileFile_returnsCredentials() { + void resolveCredentials_ProfileCredentialsProviderWithProfileFile_returnsCredentials() { DefaultCredentialsProvider provider = DefaultCredentialsProvider .builder() .profileFile(credentialFile("test", "access", "secret")) @@ -41,7 +42,7 @@ void resolveCredentials_requestFallsIntoProfileCredentialsProviderWithProfileFil } @Test - void resolveCredentials_requestFallsIntoProfileCredentialsProviderWithProfileFileSupplier_returnsCredentials() { + void resolveCredentials_ProfileCredentialsProviderWithProfileFileSupplier_resolvesCredentialsPerCall() { List profileFileList = Arrays.asList(credentialFile("test", "access", "secret"), credentialFile("test", "modified", "update")); ProfileFileSupplier profileFileSupplier = supply(profileFileList); @@ -63,6 +64,39 @@ void resolveCredentials_requestFallsIntoProfileCredentialsProviderWithProfileFil }); } + @Test + void resolveCredentials_ProfileCredentialsProviderWithProfileFileSupplier_returnsCredentials() { + ProfileFile profileFile = credentialFile("test", "access", "secret"); + ProfileFileSupplier profileFileSupplier = ProfileFileSupplier.fixedProfileFile(profileFile); + + DefaultCredentialsProvider provider = DefaultCredentialsProvider + .builder() + .profileFile(profileFileSupplier) + .profileName("test") + .build(); + + assertThat(provider.resolveCredentials()).satisfies(awsCredentials -> { + assertThat(awsCredentials.accessKeyId()).isEqualTo("access"); + assertThat(awsCredentials.secretAccessKey()).isEqualTo("secret"); + }); + } + + @Test + void resolveCredentials_ProfileCredentialsProviderWithSupplierProfileFile_returnsCredentials() { + Supplier supplier = () -> credentialFile("test", "access", "secret"); + + DefaultCredentialsProvider provider = DefaultCredentialsProvider + .builder() + .profileFile(supplier) + .profileName("test") + .build(); + + assertThat(provider.resolveCredentials()).satisfies(awsCredentials -> { + assertThat(awsCredentials.accessKeyId()).isEqualTo("access"); + assertThat(awsCredentials.secretAccessKey()).isEqualTo("secret"); + }); + } + private ProfileFile credentialFile(String credentialFile) { return ProfileFile.builder() .content(new StringInputStream(credentialFile)) 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 fe6c7952fa30..0f32ed3c17bd 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 @@ -43,6 +43,7 @@ import java.time.ZoneOffset; import java.util.Arrays; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; import org.junit.AfterClass; import org.junit.Before; @@ -305,6 +306,47 @@ public void resolveCredentials_customProfileFileSupplierAndNameSettingEndpointOv } } + @Test + public void resolveCredentials_customSupplierProfileFileAndNameSettingEndpointOverride_usesCorrectEndpointFromSupplier() { + System.clearProperty(SdkSystemSetting.AWS_EC2_METADATA_SERVICE_ENDPOINT.property()); + WireMockServer mockMetadataEndpoint_2 = new WireMockServer(WireMockConfiguration.options().dynamicPort()); + mockMetadataEndpoint_2.start(); + try { + String stubToken = "some-token"; + mockMetadataEndpoint_2.stubFor(put(urlPathEqualTo(TOKEN_RESOURCE_PATH)).willReturn(aResponse().withBody(stubToken))); + mockMetadataEndpoint_2.stubFor(get(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH)).willReturn(aResponse().withBody("some-profile"))); + mockMetadataEndpoint_2.stubFor(get(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH + "some-profile")).willReturn(aResponse().withBody(STUB_CREDENTIALS))); + + String mockServer2Endpoint = "http://localhost:" + mockMetadataEndpoint_2.port(); + + ProfileFile config = configFile("profile test", + Pair.of(ProfileProperty.EC2_METADATA_SERVICE_ENDPOINT, mockServer2Endpoint)); + + Supplier supplier = () -> config; + + InstanceProfileCredentialsProvider provider = InstanceProfileCredentialsProvider + .builder() + .profileFile(supplier) + .profileName("test") + .build(); + + AwsCredentials awsCredentials1 = provider.resolveCredentials(); + + assertThat(awsCredentials1).isNotNull(); + + String userAgentHeader = "User-Agent"; + String userAgent = SdkUserAgent.create().userAgent(); + mockMetadataEndpoint_2.verify(putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)).withHeader(userAgentHeader, equalTo(userAgent))); + mockMetadataEndpoint_2.verify(getRequestedFor(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH)).withHeader(userAgentHeader, equalTo(userAgent))); + mockMetadataEndpoint_2.verify(getRequestedFor(urlPathEqualTo(CREDENTIALS_RESOURCE_PATH + "some-profile")).withHeader(userAgentHeader, equalTo(userAgent))); + + // all requests should have gone to the second server, and none to the other one + mockMetadataEndpoint.verify(0, RequestPatternBuilder.allRequests()); + } finally { + mockMetadataEndpoint_2.stop(); + } + } + @Test public void resolveCredentials_doesNotFailIfImdsReturnsExpiredCredentials() { String credentialsResponse = diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProviderTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProviderTest.java index b7eea2daff67..17b9b24ae092 100644 --- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProviderTest.java +++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/ProfileCredentialsProviderTest.java @@ -24,6 +24,7 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; +import java.util.function.Supplier; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -203,6 +204,23 @@ void resolveCredentials_presentProfileFileSupplier_returnsCredentials() { }); } + @Test + void resolveCredentials_presentSupplierProfileFile_returnsCredentials() { + Supplier supplier = () -> profileFile("[default]\naws_access_key_id = defaultAccessKey\n" + + "aws_secret_access_key = defaultSecretAccessKey\n"); + + ProfileCredentialsProvider provider = + ProfileCredentialsProvider.builder() + .profileFile(supplier) + .profileName("default") + .build(); + + assertThat(provider.resolveCredentials()).satisfies(credentials -> { + assertThat(credentials.accessKeyId()).isEqualTo("defaultAccessKey"); + assertThat(credentials.secretAccessKey()).isEqualTo("defaultSecretAccessKey"); + }); + } + @Test void create_noProfileName_returnsProfileCredentialsProviderToResolveWithDefaults() { ProfileCredentialsProvider provider = ProfileCredentialsProvider.create(); @@ -222,7 +240,8 @@ void create_givenProfileName_returnsProfileCredentialsProviderToResolveForGivenN @Test void toString_anyProfileCredentialsProviderAfterResolvingCredentialsFileDoesExists_returnsProfileFile() { ProfileCredentialsProvider provider = new ProfileCredentialsProvider.BuilderImpl() - .defaultProfileFileLoader(() -> profileFile("[default]\naws_access_key_id = %s\naws_secret_access_key = %s\n")) + .defaultProfileFileLoader(() -> profileFile("[default]\naws_access_key_id = not-set\n" + + "aws_secret_access_key = not-set\n")) .build(); provider.resolveCredentials(); String toString = provider.toString();