From 8ac22a45ccda8ebe5f086a5d7f23cb2c3a7c3c82 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Tue, 7 Mar 2023 13:04:07 -0800 Subject: [PATCH 01/13] Accept and use the new AWS Credentials interfaces In AwsClientBuilder and other places where customers used to be able to provide AwsCredentialsProvider. --- .../codegen/poet/client/SyncClientClass.java | 2 + .../auth/credentials/CredentialUtils.java | 60 ++++++++++++++++++- .../signer/AwsSignerExecutionAttribute.java | 1 + .../AwsRequestOverrideConfiguration.java | 43 ++++++++++++- .../client/builder/AwsClientBuilder.java | 32 +++++++++- .../builder/AwsDefaultClientBuilder.java | 34 +++++++++-- .../client/config/AwsClientOption.java | 17 ++++++ .../internal/AwsExecutionContextBuilder.java | 30 ---------- .../AuthorizationStrategyFactory.java | 6 +- .../AwsCredentialsAuthorizationStrategy.java | 42 ++++++++----- .../config/AwsClientOptionValidation.java | 4 +- .../awscore/presigner/SdkPresigner.java | 33 +++++++++- .../awscore/client/utils/HttpTestUtils.java | 2 +- .../AwsExecutionContextBuilderTest.java | 2 +- ...sCredentialsAuthorizationStrategyTest.java | 12 ++-- pom.xml | 3 + .../presigner/DefaultPollyPresigner.java | 28 +++++++-- .../polly/presigner/PollyPresigner.java | 5 ++ .../presigner/DefaultPollyPresignerTest.java | 4 +- .../services/rds/DefaultRdsUtilities.java | 23 ++++--- .../awssdk/services/rds/RdsUtilities.java | 16 ++++- .../GenerateAuthenticationTokenRequest.java | 26 +++++++- .../internal/signing/DefaultSdkPresigner.java | 15 ++++- .../services/s3/presigner/S3Presigner.java | 5 ++ 24 files changed, 360 insertions(+), 85 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java index a653fd96c9e6..d917c5d801f5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java @@ -243,6 +243,8 @@ private List operationMethodSpecs(OperationModel opModel) { method.addStatement("$T cachedEndpoint = null", URI.class); method.beginControlFlow("if (endpointDiscoveryEnabled)"); + // TODO: If new clientOption for CREDENTIALS_IDENTITY_PROVIDER is used, this needs to be updated. + // Also see if use of AwsRequestOverrideConfiguration::credentialsProvider should be changed to new method. method.addCode("$T key = $N.overrideConfiguration()", String.class, opModel.getInput().getVariableName()) .addCode(" .flatMap($T::credentialsProvider)", AwsRequestOverrideConfiguration.class) .addCode(" .orElseGet(() -> clientConfiguration.option($T.CREDENTIALS_PROVIDER))", AwsClientOption.class) diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java index 6e4879b59c2a..fa9d121d2d2d 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java @@ -16,6 +16,9 @@ package software.amazon.awssdk.auth.credentials; import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; @SdkProtectedApi public final class CredentialUtils { @@ -27,7 +30,62 @@ private CredentialUtils() { * Determine whether the provided credentials are anonymous credentials, indicating that the customer is not attempting to * authenticate themselves. */ - public static boolean isAnonymous(AwsCredentials credentials) { + public static boolean isAnonymous(AwsCredentialsIdentity credentials) { return credentials.secretAccessKey() == null && credentials.accessKeyId() == null; } + + /** + * Converts an {@link AwsCredentialsIdentity} to {@link AwsCredentials}. + * + *

Usage of the new AwsCredentialsIdentity type is preferred over AwsCredentials. But some places may need to still + * convert to the older AwsCredentials type to work with existing code.

+ * + *

The conversion is only aware of {@link AwsCredentialsIdentity} and {@link AwsSessionCredentialsIdentity} types. If the + * input is another sub-type that has other properties, they are not carried over. i.e., + *

+ *

+ * + * @param awsCredentialsIdentity The {@link AwsCredentialsIdentity} to convert + * @return The corresponding {@link AwsCredentials} + */ + public static AwsCredentials toCredentials(AwsCredentialsIdentity awsCredentialsIdentity) { + // TODO: Is below safe? What if customer defines there own sub-type of AwsCredentialsIdentity?! Valid use case? + // If sub-type defines new properties, this conversion would be lossy. But does it matter, if no other code in + // `core` module care about types other than these 2? + // 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()); + } + if (isAnonymous(awsCredentialsIdentity)) { + return AwsBasicCredentials.ANONYMOUS_CREDENTIALS; + } + return AwsBasicCredentials.create(awsCredentialsIdentity.accessKeyId(), + awsCredentialsIdentity.secretAccessKey()); + } + + /** + * Converts an {@link IdentityProvider} to {@link AwsCredentialsProvider} based on + * {@link #toCredentials(AwsCredentialsIdentity)}. + * + *

Usage of the new IdentityProvider type is preferred over AwsCredentialsProvider. But some places may need to still + * convert to the older AwsCredentialsProvider type to work with existing code. + *

+ * + * @param identityProvider The {@link IdentityProvider} to convert + * @return The corresponding {@link AwsCredentialsProvider} + */ + public static AwsCredentialsProvider toCredentialsProvider( + IdentityProvider identityProvider) { + return () -> { + // TODO: Exception handling for CompletionException thrown from join? + AwsCredentialsIdentity awsCredentialsIdentity = identityProvider.resolveIdentity().join(); + return toCredentials(awsCredentialsIdentity); + }; + } } diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java b/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java index a90eae258660..a9a7062d2bc1 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java @@ -36,6 +36,7 @@ public final class AwsSignerExecutionAttribute extends SdkExecutionAttribute { /** * The key under which the request credentials are set. */ + // TODO: Can the type be changed to IdentityProvider? This class is @SdkProtectedApi public static final ExecutionAttribute AWS_CREDENTIALS = new ExecutionAttribute<>("AwsCredentials"); /** diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java index f101e0b06493..c077b743356d 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java @@ -19,7 +19,10 @@ import java.util.Optional; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.CredentialUtils; import software.amazon.awssdk.core.RequestOverrideConfiguration; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.utils.builder.SdkBuilder; /** @@ -58,10 +61,25 @@ public static AwsRequestOverrideConfiguration from(RequestOverrideConfiguration * * @return The optional {@link AwsCredentialsProvider}. */ + // TODO: Note, this method is called from generated public classes, when endpoint discover is involved. public Optional credentialsProvider() { return Optional.ofNullable(credentialsProvider); } + // TODO: Cannot change the return type of {@link #credentialsProvider()} so creating another method returning the same + // object but of new super type. + // TODO: As mentioned below, another option is to save reference of IdentityProvider and + // convert in above method. Either ways, need 2 methods to return the 2 different types. + /** + * The optional {@link IdentityProvider} that will provide credentials to be used to + * authenticate this request. + * + * @return The optional {@link IdentityProvider}. + */ + public Optional> credentialsIdentityProvider() { + return Optional.ofNullable(credentialsProvider); + } + @Override public Builder toBuilder() { return new BuilderImpl(this); @@ -103,7 +121,20 @@ public interface Builder extends RequestOverrideConfiguration.Builder, * @param credentialsProvider The {@link AwsCredentialsProvider}. * @return This object for chaining. */ - Builder credentialsProvider(AwsCredentialsProvider credentialsProvider); + default Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } + + /** + * Set the optional {@link IdentityProvider} that will provide credentials to be used + * to authenticate this request. + * + * @param credentialsProvider The {@link IdentityProvider}. + * @return This object for chaining. + */ + default Builder credentialsProvider(IdentityProvider credentialsProvider) { + throw new UnsupportedOperationException(); + } /** * Return the optional {@link AwsCredentialsProvider} that will provide credentials to be used to authenticate this @@ -136,10 +167,20 @@ private BuilderImpl(AwsRequestOverrideConfiguration awsRequestOverrideConfig) { @Override public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + // TODO: Another option: + // credentialsProvider((IdentityProvider) credentialsProvider); + // But that would lead to potentially converting a AwsCredentialsProvider to another AwsCredentialsProvider + // to fulfil AwsRequestOverrideConfiguration.credentialsProvider() to return AwsCredentialsProvider type. this.awsCredentialsProvider = credentialsProvider; return this; } + @Override + public Builder credentialsProvider(IdentityProvider credentialsProvider) { + this.awsCredentialsProvider = CredentialUtils.toCredentialsProvider(credentialsProvider); + return this; + } + @Override public AwsCredentialsProvider credentialsProvider() { return awsCredentialsProvider; diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsClientBuilder.java index 73d757919235..1e6c3f1c8e2d 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsClientBuilder.java @@ -19,6 +19,8 @@ import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode; import software.amazon.awssdk.core.client.builder.SdkClientBuilder; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; /** @@ -49,8 +51,36 @@ public interface AwsClientBuilderIf the credentials are not found in any of the locations above, an exception will be thrown at {@link #build()} time. *

+ * + *

The last of {@link #credentialsProvider(AwsCredentialsProvider)} or {@link #credentialsProvider(IdentityProvider)} + * wins.

+ */ + default BuilderT credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } + + /** + * Configure the credentials that should be used to authenticate with AWS. + * + *

The default provider will attempt to identify the credentials automatically using the following checks: + *

    + *
  1. Java System Properties - aws.accessKeyId and aws.secretAccessKey
  2. + *
  3. Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
  4. + *
  5. Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI
  6. + *
  7. Credentials delivered through the Amazon EC2 container service if AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment + * variable is set and security manager has permission to access the variable.
  8. + *
  9. Instance profile credentials delivered through the Amazon EC2 metadata service
  10. + *
+ * + *

If the credentials are not found in any of the locations above, an exception will be thrown at {@link #build()} time. + *

+ * + *

The last of {@link #credentialsProvider(AwsCredentialsProvider)} or {@link #credentialsProvider(IdentityProvider)} + * wins.

*/ - BuilderT credentialsProvider(AwsCredentialsProvider credentialsProvider); + default BuilderT credentialsProvider(IdentityProvider credentialsProvider) { + throw new UnsupportedOperationException(); + } /** * Configure the region with which the SDK should communicate. diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index c41e604afccb..ec05762109aa 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -48,6 +48,8 @@ import software.amazon.awssdk.core.retry.RetryPolicy; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.async.SdkAsyncHttpClient; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.ServiceMetadata; @@ -191,7 +193,8 @@ protected final SdkClientConfiguration finalizeChildConfiguration(SdkClientConfi configuration = mergeSmartDefaults(configuration); return configuration.toBuilder() - .option(AwsClientOption.CREDENTIALS_PROVIDER, resolveCredentials(configuration)) + .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, + resolveCredentialsIdentityProvider(configuration)) .option(SdkClientOption.ENDPOINT, resolveEndpoint(configuration)) .option(SdkClientOption.EXECUTION_INTERCEPTORS, addAwsInterceptors(configuration)) .option(AwsClientOption.SIGNING_REGION, resolveSigningRegion(configuration)) @@ -349,9 +352,10 @@ private Boolean resolveUseFipsFromDefaultProvider(SdkClientConfiguration config) /** * Resolve the credentials that should be used based on the customer's configuration. */ - private AwsCredentialsProvider resolveCredentials(SdkClientConfiguration config) { - return config.option(AwsClientOption.CREDENTIALS_PROVIDER) != null - ? config.option(AwsClientOption.CREDENTIALS_PROVIDER) + private IdentityProvider resolveCredentialsIdentityProvider(SdkClientConfiguration config) { + // Note, that CREDENTIALS_PROVIDER is never set. It is replaced with CREDENTIALS_IDENTITY_PROVIDER, so just check that + return config.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) != null + ? config.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) : DefaultCredentialsProvider.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)) @@ -419,16 +423,34 @@ public final void setFipsEnabled(Boolean fipsEndpointEnabled) { fipsEnabled(fipsEndpointEnabled); } + // TODO: Should the existing method just be removed? Anyone passing the sub type would still + // use the method with the new super type? @Override public final BuilderT credentialsProvider(AwsCredentialsProvider credentialsProvider) { - clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER, credentialsProvider); - return thisBuilder(); + // clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER, credentialsProvider); + // return thisBuilder(); + // TODO: by delegating to {@link #credentialsProvider(IdentityProvider)} we longer set + // AwsClientOption.CREDENTIALS_PROVIDER, thus removing need for validating that only one of the 2 is set. + // It may even let us remove the old AwsClientOption (or change the type) - maybe? + return credentialsProvider((IdentityProvider) credentialsProvider); } + // TODO: Not sure where the setter is used. Is it ok to delegate to new type (transitively from + // {@link #credentialsProvider(AwsCredentialsIdentity))}? public final void setCredentialsProvider(AwsCredentialsProvider credentialsProvider) { credentialsProvider(credentialsProvider); } + @Override + public final BuilderT credentialsProvider(IdentityProvider identityProvider) { + clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, identityProvider); + return thisBuilder(); + } + + public void setCredentialsProvider(IdentityProvider identityProvider) { + credentialsProvider(identityProvider); + } + private List addAwsInterceptors(SdkClientConfiguration config) { List interceptors = awsInterceptors(); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java index a063adbca51f..6556065c6216 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java @@ -21,16 +21,29 @@ import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder; import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode; import software.amazon.awssdk.core.client.config.ClientOption; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; @SdkProtectedApi public final class AwsClientOption extends ClientOption { + // TODO: Should the existing option be removed? + // Or replaced with same name (CREDENTIALS_PROVIDER) but new type below? + // This class is SdkProtectedApi, and it seems customer cannot create an option with this directly (we do it in + // AwsDefaultClientBuilder). Is there risk of old generated code when there are mixed versions of modules? + // If it is kept, should it be marked @Deprecated? /** * @see AwsClientBuilder#credentialsProvider(AwsCredentialsProvider) */ public static final AwsClientOption CREDENTIALS_PROVIDER = new AwsClientOption<>(AwsCredentialsProvider.class); + /** + * @see AwsClientBuilder#credentialsProvider(IdentityProvider) + */ + public static final AwsClientOption> CREDENTIALS_IDENTITY_PROVIDER = + new AwsClientOption<>(new UnsafeValueType(IdentityProvider.class)); + /** * AWS Region the client was configured with. Note that this is not always the signing region in the case of global * services like IAM. @@ -85,4 +98,8 @@ public final class AwsClientOption extends ClientOption { private AwsClientOption(Class valueClass) { super(valueClass); } + + private AwsClientOption(UnsafeValueType valueType) { + super(valueType); + } } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java index 32daaba3f3fb..0687cb793789 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java @@ -19,15 +19,12 @@ import static software.amazon.awssdk.core.interceptor.SdkExecutionAttribute.RESOLVED_CHECKSUM_SPECS; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.internal.authcontext.AuthorizationStrategy; import software.amazon.awssdk.awscore.internal.authcontext.AuthorizationStrategyFactory; import software.amazon.awssdk.core.HttpChecksumConstant; -import software.amazon.awssdk.core.RequestOverrideConfiguration; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SdkResponse; import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; @@ -138,33 +135,6 @@ private AwsExecutionContextBuilder() { .build(); } - /** - * Resolves the credentials provider, with the request override configuration taking precedence over the - * provided default. - * - * @return The credentials provider that will be used by the SDK to resolve credentials - */ - public static AwsCredentialsProvider resolveCredentialsProvider(SdkRequest originalRequest, - AwsCredentialsProvider defaultProvider) { - return originalRequest.overrideConfiguration() - .filter(c -> c instanceof AwsRequestOverrideConfiguration) - .map(c -> (AwsRequestOverrideConfiguration) c) - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElse(defaultProvider); - } - - /** - * Request override signers take precedence over the default alternative, for instance what is specified in the - * client. Request override signers can also be modified by modifyRequest interceptors. - * - * @return The signer that will be used by the SDK to sign the request - */ - public static Signer resolveSigner(SdkRequest request, Signer defaultSigner) { - return request.overrideConfiguration() - .flatMap(RequestOverrideConfiguration::signer) - .orElse(defaultSigner); - } - /** * Finalize {@link SdkRequest} by running beforeExecution and modifyRequest interceptors. * diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java index 938e2ff0a7f8..e56b44d01efe 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java @@ -16,7 +16,6 @@ package software.amazon.awssdk.awscore.internal.authcontext; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.core.CredentialType; @@ -24,6 +23,8 @@ import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricCollector; /** @@ -64,7 +65,8 @@ private TokenAuthorizationStrategy tokenAuthorizationStrategy() { private AwsCredentialsAuthorizationStrategy awsCredentialsAuthorizationStrategy() { Signer defaultSigner = clientConfiguration.option(SdkAdvancedClientOption.SIGNER); - AwsCredentialsProvider defaultCredentialsProvider = clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER); + IdentityProvider defaultCredentialsProvider = + clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); return AwsCredentialsAuthorizationStrategy.builder() .request(request) .defaultSigner(defaultSigner) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java index 01ad2dd5217b..8c6929e6dcba 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java @@ -18,7 +18,7 @@ import java.time.Duration; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.CredentialUtils; import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.core.RequestOverrideConfiguration; @@ -27,6 +27,8 @@ import software.amazon.awssdk.core.internal.util.MetricUtils; import software.amazon.awssdk.core.metrics.CoreMetric; import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.utils.Pair; import software.amazon.awssdk.utils.Validate; @@ -40,7 +42,7 @@ public final class AwsCredentialsAuthorizationStrategy implements AuthorizationS private final SdkRequest request; private final Signer defaultSigner; - private final AwsCredentialsProvider defaultCredentialsProvider; + private final IdentityProvider defaultCredentialsProvider; private final MetricCollector metricCollector; public AwsCredentialsAuthorizationStrategy(Builder builder) { @@ -73,8 +75,15 @@ public Signer resolveSigner() { */ @Override public void addCredentialsToExecutionAttributes(ExecutionAttributes executionAttributes) { - AwsCredentialsProvider credentialsProvider = resolveCredentialsProvider(request, defaultCredentialsProvider); - AwsCredentials credentials = resolveCredentials(credentialsProvider, metricCollector); + IdentityProvider credentialsProvider = + resolveCredentialsProvider(request, defaultCredentialsProvider); + // TODO: Other option is casting: + // AwsCredentials credentials = (AwsCredentials) resolveCredentials(credentialsProvider, metricCollector); + // This may be unsafe if there is a sub-type of AwsCredentialsIdentity that is not AwsCredentials. + // Like if customer creates an OdinAwsCredentialsIdentity which directly is-a AwsCredentialsIdentity. + AwsCredentials credentials = CredentialUtils.toCredentials(resolveCredentials(credentialsProvider, metricCollector)); + + // TODO: Should the signer be changed to use AwsCredentialsIdentity? Maybe with Signer SRA work, not now. executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, credentials); } @@ -84,22 +93,27 @@ public void addCredentialsToExecutionAttributes(ExecutionAttributes executionAtt * * @return The credentials provider that will be used by the SDK to resolve credentials */ - private static AwsCredentialsProvider resolveCredentialsProvider(SdkRequest originalRequest, - AwsCredentialsProvider defaultProvider) { + private static IdentityProvider resolveCredentialsProvider( + SdkRequest originalRequest, + IdentityProvider defaultProvider) { return originalRequest.overrideConfiguration() .filter(c -> c instanceof AwsRequestOverrideConfiguration) .map(c -> (AwsRequestOverrideConfiguration) c) - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) .orElse(defaultProvider); } - private static AwsCredentials resolveCredentials(AwsCredentialsProvider credentialsProvider, - MetricCollector metricCollector) { + private static AwsCredentialsIdentity resolveCredentials( + IdentityProvider credentialsProvider, + MetricCollector metricCollector) { Validate.notNull(credentialsProvider, "No credentials provider exists to resolve credentials from."); - Pair measured = MetricUtils.measureDuration(credentialsProvider::resolveCredentials); + // TODO: Exception handling for join()? + Pair measured = + MetricUtils.measureDuration(() -> credentialsProvider.resolveIdentity().join()); + metricCollector.reportMetric(CoreMetric.CREDENTIALS_FETCH_DURATION, measured.right()); - AwsCredentials credentials = measured.left(); + AwsCredentialsIdentity credentials = measured.left(); Validate.validState(credentials != null, "Credential providers must never return null."); return credentials; @@ -108,7 +122,7 @@ private static AwsCredentials resolveCredentials(AwsCredentialsProvider credenti public static final class Builder { private SdkRequest request; private Signer defaultSigner; - private AwsCredentialsProvider defaultCredentialsProvider; + private IdentityProvider defaultCredentialsProvider; private MetricCollector metricCollector; private Builder() { @@ -132,11 +146,11 @@ public Builder defaultSigner(Signer defaultSigner) { return this; } - public AwsCredentialsProvider defaultCredentialsProvider() { + public IdentityProvider defaultCredentialsProvider() { return this.defaultCredentialsProvider; } - public Builder defaultCredentialsProvider(AwsCredentialsProvider defaultCredentialsProvider) { + public Builder defaultCredentialsProvider(IdentityProvider defaultCredentialsProvider) { this.defaultCredentialsProvider = defaultCredentialsProvider; return this; } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java index 5dce8619099a..03138a42a3e6 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java @@ -39,8 +39,8 @@ public static void validateSyncClientOptions(SdkClientConfiguration c) { } private static void validateClientOptions(SdkClientConfiguration c) { - require("credentialsProvider", c.option(AwsClientOption.CREDENTIALS_PROVIDER)); - + // TODO: where does the field name come from? Should it be "credentialsIdentityProvider"? + require("credentialsProvider", c.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)); require("overrideConfiguration.advancedOption[AWS_REGION]", c.option(AwsClientOption.AWS_REGION)); require("overrideConfiguration.advancedOption[SIGNING_REGION]", c.option(AwsClientOption.SIGNING_REGION)); require("overrideConfiguration.advancedOption[SERVICE_SIGNING_NAME]", diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/presigner/SdkPresigner.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/presigner/SdkPresigner.java index f39bbb258b70..2d4fd8c9c1a4 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/presigner/SdkPresigner.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/presigner/SdkPresigner.java @@ -18,6 +18,8 @@ import java.net.URI; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.utils.SdkAutoCloseable; @@ -72,8 +74,37 @@ interface Builder { *

If the credentials are not found in any of the locations above, an exception will be thrown at {@link #build()} * time. *

+ * + *

The last of {@link #credentialsProvider(AwsCredentialsProvider)} or {@link #credentialsProvider(IdentityProvider)} + * wins.

+ */ + default Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } + + /** + * Configure the credentials that should be used to authenticate with AWS. + * + *

The default provider will attempt to identify the credentials automatically using the following checks: + *

    + *
  1. Java System Properties - aws.accessKeyId and aws.secretAccessKey
  2. + *
  3. Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
  4. + *
  5. Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI
  6. + *
  7. Credentials delivered through the Amazon EC2 container service if AWS_CONTAINER_CREDENTIALS_RELATIVE_URI + * environment variable is set and security manager has permission to access the variable.
  8. + *
  9. Instance profile credentials delivered through the Amazon EC2 metadata service
  10. + *
+ * + *

If the credentials are not found in any of the locations above, an exception will be thrown at {@link #build()} + * time. + *

+ * + *

The last of {@link #credentialsProvider(AwsCredentialsProvider)} or {@link #credentialsProvider(IdentityProvider)} + * wins.

*/ - Builder credentialsProvider(AwsCredentialsProvider credentialsProvider); + default Builder credentialsProvider(IdentityProvider credentialsProvider) { + throw new UnsupportedOperationException(); + } /** * Configure whether the SDK should use the AWS dualstack endpoint. diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java index e92e771f390f..37577e99376e 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/utils/HttpTestUtils.java @@ -54,7 +54,7 @@ public static SdkClientConfiguration testClientConfiguration() { .option(SdkClientOption.RETRY_POLICY, RetryPolicy.defaultRetryPolicy()) .option(SdkClientOption.ADDITIONAL_HTTP_HEADERS, new HashMap<>()) .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(AwsClientOption.CREDENTIALS_PROVIDER, DefaultCredentialsProvider.create()) + .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, DefaultCredentialsProvider.create()) .option(SdkAdvancedClientOption.SIGNER, new NoOpSigner()) .option(SdkAdvancedClientOption.USER_AGENT_PREFIX, "") .option(SdkAdvancedClientOption.USER_AGENT_SUFFIX, "") diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java index 67ef23a8426c..f6b67e84b2ba 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java @@ -209,7 +209,7 @@ private SdkClientConfiguration.Builder testClientConfiguration() { return SdkClientConfiguration.builder() .option(SdkClientOption.EXECUTION_INTERCEPTORS, new ArrayList<>()) .option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptorList) - .option(AwsClientOption.CREDENTIALS_PROVIDER, DefaultCredentialsProvider.create()) + .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, DefaultCredentialsProvider.create()) .option(SdkAdvancedClientOption.SIGNER, this.defaultSigner); } } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java index 282e048052dc..2561ece34c1f 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import java.util.Optional; @@ -26,8 +25,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.core.SdkRequest; @@ -41,14 +42,17 @@ public class AwsCredentialsAuthorizationStrategyTest { @Mock SdkRequest sdkRequest; @Mock Signer defaultSigner; @Mock Signer requestOverrideSigner; - @Mock AwsCredentialsProvider credentialsProvider; - @Mock AwsCredentials credentials; + AwsCredentialsProvider credentialsProvider; + AwsCredentials credentials; @Mock MetricCollector metricCollector; @Before public void setUp() throws Exception { when(sdkRequest.overrideConfiguration()).thenReturn(Optional.empty()); - when(credentialsProvider.resolveCredentials()).thenReturn(credentials); + // TODO: The below with using @Mock for credentialsProvider and credentials was giving a compile error, so not using mock + // when(credentialsProvider.resolveIdentity()).thenReturn(CompletableFuture.completedFuture(credentials)); + credentials = AwsBasicCredentials.create("foo", "bar"); + credentialsProvider = StaticCredentialsProvider.create(credentials); } @Test diff --git a/pom.xml b/pom.xml index a502bb6daf8b..4815145c74e8 100644 --- a/pom.xml +++ b/pom.xml @@ -634,6 +634,9 @@ software.amazon.awssdk.auth.credentials.AwsCredentials software.amazon.awssdk.auth.token.credentials.SdkToken + + + software.amazon.awssdk.auth.credentials.CredentialUtils true diff --git a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java index d939bdbc389d..702e7efc7bd1 100644 --- a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java +++ b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java @@ -30,6 +30,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.CredentialUtils; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; @@ -48,6 +49,8 @@ import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.regions.Region; @@ -72,7 +75,7 @@ public final class DefaultPollyPresigner implements PollyPresigner { private final Supplier profileFile; private final String profileName; private final Region region; - private final AwsCredentialsProvider credentialsProvider; + private final IdentityProvider credentialsProvider; private final URI endpointOverride; private final Boolean dualstackEnabled; private final Boolean fipsEnabled; @@ -112,7 +115,10 @@ public Region region() { return region; } - public AwsCredentialsProvider credentialsProvider() { + // TODO: Why are these 3 getters public? And why methods instead of accessing the members directly - used only inside this + // class. And this class is @SdkInternalApi + // Maybe package scope for unit test + public IdentityProvider credentialsProvider() { return credentialsProvider; } @@ -198,7 +204,7 @@ private SdkHttpFullRequest presignRequest(PollyRequest requestToPresign, private ExecutionAttributes createExecutionAttributes(PresignRequest presignRequest, PollyRequest requestToPresign) { Instant signatureExpiration = Instant.now().plus(presignRequest.signatureDuration()); - AwsCredentials credentials = resolveCredentialsProvider(requestToPresign).resolveCredentials(); + AwsCredentials credentials = resolveCredentials(resolveCredentialsProvider(requestToPresign)); Validate.validState(credentials != null, "Credential providers must never return null."); return new ExecutionAttributes() @@ -212,11 +218,16 @@ private ExecutionAttributes createExecutionAttributes(PresignRequest presignRequ .putAttribute(PRESIGNER_EXPIRATION, signatureExpiration); } - private AwsCredentialsProvider resolveCredentialsProvider(PollyRequest request) { - return request.overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsProvider) + private IdentityProvider resolveCredentialsProvider(PollyRequest request) { + return request.overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) .orElse(credentialsProvider()); } + private AwsCredentials resolveCredentials(IdentityProvider credentialsProvider) { + AwsCredentialsIdentity credentials = credentialsProvider.resolveIdentity().join(); + return CredentialUtils.toCredentials(credentials); + } + private Presigner resolvePresigner(PollyRequest request) { Signer signer = request.overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::signer) .orElse(DEFAULT_SIGNER); @@ -255,7 +266,7 @@ private URI resolveEndpoint() { public static class BuilderImpl implements PollyPresigner.Builder { private Region region; - private AwsCredentialsProvider credentialsProvider; + private IdentityProvider credentialsProvider; private URI endpointOverride; private Boolean dualstackEnabled; private Boolean fipsEnabled; @@ -268,6 +279,11 @@ public Builder region(Region region) { @Override public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } + + @Override + public Builder credentialsProvider(IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return this; } diff --git a/services/polly/src/main/java/software/amazon/awssdk/services/polly/presigner/PollyPresigner.java b/services/polly/src/main/java/software/amazon/awssdk/services/polly/presigner/PollyPresigner.java index 90602e481e86..61a24fa74ed9 100644 --- a/services/polly/src/main/java/software/amazon/awssdk/services/polly/presigner/PollyPresigner.java +++ b/services/polly/src/main/java/software/amazon/awssdk/services/polly/presigner/PollyPresigner.java @@ -22,6 +22,8 @@ import software.amazon.awssdk.awscore.presigner.PresignedRequest; import software.amazon.awssdk.awscore.presigner.SdkPresigner; import software.amazon.awssdk.http.SdkHttpClient; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.polly.internal.presigner.DefaultPollyPresigner; import software.amazon.awssdk.services.polly.model.PollyRequest; @@ -163,6 +165,9 @@ interface Builder extends SdkPresigner.Builder { @Override Builder credentialsProvider(AwsCredentialsProvider credentialsProvider); + @Override + Builder credentialsProvider(IdentityProvider credentialsProvider); + @Override Builder dualstackEnabled(Boolean dualstackEnabled); diff --git a/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java b/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java index 4d5cc4973ff3..78c2c78ee374 100644 --- a/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java +++ b/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java @@ -31,6 +31,8 @@ import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.polly.model.OutputFormat; import software.amazon.awssdk.services.polly.model.SynthesizeSpeechRequest; @@ -195,7 +197,7 @@ void presigner_credentialsProviderSetToNullByBuilder_createsDefaultCredentialsPr .build(); - AwsCredentialsProvider awsCredentialsProvider = presigner.credentialsProvider(); + IdentityProvider awsCredentialsProvider = presigner.credentialsProvider(); assertThat(awsCredentialsProvider).isNotNull(); } diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java index f77082792631..d5e9a958df18 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java @@ -20,13 +20,16 @@ import java.time.Instant; import software.amazon.awssdk.annotations.Immutable; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.CredentialUtils; import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.auth.signer.params.Aws4PresignerParams; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rds.model.GenerateAuthenticationTokenRequest; import software.amazon.awssdk.utils.StringUtils; @@ -39,7 +42,7 @@ final class DefaultRdsUtilities implements RdsUtilities { private final Aws4Signer signer = Aws4Signer.create(); private final Region region; - private final AwsCredentialsProvider credentialsProvider; + private final IdentityProvider credentialsProvider; private final Clock clock; DefaultRdsUtilities(DefaultBuilder builder) { @@ -79,7 +82,7 @@ public String generateAuthenticationToken(GenerateAuthenticationTokenRequest req Aws4PresignerParams presignRequest = Aws4PresignerParams.builder() .signingClockOverride(clock) .expirationTime(expirationTime) - .awsCredentials(resolveCredentials(request).resolveCredentials()) + .awsCredentials(resolveCredentials(request)) .signingName("rds-db") .signingRegion(resolveRegion(request)) .build(); @@ -105,13 +108,13 @@ private Region resolveRegion(GenerateAuthenticationTokenRequest request) { "or RdsUtilities object"); } - private AwsCredentialsProvider resolveCredentials(GenerateAuthenticationTokenRequest request) { + private AwsCredentials resolveCredentials(GenerateAuthenticationTokenRequest request) { if (request.credentialsProvider() != null) { - return request.credentialsProvider(); + return request.credentialsProvider().resolveCredentials(); } if (this.credentialsProvider != null) { - return this.credentialsProvider; + return CredentialUtils.toCredentials(this.credentialsProvider.resolveIdentity().join()); } throw new IllegalArgumentException("CredentialProvider should be provided either in GenerateAuthenticationTokenRequest " + @@ -121,13 +124,14 @@ private AwsCredentialsProvider resolveCredentials(GenerateAuthenticationTokenReq @SdkInternalApi static final class DefaultBuilder implements Builder { private Region region; - private AwsCredentialsProvider credentialsProvider; + private IdentityProvider credentialsProvider; DefaultBuilder() { } Builder clientConfiguration(SdkClientConfiguration clientConfiguration) { - this.credentialsProvider = clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER); + // TODO: update + this.credentialsProvider = clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); this.region = clientConfiguration.option(AwsClientOption.AWS_REGION); return this; @@ -139,8 +143,9 @@ public Builder region(Region region) { return this; } + // TODO: {@link #credentialsProvider(AwsCredentialsProvider)} uses the default implementation which call this @Override - public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + public Builder credentialsProvider(IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return this; } diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/RdsUtilities.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/RdsUtilities.java index d7ce5e19c06b..7e7394ec776c 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/RdsUtilities.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/RdsUtilities.java @@ -18,6 +18,8 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rds.model.GenerateAuthenticationTokenRequest; @@ -96,7 +98,19 @@ interface Builder { * * @return This object for method chaining */ - Builder credentialsProvider(AwsCredentialsProvider credentialsProvider); + default Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } + + /** + * The default credentials provider to use when working with the methods in {@link RdsUtilities} class. + * + * @return This object for method chaining + */ + default Builder credentialsProvider(IdentityProvider credentialsProvider) { + throw new UnsupportedOperationException(); + } + /** * Create a {@link RdsUtilities} diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java index fb13d6f95353..7f0492f8692a 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java @@ -18,6 +18,9 @@ import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.CredentialUtils; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rds.RdsUtilities; import software.amazon.awssdk.utils.Validate; @@ -77,6 +80,8 @@ public Region region() { * @return The credentials provider to sign the IAM auth request with. If specified, takes precedence over the value * specified in {@link RdsUtilities.Builder#credentialsProvider(AwsCredentialsProvider)}} */ + // TODO: should another method returning IdentityProvider be added and used in + // DefaultRdsUtilities? public AwsCredentialsProvider credentialsProvider() { return credentialsProvider; } @@ -131,10 +136,23 @@ public interface Builder extends CopyableBuilder) credentialsProvider); + } + + /** + * The credentials provider to sign the IAM auth request with. If specified, takes precedence over the value + * specified in {@link RdsUtilities.Builder#credentialsProvider(IdentityProvider)}} + * + * @return This object for method chaining + */ + default Builder credentialsProvider(IdentityProvider credentialsProvider) { + throw new UnsupportedOperationException(); + } @Override GenerateAuthenticationTokenRequest build(); @@ -188,6 +206,12 @@ public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { return this; } + @Override + public Builder credentialsProvider(IdentityProvider credentialsProvider) { + this.credentialsProvider = CredentialUtils.toCredentialsProvider(credentialsProvider); + return this; + } + @Override public GenerateAuthenticationTokenRequest build() { return new GenerateAuthenticationTokenRequest(this); diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java index b6df6e29fe7b..7a96ea5f0230 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java @@ -23,6 +23,8 @@ import software.amazon.awssdk.awscore.endpoint.DualstackEnabledProvider; import software.amazon.awssdk.awscore.endpoint.FipsEnabledProvider; import software.amazon.awssdk.awscore.presigner.SdkPresigner; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.regions.Region; @@ -42,7 +44,7 @@ public abstract class DefaultSdkPresigner implements SdkPresigner { private final String profileName; private final Region region; private final URI endpointOverride; - private final AwsCredentialsProvider credentialsProvider; + private final IdentityProvider credentialsProvider; private final Boolean dualstackEnabled; private final boolean fipsEnabled; @@ -88,7 +90,9 @@ protected Region region() { return region; } - protected AwsCredentialsProvider credentialsProvider() { + // TODO: only called in DefaultS3Presigner.invokeInterceptorsAndCreateExecutionContext to build the + // AwsCredentialsAuthorizationStrategy which now accepts IdentityProvider + protected IdentityProvider credentialsProvider() { return credentialsProvider; } @@ -116,7 +120,7 @@ public void close() { public abstract static class Builder> implements SdkPresigner.Builder { private Region region; - private AwsCredentialsProvider credentialsProvider; + private IdentityProvider credentialsProvider; private Boolean dualstackEnabled; private Boolean fipsEnabled; private URI endpointOverride; @@ -132,6 +136,11 @@ public B region(Region region) { @Override public B credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } + + @Override + public B credentialsProvider(IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return thisBuilder(); } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/presigner/S3Presigner.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/presigner/S3Presigner.java index c2aa3e457403..6d9be8376e26 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/presigner/S3Presigner.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/presigner/S3Presigner.java @@ -28,6 +28,8 @@ import software.amazon.awssdk.awscore.presigner.SdkPresigner; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.http.SdkHttpClient; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; import software.amazon.awssdk.services.s3.S3Configuration; @@ -539,6 +541,9 @@ interface Builder extends SdkPresigner.Builder { @Override Builder credentialsProvider(AwsCredentialsProvider credentialsProvider); + @Override + Builder credentialsProvider(IdentityProvider credentialsProvider); + @Override Builder dualstackEnabled(Boolean dualstackEnabled); From 6c3095b3efa610bf3069284adc5442634361e51f Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Fri, 10 Mar 2023 22:35:19 -0800 Subject: [PATCH 02/13] Update client codegen for endpoint discovery --- .../codegen/poet/client/AsyncClientClass.java | 7 ++++--- .../codegen/poet/client/SyncClientClass.java | 9 ++++----- .../client/test-endpoint-discovery-async.java | 18 +++++++++--------- .../client/test-endpoint-discovery-sync.java | 18 +++++++++--------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java index 7fd06cf8aa34..455d6c4b3056 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java @@ -363,9 +363,10 @@ protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, Operation builder.beginControlFlow("if (endpointDiscoveryEnabled)"); builder.addCode("$T key = $N.overrideConfiguration()", String.class, opModel.getInput().getVariableName()) - .addCode(" .flatMap($T::credentialsProvider)", AwsRequestOverrideConfiguration.class) - .addCode(" .orElseGet(() -> clientConfiguration.option($T.CREDENTIALS_PROVIDER))", AwsClientOption.class) - .addCode(" .resolveCredentials().accessKeyId();"); + .addCode(" .flatMap($T::credentialsIdentityProvider)", AwsRequestOverrideConfiguration.class) + .addCode(" .orElseGet(() -> clientConfiguration.option($T.CREDENTIALS_IDENTITY_PROVIDER))", + AwsClientOption.class) + .addCode(" .resolveIdentity().join().accessKeyId();"); builder.addCode("$1T endpointDiscoveryRequest = $1T.builder()", EndpointDiscoveryRequest.class) .addCode(" .required($L)", opModel.getInputShape().getEndpointDiscovery().isRequired()) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java index d917c5d801f5..519538135d73 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java @@ -243,12 +243,11 @@ private List operationMethodSpecs(OperationModel opModel) { method.addStatement("$T cachedEndpoint = null", URI.class); method.beginControlFlow("if (endpointDiscoveryEnabled)"); - // TODO: If new clientOption for CREDENTIALS_IDENTITY_PROVIDER is used, this needs to be updated. - // Also see if use of AwsRequestOverrideConfiguration::credentialsProvider should be changed to new method. method.addCode("$T key = $N.overrideConfiguration()", String.class, opModel.getInput().getVariableName()) - .addCode(" .flatMap($T::credentialsProvider)", AwsRequestOverrideConfiguration.class) - .addCode(" .orElseGet(() -> clientConfiguration.option($T.CREDENTIALS_PROVIDER))", AwsClientOption.class) - .addCode(" .resolveCredentials().accessKeyId();"); + .addCode(" .flatMap($T::credentialsIdentityProvider)", AwsRequestOverrideConfiguration.class) + .addCode(" .orElseGet(() -> clientConfiguration.option($T.CREDENTIALS_IDENTITY_PROVIDER))", + AwsClientOption.class) + .addCode(" .resolveIdentity().join().accessKeyId();"); method.addCode("$1T endpointDiscoveryRequest = $1T.builder()", EndpointDiscoveryRequest.class) .addCode(" .required($L)", opModel.getInputShape().getEndpointDiscovery().isRequired()) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java index 12ee3816aa6f..529d555c142e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java @@ -174,9 +174,9 @@ public CompletableFuture testDiscovery URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { String key = testDiscoveryIdentifiersRequiredRequest.overrideConfiguration() - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER)).resolveCredentials() - .accessKeyId(); + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) .overrideConfiguration(testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)) @@ -242,9 +242,9 @@ public CompletableFuture testDiscoveryOptional( URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { String key = testDiscoveryOptionalRequest.overrideConfiguration() - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER)).resolveCredentials() - .accessKeyId(); + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(false) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) .overrideConfiguration(testDiscoveryOptionalRequest.overrideConfiguration().orElse(null)).build(); @@ -317,9 +317,9 @@ public CompletableFuture testDiscoveryRequired( URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { String key = testDiscoveryRequiredRequest.overrideConfiguration() - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER)).resolveCredentials() - .accessKeyId(); + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) .overrideConfiguration(testDiscoveryRequiredRequest.overrideConfiguration().orElse(null)).build(); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java index d2fbf21bd173..6845c352a625 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java @@ -151,9 +151,9 @@ public TestDiscoveryIdentifiersRequiredResponse testDiscoveryIdentifiersRequired URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { String key = testDiscoveryIdentifiersRequiredRequest.overrideConfiguration() - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER)).resolveCredentials() - .accessKeyId(); + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) .overrideConfiguration(testDiscoveryIdentifiersRequiredRequest.overrideConfiguration().orElse(null)).build(); @@ -208,9 +208,9 @@ public TestDiscoveryOptionalResponse testDiscoveryOptional(TestDiscoveryOptional URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { String key = testDiscoveryOptionalRequest.overrideConfiguration() - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER)).resolveCredentials() - .accessKeyId(); + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(false) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) .overrideConfiguration(testDiscoveryOptionalRequest.overrideConfiguration().orElse(null)).build(); @@ -272,9 +272,9 @@ public TestDiscoveryRequiredResponse testDiscoveryRequired(TestDiscoveryRequired URI cachedEndpoint = null; if (endpointDiscoveryEnabled) { String key = testDiscoveryRequiredRequest.overrideConfiguration() - .flatMap(AwsRequestOverrideConfiguration::credentialsProvider) - .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER)).resolveCredentials() - .accessKeyId(); + .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) + .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) .overrideConfiguration(testDiscoveryRequiredRequest.overrideConfiguration().orElse(null)).build(); From 2247529dcbc5cf29e0981f34c3f139472c0ee650 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Thu, 23 Mar 2023 23:54:06 -0700 Subject: [PATCH 03/13] Address some of Matt's feedback --- .../auth/credentials/CredentialUtils.java | 11 +++-- .../signer/AwsSignerExecutionAttribute.java | 1 - .../AwsRequestOverrideConfiguration.java | 42 ++++++++++--------- .../builder/AwsDefaultClientBuilder.java | 31 +++++++------- .../client/config/AwsClientOption.java | 10 ++--- .../AuthorizationStrategyFactory.java | 5 ++- .../AwsCredentialsAuthorizationStrategy.java | 5 --- .../config/AwsClientOptionValidation.java | 1 - ...sCredentialsAuthorizationStrategyTest.java | 2 - pom.xml | 3 -- .../presigner/DefaultPollyPresigner.java | 35 +++++----------- .../services/rds/DefaultRdsUtilities.java | 7 ++-- .../GenerateAuthenticationTokenRequest.java | 29 +++++++------ .../internal/signing/DefaultSdkPresigner.java | 2 - 14 files changed, 82 insertions(+), 102 deletions(-) diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java index fa9d121d2d2d..b56e2d0d7def 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java @@ -26,6 +26,14 @@ public final class CredentialUtils { private CredentialUtils() { } + /** + * Determine whether the provided credentials are anonymous credentials, indicating that the customer is not attempting to + * authenticate themselves. + */ + public static boolean isAnonymous(AwsCredentials credentials) { + return isAnonymous((AwsCredentialsIdentity) credentials); + } + /** * Determine whether the provided credentials are anonymous credentials, indicating that the customer is not attempting to * authenticate themselves. @@ -52,9 +60,6 @@ public static boolean isAnonymous(AwsCredentialsIdentity credentials) { * @return The corresponding {@link AwsCredentials} */ public static AwsCredentials toCredentials(AwsCredentialsIdentity awsCredentialsIdentity) { - // TODO: Is below safe? What if customer defines there own sub-type of AwsCredentialsIdentity?! Valid use case? - // If sub-type defines new properties, this conversion would be lossy. But does it matter, if no other code in - // `core` module care about types other than these 2? // identity-spi defines 2 known types - AwsCredentialsIdentity and a sub-type AwsSessionCredentialsIdentity if (awsCredentialsIdentity instanceof AwsSessionCredentialsIdentity) { AwsSessionCredentialsIdentity awsSessionCredentialsIdentity = (AwsSessionCredentialsIdentity) awsCredentialsIdentity; diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java b/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java index a9a7062d2bc1..a90eae258660 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java @@ -36,7 +36,6 @@ public final class AwsSignerExecutionAttribute extends SdkExecutionAttribute { /** * The key under which the request credentials are set. */ - // TODO: Can the type be changed to IdentityProvider? This class is @SdkProtectedApi public static final ExecutionAttribute AWS_CREDENTIALS = new ExecutionAttribute<>("AwsCredentials"); /** diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java index c077b743356d..5c8b959d4f5f 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java @@ -30,11 +30,11 @@ */ @SdkPublicApi public final class AwsRequestOverrideConfiguration extends RequestOverrideConfiguration { - private final AwsCredentialsProvider credentialsProvider; + private final IdentityProvider credentialsProvider; private AwsRequestOverrideConfiguration(Builder builder) { super(builder); - this.credentialsProvider = builder.credentialsProvider(); + this.credentialsProvider = builder.credentialsIdentityProvider(); } /** @@ -61,15 +61,10 @@ public static AwsRequestOverrideConfiguration from(RequestOverrideConfiguration * * @return The optional {@link AwsCredentialsProvider}. */ - // TODO: Note, this method is called from generated public classes, when endpoint discover is involved. public Optional credentialsProvider() { - return Optional.ofNullable(credentialsProvider); + return Optional.ofNullable(CredentialUtils.toCredentialsProvider(credentialsProvider)); } - // TODO: Cannot change the return type of {@link #credentialsProvider()} so creating another method returning the same - // object but of new super type. - // TODO: As mentioned below, another option is to save reference of IdentityProvider and - // convert in above method. Either ways, need 2 methods to return the 2 different types. /** * The optional {@link IdentityProvider} that will provide credentials to be used to * authenticate this request. @@ -132,6 +127,7 @@ default Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) * @param credentialsProvider The {@link IdentityProvider}. * @return This object for chaining. */ + // review TODO: Should this be named credentialsIdentityProvider for symmetry with the "get" method default Builder credentialsProvider(IdentityProvider credentialsProvider) { throw new UnsupportedOperationException(); } @@ -144,14 +140,21 @@ default Builder credentialsProvider(IdentityProvider} that will provide credentials to be + * used to authenticate this request. + * + * @return The optional {@link IdentityProvider}. + */ + IdentityProvider credentialsIdentityProvider(); + @Override AwsRequestOverrideConfiguration build(); } private static final class BuilderImpl extends RequestOverrideConfiguration.BuilderImpl implements Builder { - private AwsCredentialsProvider awsCredentialsProvider; - + private IdentityProvider awsCredentialsProvider; private BuilderImpl() { } @@ -165,24 +168,25 @@ private BuilderImpl(AwsRequestOverrideConfiguration awsRequestOverrideConfig) { this.awsCredentialsProvider = awsRequestOverrideConfig.credentialsProvider; } + // review TODO: remove this since it is the same as the default interface implementation + // @Override + // public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + // return credentialsProvider((IdentityProvider) credentialsProvider); + // } + @Override - public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { - // TODO: Another option: - // credentialsProvider((IdentityProvider) credentialsProvider); - // But that would lead to potentially converting a AwsCredentialsProvider to another AwsCredentialsProvider - // to fulfil AwsRequestOverrideConfiguration.credentialsProvider() to return AwsCredentialsProvider type. + public Builder credentialsProvider(IdentityProvider credentialsProvider) { this.awsCredentialsProvider = credentialsProvider; return this; } @Override - public Builder credentialsProvider(IdentityProvider credentialsProvider) { - this.awsCredentialsProvider = CredentialUtils.toCredentialsProvider(credentialsProvider); - return this; + public AwsCredentialsProvider credentialsProvider() { + return CredentialUtils.toCredentialsProvider(awsCredentialsProvider); } @Override - public AwsCredentialsProvider credentialsProvider() { + public IdentityProvider credentialsIdentityProvider() { return awsCredentialsProvider; } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index ec05762109aa..92342b97e47b 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -25,6 +25,7 @@ import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.CredentialUtils; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.awscore.client.config.AwsAdvancedClientOption; import software.amazon.awssdk.awscore.client.config.AwsClientOption; @@ -192,9 +193,11 @@ protected final SdkClientConfiguration finalizeChildConfiguration(SdkClientConfi configuration = mergeSmartDefaults(configuration); + IdentityProvider identityProvider = resolveCredentialsIdentityProvider(configuration); return configuration.toBuilder() - .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, - resolveCredentialsIdentityProvider(configuration)) + .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, identityProvider) + // CREDENTIALS_PROVIDER is also set, since older clients may be relying on it + .option(AwsClientOption.CREDENTIALS_PROVIDER, toCredentialsProvider(identityProvider)) .option(SdkClientOption.ENDPOINT, resolveEndpoint(configuration)) .option(SdkClientOption.EXECUTION_INTERCEPTORS, addAwsInterceptors(configuration)) .option(AwsClientOption.SIGNING_REGION, resolveSigningRegion(configuration)) @@ -353,7 +356,6 @@ private Boolean resolveUseFipsFromDefaultProvider(SdkClientConfiguration config) * Resolve the credentials that should be used based on the customer's configuration. */ private IdentityProvider resolveCredentialsIdentityProvider(SdkClientConfiguration config) { - // Note, that CREDENTIALS_PROVIDER is never set. It is replaced with CREDENTIALS_IDENTITY_PROVIDER, so just check that return config.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) != null ? config.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) : DefaultCredentialsProvider.builder() @@ -362,6 +364,15 @@ private IdentityProvider resolveCredentialsIde .build(); } + // If resolveCredentialsIdentityProvider returns a DefaultCredentialsProvider (which is the more common usage), this avoids + // wrapping it in another AwsCredentialsProvider. + private AwsCredentialsProvider toCredentialsProvider(IdentityProvider identityProvider) { + return identityProvider instanceof AwsCredentialsProvider ? (AwsCredentialsProvider) identityProvider : + CredentialUtils.toCredentialsProvider(identityProvider); + } + + + private RetryPolicy resolveAwsRetryPolicy(SdkClientConfiguration config) { RetryPolicy policy = config.option(SdkClientOption.RETRY_POLICY); @@ -423,20 +434,6 @@ public final void setFipsEnabled(Boolean fipsEndpointEnabled) { fipsEnabled(fipsEndpointEnabled); } - // TODO: Should the existing method just be removed? Anyone passing the sub type would still - // use the method with the new super type? - @Override - public final BuilderT credentialsProvider(AwsCredentialsProvider credentialsProvider) { - // clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER, credentialsProvider); - // return thisBuilder(); - // TODO: by delegating to {@link #credentialsProvider(IdentityProvider)} we longer set - // AwsClientOption.CREDENTIALS_PROVIDER, thus removing need for validating that only one of the 2 is set. - // It may even let us remove the old AwsClientOption (or change the type) - maybe? - return credentialsProvider((IdentityProvider) credentialsProvider); - } - - // TODO: Not sure where the setter is used. Is it ok to delegate to new type (transitively from - // {@link #credentialsProvider(AwsCredentialsIdentity))}? public final void setCredentialsProvider(AwsCredentialsProvider credentialsProvider) { credentialsProvider(credentialsProvider); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java index 6556065c6216..aefab749f178 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java @@ -27,14 +27,14 @@ @SdkProtectedApi public final class AwsClientOption extends ClientOption { - // TODO: Should the existing option be removed? - // Or replaced with same name (CREDENTIALS_PROVIDER) but new type below? - // This class is SdkProtectedApi, and it seems customer cannot create an option with this directly (we do it in - // AwsDefaultClientBuilder). Is there risk of old generated code when there are mixed versions of modules? - // If it is kept, should it be marked @Deprecated? /** + // * This option is deprecated in favor of {@link #CREDENTIALS_IDENTITY_PROVIDER}. * @see AwsClientBuilder#credentialsProvider(AwsCredentialsProvider) */ + @Deprecated + // smithy codegen TODO: This could be removed when doing a minor version bump where we told customers we'll be breaking + // protected APIs. Postpone this to when we do Smithy code generator migration, where we'll likely have to start + // breaking a lot of protected things. public static final AwsClientOption CREDENTIALS_PROVIDER = new AwsClientOption<>(AwsCredentialsProvider.class); diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java index e56b44d01efe..0cffb7e9b355 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java @@ -65,8 +65,11 @@ private TokenAuthorizationStrategy tokenAuthorizationStrategy() { private AwsCredentialsAuthorizationStrategy awsCredentialsAuthorizationStrategy() { Signer defaultSigner = clientConfiguration.option(SdkAdvancedClientOption.SIGNER); + // Older generated clients may still be using CREDENTIALS_PROVIDER, so fall back to that. IdentityProvider defaultCredentialsProvider = - clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); + clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) != null + ? clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) + : clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER); return AwsCredentialsAuthorizationStrategy.builder() .request(request) .defaultSigner(defaultSigner) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java index 8c6929e6dcba..2ca040911efe 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategy.java @@ -77,12 +77,7 @@ public Signer resolveSigner() { public void addCredentialsToExecutionAttributes(ExecutionAttributes executionAttributes) { IdentityProvider credentialsProvider = resolveCredentialsProvider(request, defaultCredentialsProvider); - // TODO: Other option is casting: - // AwsCredentials credentials = (AwsCredentials) resolveCredentials(credentialsProvider, metricCollector); - // This may be unsafe if there is a sub-type of AwsCredentialsIdentity that is not AwsCredentials. - // Like if customer creates an OdinAwsCredentialsIdentity which directly is-a AwsCredentialsIdentity. AwsCredentials credentials = CredentialUtils.toCredentials(resolveCredentials(credentialsProvider, metricCollector)); - // TODO: Should the signer be changed to use AwsCredentialsIdentity? Maybe with Signer SRA work, not now. executionAttributes.putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, credentials); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java index 03138a42a3e6..d72f41356aa6 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/client/config/AwsClientOptionValidation.java @@ -39,7 +39,6 @@ public static void validateSyncClientOptions(SdkClientConfiguration c) { } private static void validateClientOptions(SdkClientConfiguration c) { - // TODO: where does the field name come from? Should it be "credentialsIdentityProvider"? require("credentialsProvider", c.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)); require("overrideConfiguration.advancedOption[AWS_REGION]", c.option(AwsClientOption.AWS_REGION)); require("overrideConfiguration.advancedOption[SIGNING_REGION]", c.option(AwsClientOption.SIGNING_REGION)); diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java index 2561ece34c1f..884e80d5ae28 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AwsCredentialsAuthorizationStrategyTest.java @@ -49,8 +49,6 @@ public class AwsCredentialsAuthorizationStrategyTest { @Before public void setUp() throws Exception { when(sdkRequest.overrideConfiguration()).thenReturn(Optional.empty()); - // TODO: The below with using @Mock for credentialsProvider and credentials was giving a compile error, so not using mock - // when(credentialsProvider.resolveIdentity()).thenReturn(CompletableFuture.completedFuture(credentials)); credentials = AwsBasicCredentials.create("foo", "bar"); credentialsProvider = StaticCredentialsProvider.create(credentials); } diff --git a/pom.xml b/pom.xml index 4815145c74e8..a502bb6daf8b 100644 --- a/pom.xml +++ b/pom.xml @@ -634,9 +634,6 @@ software.amazon.awssdk.auth.credentials.AwsCredentials software.amazon.awssdk.auth.token.credentials.SdkToken - - - software.amazon.awssdk.auth.credentials.CredentialUtils true diff --git a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java index 702e7efc7bd1..201818e8a358 100644 --- a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java +++ b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java @@ -28,7 +28,6 @@ import java.util.function.Supplier; import java.util.stream.Stream; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.CredentialUtils; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; @@ -111,21 +110,10 @@ private DefaultPollyPresigner(BuilderImpl builder) { .orElse(false); } - public Region region() { - return region; - } - - // TODO: Why are these 3 getters public? And why methods instead of accessing the members directly - used only inside this - // class. And this class is @SdkInternalApi - // Maybe package scope for unit test - public IdentityProvider credentialsProvider() { + IdentityProvider credentialsProvider() { return credentialsProvider; } - public URI endpointOverride() { - return endpointOverride; - } - @Override public void close() { IoUtils.closeIfCloseable(credentialsProvider, null); @@ -204,14 +192,14 @@ private SdkHttpFullRequest presignRequest(PollyRequest requestToPresign, private ExecutionAttributes createExecutionAttributes(PresignRequest presignRequest, PollyRequest requestToPresign) { Instant signatureExpiration = Instant.now().plus(presignRequest.signatureDuration()); - AwsCredentials credentials = resolveCredentials(resolveCredentialsProvider(requestToPresign)); + AwsCredentialsIdentity credentials = resolveCredentials(resolveCredentialsProvider(requestToPresign)); Validate.validState(credentials != null, "Credential providers must never return null."); return new ExecutionAttributes() - .putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, credentials) + .putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, CredentialUtils.toCredentials(credentials)) .putAttribute(AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME, SIGNING_NAME) - .putAttribute(AwsExecutionAttribute.AWS_REGION, region()) - .putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION, region()) + .putAttribute(AwsExecutionAttribute.AWS_REGION, region) + .putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION, region) .putAttribute(SdkInternalExecutionAttribute.IS_FULL_DUPLEX, false) .putAttribute(SdkExecutionAttribute.CLIENT_TYPE, ClientType.SYNC) .putAttribute(SdkExecutionAttribute.SERVICE_NAME, SERVICE_NAME) @@ -220,12 +208,11 @@ private ExecutionAttributes createExecutionAttributes(PresignRequest presignRequ private IdentityProvider resolveCredentialsProvider(PollyRequest request) { return request.overrideConfiguration().flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .orElse(credentialsProvider()); + .orElse(credentialsProvider); } - private AwsCredentials resolveCredentials(IdentityProvider credentialsProvider) { - AwsCredentialsIdentity credentials = credentialsProvider.resolveIdentity().join(); - return CredentialUtils.toCredentials(credentials); + private AwsCredentialsIdentity resolveCredentials(IdentityProvider credentialsProvider) { + return credentialsProvider.resolveIdentity().join(); } private Presigner resolvePresigner(PollyRequest request) { @@ -251,12 +238,12 @@ private void applyEndpoint(SdkHttpFullRequest.Builder httpRequestBuilder) { } private URI resolveEndpoint() { - if (endpointOverride() != null) { - return endpointOverride(); + if (endpointOverride != null) { + return endpointOverride; } return new DefaultServiceEndpointBuilder(SERVICE_NAME, "https") - .withRegion(region()) + .withRegion(region) .withProfileFile(profileFile) .withProfileName(profileName) .withDualstackEnabled(dualstackEnabled) diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java index d5e9a958df18..fd40e016bc9d 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/DefaultRdsUtilities.java @@ -108,9 +108,10 @@ private Region resolveRegion(GenerateAuthenticationTokenRequest request) { "or RdsUtilities object"); } + // TODO: update this to use AwsCredentialsIdentity when we migrate Signers to accept the new type. private AwsCredentials resolveCredentials(GenerateAuthenticationTokenRequest request) { - if (request.credentialsProvider() != null) { - return request.credentialsProvider().resolveCredentials(); + if (request.credentialsIdentityProvider() != null) { + return CredentialUtils.toCredentials(request.credentialsIdentityProvider().resolveIdentity().join()); } if (this.credentialsProvider != null) { @@ -130,7 +131,6 @@ static final class DefaultBuilder implements Builder { } Builder clientConfiguration(SdkClientConfiguration clientConfiguration) { - // TODO: update this.credentialsProvider = clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); this.region = clientConfiguration.option(AwsClientOption.AWS_REGION); @@ -143,7 +143,6 @@ public Builder region(Region region) { return this; } - // TODO: {@link #credentialsProvider(AwsCredentialsProvider)} uses the default implementation which call this @Override public Builder credentialsProvider(IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java index 7f0492f8692a..9c7f79888b0e 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/model/GenerateAuthenticationTokenRequest.java @@ -37,7 +37,7 @@ public final class GenerateAuthenticationTokenRequest implements private final int port; private final String username; private final Region region; - private final AwsCredentialsProvider credentialsProvider; + private final IdentityProvider credentialsProvider; private GenerateAuthenticationTokenRequest(BuilderImpl builder) { this.hostname = Validate.notEmpty(builder.hostname, "hostname"); @@ -78,11 +78,17 @@ public Region region() { /** * @return The credentials provider to sign the IAM auth request with. If specified, takes precedence over the value - * specified in {@link RdsUtilities.Builder#credentialsProvider(AwsCredentialsProvider)}} + * specified in {@link RdsUtilities.Builder#credentialsProvider}} */ - // TODO: should another method returning IdentityProvider be added and used in - // DefaultRdsUtilities? public AwsCredentialsProvider credentialsProvider() { + return CredentialUtils.toCredentialsProvider(credentialsProvider); + } + + /** + * @return The credentials provider to sign the IAM auth request with. If specified, takes precedence over the value + * specified in {@link RdsUtilities.Builder#credentialsProvider(AwsCredentialsProvider)}} + */ + public IdentityProvider credentialsIdentityProvider() { return credentialsProvider; } @@ -135,8 +141,7 @@ public interface Builder extends CopyableBuilder credentialsProvider; private BuilderImpl() { } @@ -200,15 +205,9 @@ public Builder region(Region region) { return this; } - @Override - public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { - this.credentialsProvider = credentialsProvider; - return this; - } - @Override public Builder credentialsProvider(IdentityProvider credentialsProvider) { - this.credentialsProvider = CredentialUtils.toCredentialsProvider(credentialsProvider); + this.credentialsProvider = credentialsProvider; return this; } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java index 7a96ea5f0230..921e7101a410 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultSdkPresigner.java @@ -90,8 +90,6 @@ protected Region region() { return region; } - // TODO: only called in DefaultS3Presigner.invokeInterceptorsAndCreateExecutionContext to build the - // AwsCredentialsAuthorizationStrategy which now accepts IdentityProvider protected IdentityProvider credentialsProvider() { return credentialsProvider; } From 30635e281b2dd22372d810943d48877434759b4e Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Mon, 27 Mar 2023 15:29:16 -0700 Subject: [PATCH 04/13] Switch one usage of overrideConfiguration.credentialsProvider To use the new credentialsIdentityProvider() instead. --- .../services/s3/internal/crt/DefaultS3CrtAsyncClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java index df8597a2e4ea..4f18a1fb4b05 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java @@ -253,7 +253,7 @@ private static void validateOverrideConfiguration(SdkRequest request) { } // TODO: support request-level credential override - if (overrideConfiguration.credentialsProvider().isPresent()) { + if (overrideConfiguration.credentialsIdentityProvider().isPresent()) { throw new UnsupportedOperationException("Request-level credentials override is not supported"); } From 093be1f96e46bfdba6f8e24cdda30617fe757f64 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Mon, 27 Mar 2023 16:38:25 -0700 Subject: [PATCH 05/13] Update tests to mock new IdentityProvider --- .../awssdk/services/metrics/CoreMetricsTest.java | 10 ++++++---- .../SyncClientMetricPublisherResolutionTest.java | 11 +++++++---- .../AsyncClientMetricPublisherResolutionTest.java | 11 +++++++---- .../metrics/async/AsyncCoreMetricsTest.java | 15 +++++---------- .../async/AsyncEventStreamingCoreMetricsTest.java | 9 +++++---- .../async/AsyncStreamingCoreMetricsTest.java | 9 +++++---- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/CoreMetricsTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/CoreMetricsTest.java index 0594f635d7ad..6e60d0307b7c 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/CoreMetricsTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/CoreMetricsTest.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.time.Duration; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import org.junit.After; import org.junit.Before; @@ -37,7 +38,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.core.metrics.CoreMetric; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.ExecutableHttpRequest; @@ -46,6 +46,8 @@ import software.amazon.awssdk.http.HttpMetric; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricCollection; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; @@ -70,7 +72,7 @@ public class CoreMetricsTest { private SdkHttpClient mockHttpClient; @Mock - private AwsCredentialsProvider mockCredentialsProvider; + private IdentityProvider mockCredentialsProvider; @Mock private MetricPublisher mockPublisher; @@ -106,13 +108,13 @@ public void setup() throws IOException { when(mockHttpClient.prepareRequest(any(HttpExecuteRequest.class))) .thenReturn(mockExecuteRequest); - when(mockCredentialsProvider.resolveCredentials()).thenAnswer(invocation -> { + when(mockCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> { try { Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } - return AwsBasicCredentials.create("foo", "bar"); + return CompletableFuture.completedFuture(AwsBasicCredentials.create("foo", "bar")); }); } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/SyncClientMetricPublisherResolutionTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/SyncClientMetricPublisherResolutionTest.java index e07c73703883..f2e2a0741728 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/SyncClientMetricPublisherResolutionTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/SyncClientMetricPublisherResolutionTest.java @@ -20,22 +20,25 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Arrays; +import java.util.concurrent.CompletableFuture; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.http.AbortableInputStream; import software.amazon.awssdk.http.ExecutableHttpRequest; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpFullResponse; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricCollection; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; @@ -49,7 +52,7 @@ public class SyncClientMetricPublisherResolutionTest { private SdkHttpClient mockHttpClient; @Mock - private AwsCredentialsProvider mockCredentialsProvider; + private IdentityProvider mockCredentialsProvider; private ProtocolRestJsonClient client; @@ -153,13 +156,13 @@ private ProtocolRestJsonClient clientWithPublishers(MetricPublisher... metricPub when(mockHttpClient.prepareRequest(any(HttpExecuteRequest.class))) .thenReturn(mockExecuteRequest); - when(mockCredentialsProvider.resolveCredentials()).thenAnswer(invocation -> { + when(mockCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> { try { Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } - return AwsBasicCredentials.create("foo", "bar"); + return CompletableFuture.completedFuture(AwsBasicCredentials.create("foo", "bar")); }); if (metricPublishers != null) { diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncClientMetricPublisherResolutionTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncClientMetricPublisherResolutionTest.java index 64d43fbe7560..3fabac4b7f10 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncClientMetricPublisherResolutionTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncClientMetricPublisherResolutionTest.java @@ -21,10 +21,12 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; + import com.github.tomakehurst.wiremock.junit.WireMockRule; import java.io.IOException; import java.net.URI; import java.util.Arrays; +import java.util.concurrent.CompletableFuture; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -34,7 +36,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricCollection; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; @@ -45,7 +48,7 @@ @RunWith(MockitoJUnitRunner.class) public class AsyncClientMetricPublisherResolutionTest { @Mock - private AwsCredentialsProvider mockCredentialsProvider; + private IdentityProvider mockCredentialsProvider; @Rule public WireMockRule wireMock = new WireMockRule(0); @@ -58,13 +61,13 @@ public class AsyncClientMetricPublisherResolutionTest { @Before public void setup() { - when(mockCredentialsProvider.resolveCredentials()).thenAnswer(invocation -> { + when(mockCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> { try { Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } - return AwsBasicCredentials.create("foo", "bar"); + return CompletableFuture.completedFuture(AwsBasicCredentials.create("foo", "bar")); }); } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncCoreMetricsTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncCoreMetricsTest.java index 7649fbae6fb0..30d04c2721a1 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncCoreMetricsTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncCoreMetricsTest.java @@ -24,12 +24,8 @@ import com.github.tomakehurst.wiremock.junit.WireMockRule; import java.io.IOException; import java.net.URI; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.function.Supplier; -import java.util.stream.Collectors; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -38,14 +34,13 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricCollection; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonAsyncClient; import software.amazon.awssdk.services.protocolrestjson.model.PaginatedOperationWithResultKeyResponse; -import software.amazon.awssdk.services.protocolrestjson.model.SimpleStruct; -import software.amazon.awssdk.services.protocolrestjson.paginators.PaginatedOperationWithResultKeyIterable; import software.amazon.awssdk.services.protocolrestjson.paginators.PaginatedOperationWithResultKeyPublisher; /** @@ -55,7 +50,7 @@ public class AsyncCoreMetricsTest extends BaseAsyncCoreMetricsTest { @Mock - private AwsCredentialsProvider mockCredentialsProvider; + private IdentityProvider mockCredentialsProvider; @Mock private MetricPublisher mockPublisher; @@ -75,13 +70,13 @@ public void setup() throws IOException { .overrideConfiguration(c -> c.addMetricPublisher(mockPublisher).retryPolicy(b -> b.numRetries(MAX_RETRIES))) .build(); - when(mockCredentialsProvider.resolveCredentials()).thenAnswer(invocation -> { + when(mockCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> { try { Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } - return AwsBasicCredentials.create("foo", "bar"); + return CompletableFuture.completedFuture(AwsBasicCredentials.create("foo", "bar")); }); } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncEventStreamingCoreMetricsTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncEventStreamingCoreMetricsTest.java index 534217c04110..b647df9e6f28 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncEventStreamingCoreMetricsTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncEventStreamingCoreMetricsTest.java @@ -28,9 +28,10 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.core.async.EmptyPublisher; import software.amazon.awssdk.core.signer.NoOpSigner; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonAsyncClient; @@ -46,7 +47,7 @@ public class AsyncEventStreamingCoreMetricsTest extends BaseAsyncCoreMetricsTest public WireMockRule wireMock = new WireMockRule(0); @Mock - private AwsCredentialsProvider mockCredentialsProvider; + private IdentityProvider mockCredentialsProvider; @Mock private MetricPublisher mockPublisher; @@ -64,13 +65,13 @@ public void setup() { .retryPolicy(b -> b.numRetries(MAX_RETRIES))) .build(); - when(mockCredentialsProvider.resolveCredentials()).thenAnswer(invocation -> { + when(mockCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> { try { Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } - return AwsBasicCredentials.create("foo", "bar"); + return CompletableFuture.completedFuture(AwsBasicCredentials.create("foo", "bar")); }); } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncStreamingCoreMetricsTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncStreamingCoreMetricsTest.java index 15b1aa5bf129..b73a85506785 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncStreamingCoreMetricsTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/metrics/async/AsyncStreamingCoreMetricsTest.java @@ -29,8 +29,9 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonAsyncClient; @@ -43,7 +44,7 @@ public class AsyncStreamingCoreMetricsTest extends BaseAsyncCoreMetricsTest { @Mock - private AwsCredentialsProvider mockCredentialsProvider; + private IdentityProvider mockCredentialsProvider; @Mock private MetricPublisher mockPublisher; @@ -62,13 +63,13 @@ public void setup() throws IOException { .overrideConfiguration(c -> c.addMetricPublisher(mockPublisher).retryPolicy(b -> b.numRetries(MAX_RETRIES))) .build(); - when(mockCredentialsProvider.resolveCredentials()).thenAnswer(invocation -> { + when(mockCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> { try { Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } - return AwsBasicCredentials.create("foo", "bar"); + return CompletableFuture.completedFuture(AwsBasicCredentials.create("foo", "bar")); }); } From 0a6bab35971cdf9b321da6bf91307be92cbaf343 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Mon, 27 Mar 2023 15:30:28 -0700 Subject: [PATCH 06/13] Handle null for CredentialUtils conversion methods --- .../amazon/awssdk/auth/credentials/CredentialUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java index b56e2d0d7def..2b855d145b3d 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java @@ -60,6 +60,9 @@ public static boolean isAnonymous(AwsCredentialsIdentity credentials) { * @return The corresponding {@link AwsCredentials} */ public static AwsCredentials toCredentials(AwsCredentialsIdentity awsCredentialsIdentity) { + if (awsCredentialsIdentity == null) { + return null; + } // identity-spi defines 2 known types - AwsCredentialsIdentity and a sub-type AwsSessionCredentialsIdentity if (awsCredentialsIdentity instanceof AwsSessionCredentialsIdentity) { AwsSessionCredentialsIdentity awsSessionCredentialsIdentity = (AwsSessionCredentialsIdentity) awsCredentialsIdentity; @@ -87,6 +90,9 @@ public static AwsCredentials toCredentials(AwsCredentialsIdentity awsCredentials */ public static AwsCredentialsProvider toCredentialsProvider( IdentityProvider identityProvider) { + if (identityProvider == null) { + return null; + } return () -> { // TODO: Exception handling for CompletionException thrown from join? AwsCredentialsIdentity awsCredentialsIdentity = identityProvider.resolveIdentity().join(); From 96bce3a0cf4791de349194360a107a2f530c873d Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Mon, 27 Mar 2023 23:41:40 -0700 Subject: [PATCH 07/13] Add IdentityProvider overload to S3CrtAsyncClientBuilder --- .../services/s3/S3CrtAsyncClientBuilder.java | 29 ++++++++++++++- .../crt/CrtCredentialsProviderAdapter.java | 20 +++++------ .../internal/crt/DefaultS3CrtAsyncClient.java | 36 +++---------------- .../crt/S3NativeClientConfiguration.java | 7 ++-- 4 files changed, 47 insertions(+), 45 deletions(-) diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.java index bba228b798eb..83dca2275214 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.java @@ -19,6 +19,8 @@ import java.nio.file.Path; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectRequest; @@ -30,6 +32,29 @@ @SdkPublicApi public interface S3CrtAsyncClientBuilder extends SdkBuilder { + /** + * Configure the credentials that should be used to authenticate with S3. + * + *

The default provider will attempt to identify the credentials automatically using the following checks: + *

    + *
  1. Java System Properties - aws.accessKeyId and aws.secretKey
  2. + *
  3. Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
  4. + *
  5. Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI
  6. + *
  7. Credentials delivered through the Amazon EC2 container service if AWS_CONTAINER_CREDENTIALS_RELATIVE_URI + * environment variable is set and security manager has permission to access the variable.
  8. + *
  9. Instance profile credentials delivered through the Amazon EC2 metadata service
  10. + *
+ * + *

If the credentials are not found in any of the locations above, an exception will be thrown at {@link #build()} + * time. + *

+ * + * @param credentialsProvider the credentials to use + * @return This builder for method chaining. + */ + default S3CrtAsyncClientBuilder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + return credentialsProvider((IdentityProvider) credentialsProvider); + } /** * Configure the credentials that should be used to authenticate with S3. @@ -51,7 +76,9 @@ public interface S3CrtAsyncClientBuilder extends SdkBuilder credentialsProvider) { + throw new UnsupportedOperationException(); + } /** * Configure the region with which the SDK should communicate. diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialsProviderAdapter.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialsProviderAdapter.java index 9ce93b028a93..8098782aaefc 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialsProviderAdapter.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialsProviderAdapter.java @@ -19,12 +19,13 @@ import java.nio.charset.StandardCharsets; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; -import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; import software.amazon.awssdk.crt.auth.credentials.Credentials; import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider; import software.amazon.awssdk.crt.auth.credentials.DelegateCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.utils.SdkAutoCloseable; /** @@ -32,10 +33,10 @@ */ @SdkInternalApi public final class CrtCredentialsProviderAdapter implements SdkAutoCloseable { - private final AwsCredentialsProvider credentialsProvider; + private final IdentityProvider credentialsProvider; private final CredentialsProvider crtCredentials; - public CrtCredentialsProviderAdapter(AwsCredentialsProvider credentialsProvider) { + public CrtCredentialsProviderAdapter(IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; this.crtCredentials = new DelegateCredentialsProvider.DelegateCredentialsProviderBuilder() .withHandler(() -> { @@ -44,18 +45,17 @@ public CrtCredentialsProviderAdapter(AwsCredentialsProvider credentialsProvider) return Credentials.createAnonymousCredentials(); } - AwsCredentials sdkCredentials = credentialsProvider.resolveCredentials(); + // TODO: Exception handling for join? + AwsCredentialsIdentity sdkCredentials = credentialsProvider.resolveIdentity().join(); byte[] accessKey = sdkCredentials.accessKeyId().getBytes(StandardCharsets.UTF_8); byte[] secreteKey = sdkCredentials.secretAccessKey().getBytes(StandardCharsets.UTF_8); byte[] sessionTokens = null; - if (sdkCredentials instanceof AwsSessionCredentials) { + if (sdkCredentials instanceof AwsSessionCredentialsIdentity) { sessionTokens = - ((AwsSessionCredentials) sdkCredentials).sessionToken().getBytes(StandardCharsets.UTF_8); + ((AwsSessionCredentialsIdentity) sdkCredentials).sessionToken().getBytes(StandardCharsets.UTF_8); } - return new Credentials(accessKey, - secreteKey, - sessionTokens); + return new Credentials(accessKey, secreteKey, sessionTokens); }).build(); } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java index 4f18a1fb4b05..b8506e7ac03f 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java @@ -22,7 +22,6 @@ import java.net.URI; import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.awscore.AwsRequest; import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.core.SdkRequest; @@ -37,6 +36,8 @@ import software.amazon.awssdk.core.retry.RetryPolicy; import software.amazon.awssdk.core.signer.NoOpSigner; import software.amazon.awssdk.http.SdkHttpExecutionAttributes; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.DelegatingS3AsyncClient; import software.amazon.awssdk.services.s3.S3AsyncClient; @@ -110,7 +111,7 @@ private static S3CrtAsyncHttpClient.Builder initializeS3CrtAsyncHttpClient(Defau public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientBuilder { private Long readBufferSizeInBytes; - private AwsCredentialsProvider credentialsProvider; + private IdentityProvider credentialsProvider; private Region region; private Long minimalPartSizeInBytes; private Double targetThroughputInGbps; @@ -118,36 +119,9 @@ public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientB private URI endpointOverride; private Boolean checksumValidationEnabled; - public AwsCredentialsProvider credentialsProvider() { - return credentialsProvider; - } - - public Region region() { - return region; - } - - public Long minimumPartSizeInBytes() { - return minimalPartSizeInBytes; - } - - public Double targetThroughputInGbps() { - return targetThroughputInGbps; - } - - public Integer maxConcurrency() { - return maxConcurrency; - } - - public URI endpointOverride() { - return endpointOverride; - } - - public Long readBufferSizeInBytes() { - return readBufferSizeInBytes; - } - @Override - public S3CrtAsyncClientBuilder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + public S3CrtAsyncClientBuilder credentialsProvider( + IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return this; } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java index 86a64fe1034c..142deadb289c 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java @@ -17,10 +17,11 @@ import java.net.URI; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider; import software.amazon.awssdk.crt.io.ClientBootstrap; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; import software.amazon.awssdk.utils.SdkAutoCloseable; @@ -119,7 +120,7 @@ public void close() { public static final class Builder { private Long readBufferSizeInBytes; private String signingRegion; - private AwsCredentialsProvider credentialsProvider; + private IdentityProvider credentialsProvider; private Long partSizeInBytes; private Double targetThroughputInGbps; private Integer maxConcurrency; @@ -134,7 +135,7 @@ public Builder signingRegion(String signingRegion) { return this; } - public Builder credentialsProvider(AwsCredentialsProvider credentialsProvider) { + public Builder credentialsProvider(IdentityProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return this; } From 4d372c9bbb225eb3128068985a36f9b12f51de93 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Tue, 28 Mar 2023 14:09:05 -0700 Subject: [PATCH 08/13] Add a TODO for removing a join() later --- .../codegen/poet/client/test-endpoint-discovery-async.java | 1 + 1 file changed, 1 insertion(+) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java index 529d555c142e..06458aaa5617 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java @@ -176,6 +176,7 @@ public CompletableFuture testDiscovery String key = testDiscoveryIdentifiersRequiredRequest.overrideConfiguration() .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) + // TODO: avoid join inside async .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) From 952a4fcba36d0add775e1cf45f75819aac269e73 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Tue, 28 Mar 2023 14:12:44 -0700 Subject: [PATCH 09/13] Add TODO for AwsCredentialsProviderChain --- .../awssdk/auth/credentials/AwsCredentialsProviderChain.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java index 3dd4a4ae4011..8a46cfc306e7 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java @@ -45,6 +45,7 @@ *

This chain implements {@link AutoCloseable}. When closed, it will call the {@link AutoCloseable#close()} on any credential * providers in the chain that need to be closed.

*/ +// TODO: deprecate with new IdentityProvider chain in identity-spi @SdkPublicApi public final class AwsCredentialsProviderChain implements AwsCredentialsProvider, From 51834e397ca354f5facdfcee213c17b363de6c6e Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Tue, 28 Mar 2023 23:35:03 -0700 Subject: [PATCH 10/13] Add unit tests and few other minor changes --- .../codegen/poet/client/AsyncClientClass.java | 1 + .../client/test-endpoint-discovery-async.java | 1 - .../auth/credentials/CredentialUtilsTest.java | 115 ++++++++++++++++++ .../AwsRequestOverrideConfiguration.java | 9 +- .../builder/AwsDefaultClientBuilder.java | 2 +- .../AwsRequestOverrideConfigurationTest.java | 54 ++++++++ .../AuthorizationStrategyFactoryTest.java | 45 ++++++- .../presigner/DefaultPollyPresignerTest.java | 29 ++++- .../services/rds/DefaultRdsUtilitiesTest.java | 54 ++++++-- .../service/AwsIntegrationTestBase.java | 7 +- 10 files changed, 291 insertions(+), 26 deletions(-) create mode 100644 core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java create mode 100644 core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java index 455d6c4b3056..8ca21f5a5612 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java @@ -366,6 +366,7 @@ protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, Operation .addCode(" .flatMap($T::credentialsIdentityProvider)", AwsRequestOverrideConfiguration.class) .addCode(" .orElseGet(() -> clientConfiguration.option($T.CREDENTIALS_IDENTITY_PROVIDER))", AwsClientOption.class) + // TODO: avoid join inside async .addCode(" .resolveIdentity().join().accessKeyId();"); builder.addCode("$1T endpointDiscoveryRequest = $1T.builder()", EndpointDiscoveryRequest.class) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java index 06458aaa5617..529d555c142e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java @@ -176,7 +176,6 @@ public CompletableFuture testDiscovery String key = testDiscoveryIdentifiersRequiredRequest.overrideConfiguration() .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) .orElseGet(() -> clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER)) - // TODO: avoid join inside async .resolveIdentity().join().accessKeyId(); EndpointDiscoveryRequest endpointDiscoveryRequest = EndpointDiscoveryRequest.builder().required(true) .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)) diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java new file mode 100644 index 000000000000..2b68ad493a0c --- /dev/null +++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java @@ -0,0 +1,115 @@ +/* + * 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; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.AwsSessionCredentialsIdentity; + +public class CredentialUtilsTest { + + @Test + public void isAnonymous_AwsCredentials_true() { + assertThat(CredentialUtils.isAnonymous(AwsBasicCredentials.ANONYMOUS_CREDENTIALS)).isTrue(); + } + + @Test + public void isAnonymous_AwsCredentials_false() { + assertThat(CredentialUtils.isAnonymous(AwsBasicCredentials.create("akid", "skid"))).isFalse(); + } + + @Test + public void isAnonymous_AwsCredentialsIdentity_true() { + assertThat(CredentialUtils.isAnonymous((AwsCredentialsIdentity) AwsBasicCredentials.ANONYMOUS_CREDENTIALS)).isTrue(); + } + + @Test + public void isAnonymous_AwsCredentialsIdentity_false() { + assertThat(CredentialUtils.isAnonymous((AwsCredentialsIdentity) AwsBasicCredentials.create("akid", "skid"))).isFalse(); + } + + @Test + public void toCredentials_null_returnsNull() { + assertThat(CredentialUtils.toCredentials(null)).isNull(); + } + + @Test + public void toCredentials_AwsSessionCredentialsIdentity_returnsAwsSessionCredentials() { + AwsCredentials awsCredentials = CredentialUtils.toCredentials(new AwsSessionCredentialsIdentity() { + @Override + public String accessKeyId() { + return "akid"; + } + + @Override + public String secretAccessKey() { + return "skid"; + } + + @Override + public String sessionToken() { + return "session"; + } + }); + + assertThat(awsCredentials).isInstanceOf(AwsSessionCredentials.class); + AwsSessionCredentials awsSessionCredentials = (AwsSessionCredentials) awsCredentials; + assertThat(awsSessionCredentials.accessKeyId()).isEqualTo("akid"); + assertThat(awsSessionCredentials.secretAccessKey()).isEqualTo("skid"); + assertThat(awsSessionCredentials.sessionToken()).isEqualTo("session"); + } + + @Test + public void toCredentials_AwsCredentialsIdentity_returnsAwsCredentials() { + AwsCredentials awsCredentials = CredentialUtils.toCredentials(new AwsCredentialsIdentity() { + @Override + public String accessKeyId() { + return "akid"; + } + + @Override + public String secretAccessKey() { + return "skid"; + } + }); + + assertThat(awsCredentials.accessKeyId()).isEqualTo("akid"); + assertThat(awsCredentials.secretAccessKey()).isEqualTo("skid"); + } + + @Test + public void toCredentials_Anonymous_returnsAnonymous() { + AwsCredentials awsCredentials = CredentialUtils.toCredentials(AwsBasicCredentials.ANONYMOUS_CREDENTIALS); + assertThat(awsCredentials.accessKeyId()).isNull(); + assertThat(awsCredentials.secretAccessKey()).isNull(); + } + + @Test + public void toCredentialsProvider_null_returnsNull() { + assertThat(CredentialUtils.toCredentialsProvider(null)).isNull(); + } + + @Test + public void toCredentialsProvider_IdentityProvider_converts() { + AwsCredentialsProvider credentialsProvider = CredentialUtils.toCredentialsProvider( + StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid"))); + AwsCredentials credentials = credentialsProvider.resolveCredentials(); + assertThat(credentials.accessKeyId()).isEqualTo("akid"); + assertThat(credentials.secretAccessKey()).isEqualTo("skid"); + } +} \ No newline at end of file diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java index 5c8b959d4f5f..5f3dc71b10c6 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfiguration.java @@ -132,6 +132,9 @@ default Builder credentialsProvider(IdentityProvider) credentialsProvider); - // } - @Override public Builder credentialsProvider(IdentityProvider credentialsProvider) { this.awsCredentialsProvider = credentialsProvider; diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index 92342b97e47b..09fc9c4b1fc9 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -444,7 +444,7 @@ public final BuilderT credentialsProvider(IdentityProvider identityProvider) { + public final void setCredentialsProvider(IdentityProvider identityProvider) { credentialsProvider(identityProvider); } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java new file mode 100644 index 000000000000..94ebe7bc810a --- /dev/null +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java @@ -0,0 +1,54 @@ +/* + * 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.awscore; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; + +public class AwsRequestOverrideConfigurationTest { + + @Test + public void testCredentialsProviderWorksWithBothOldAndNewInterfaceTypes() { + AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( + AwsBasicCredentials.create("akid","skid")); + + AwsRequestOverrideConfiguration configuration1 = AwsRequestOverrideConfiguration + .builder().credentialsProvider(credentialsProvider).build(); + + AwsRequestOverrideConfiguration configuration2 = AwsRequestOverrideConfiguration + .builder().credentialsProvider((IdentityProvider) credentialsProvider).build(); + + assertCredentialsEqual(configuration1.credentialsProvider().get(), configuration1.credentialsIdentityProvider().get()); + assertCredentialsEqual(configuration2.credentialsProvider().get(), configuration2.credentialsIdentityProvider().get()); + assertCredentialsEqual(configuration1.credentialsProvider().get(), configuration2.credentialsIdentityProvider().get()); + assertCredentialsEqual(configuration2.credentialsProvider().get(), configuration1.credentialsIdentityProvider().get()); + } + + private void assertCredentialsEqual(AwsCredentialsProvider credentialsProvider, + IdentityProvider identityProvider) { + AwsCredentials creds1 = credentialsProvider.resolveCredentials(); + AwsCredentialsIdentity creds2 = identityProvider.resolveIdentity().join(); + assertThat(creds1.accessKeyId()).isEqualTo(creds2.accessKeyId()); + assertThat(creds1.secretAccessKey()).isEqualTo(creds2.secretAccessKey()); + } +} \ No newline at end of file diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java index 1f48149c45ca..ec5ab60b60ef 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java @@ -16,19 +16,35 @@ package software.amazon.awssdk.awscore.internal.authcontext; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; -import org.junit.jupiter.api.Test; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; +import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.core.CredentialType; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.metrics.MetricCollector; +@RunWith(MockitoJUnitRunner.class) public class AuthorizationStrategyFactoryTest { @Mock SdkRequest sdkRequest; @Mock MetricCollector metricCollector; + @Before + public void setUp() throws Exception { + when(sdkRequest.overrideConfiguration()).thenReturn(Optional.empty()); + } + @Test public void credentialTypeBearerToken_returnsTokenStrategy() { AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, @@ -39,10 +55,33 @@ public void credentialTypeBearerToken_returnsTokenStrategy() { @Test public void credentialTypeAwsCredentials_returnsCredentialsStrategy() { - AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, - SdkClientConfiguration.builder().build()); + SdkClientConfiguration configuration = SdkClientConfiguration + .builder() + .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, StaticCredentialsProvider.create(AwsBasicCredentials.create( + "akid", "skid"))) + .build(); + AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, configuration); AuthorizationStrategy authorizationStrategy = factory.strategyFor(CredentialType.of("AWS")); assertThat(authorizationStrategy).isExactlyInstanceOf(AwsCredentialsAuthorizationStrategy.class); + ExecutionAttributes attributes = new ExecutionAttributes(); + authorizationStrategy.addCredentialsToExecutionAttributes(attributes); + assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).accessKeyId()).isEqualTo("akid"); + assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).secretAccessKey()).isEqualTo("skid"); } + @Test + public void credentialTypeAwsCredentials_withOldClientOption_returnsCredentialsStrategy() { + SdkClientConfiguration configuration = SdkClientConfiguration + .builder() + .option(AwsClientOption.CREDENTIALS_PROVIDER, StaticCredentialsProvider.create(AwsBasicCredentials.create( + "akid", "skid"))) + .build(); + AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, configuration); + AuthorizationStrategy authorizationStrategy = factory.strategyFor(CredentialType.of("AWS")); + assertThat(authorizationStrategy).isExactlyInstanceOf(AwsCredentialsAuthorizationStrategy.class); + ExecutionAttributes attributes = new ExecutionAttributes(); + authorizationStrategy.addCredentialsToExecutionAttributes(attributes); + assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).accessKeyId()).isEqualTo("akid"); + assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).secretAccessKey()).isEqualTo("skid"); + } } diff --git a/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java b/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java index 78c2c78ee374..30491ef287ea 100644 --- a/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java +++ b/services/polly/src/test/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresignerTest.java @@ -27,7 +27,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; @@ -50,7 +49,7 @@ class DefaultPollyPresignerTest { .text("Hello presigners!") .build(); - private AwsCredentialsProvider credentialsProvider; + private IdentityProvider credentialsProvider; @BeforeEach public void methodSetup() { @@ -59,7 +58,9 @@ public void methodSetup() { @Test void presign_requestLevelCredentials_honored() { - AwsCredentials requestCredentials = AwsBasicCredentials.create("akid2", "skid2"); + IdentityProvider requestCedentialsProvider = StaticCredentialsProvider.create( + AwsBasicCredentials.create("akid2", "skid2") + ); PollyPresigner presigner = DefaultPollyPresigner.builder() .region(Region.US_EAST_1) @@ -68,7 +69,7 @@ void presign_requestLevelCredentials_honored() { SynthesizeSpeechRequest synthesizeSpeechRequest = BASIC_SYNTHESIZE_SPEECH_REQUEST.toBuilder() .overrideConfiguration(AwsRequestOverrideConfiguration.builder() - .credentialsProvider(StaticCredentialsProvider.create(requestCredentials)).build()) + .credentialsProvider(requestCedentialsProvider).build()) .build(); SynthesizeSpeechPresignRequest presignRequest = SynthesizeSpeechPresignRequest.builder() @@ -188,6 +189,24 @@ void close_closesCustomCloseableCredentialsProvider() throws IOException { verify(mockCredentialsProvider).close(); } + @Test + void presigner_credentialsProviderSetAsAwsCredentialsProvider_delegatesCorrectly() { + AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid")); + DefaultPollyPresigner presigner1 = (DefaultPollyPresigner) + DefaultPollyPresigner.builder() + .region(Region.US_EAST_1) + .credentialsProvider(credentialsProvider) + .build(); + + DefaultPollyPresigner presigner2 = (DefaultPollyPresigner) + DefaultPollyPresigner.builder() + .region(Region.US_EAST_1) + .credentialsProvider((IdentityProvider) credentialsProvider) + .build(); + + assertThat(presigner1.credentialsProvider()).isSameAs(presigner2.credentialsProvider()); + } + @Test void presigner_credentialsProviderSetToNullByBuilder_createsDefaultCredentialsProvider() { DefaultPollyPresigner presigner = (DefaultPollyPresigner) @@ -201,6 +220,6 @@ void presigner_credentialsProviderSetToNullByBuilder_createsDefaultCredentialsPr assertThat(awsCredentialsProvider).isNotNull(); } - private interface TestCredentialsProvider extends AwsCredentialsProvider, Closeable { + private interface TestCredentialsProvider extends IdentityProvider, Closeable { } } diff --git a/services/rds/src/test/java/software/amazon/awssdk/services/rds/DefaultRdsUtilitiesTest.java b/services/rds/src/test/java/software/amazon/awssdk/services/rds/DefaultRdsUtilitiesTest.java index a8648196dadb..9830cc8f3b40 100644 --- a/services/rds/src/test/java/software/amazon/awssdk/services/rds/DefaultRdsUtilitiesTest.java +++ b/services/rds/src/test/java/software/amazon/awssdk/services/rds/DefaultRdsUtilitiesTest.java @@ -6,19 +6,23 @@ import java.time.Clock; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.function.Consumer; import org.junit.jupiter.api.Test; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rds.DefaultRdsUtilities.DefaultBuilder; +import software.amazon.awssdk.services.rds.model.GenerateAuthenticationTokenRequest; public class DefaultRdsUtilitiesTest { private final ZoneId utcZone = ZoneId.of("UTC").normalized(); private final Clock fixedClock = Clock.fixed(ZonedDateTime.of(2016, 11, 7, 17, 39, 33, 0, utcZone).toInstant(), utcZone); @Test - public void testTokenGenerationWithBuilderDefaults() { + public void testTokenGenerationWithBuilderDefaultsUsingAwsCredentialsProvider() { AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create("access_key", "secret_key") ); @@ -26,6 +30,22 @@ public void testTokenGenerationWithBuilderDefaults() { .credentialsProvider(credentialsProvider) .region(Region.US_EAST_1); + testTokenGenerationWithBuilderDefaults(utilitiesBuilder); + } + + @Test + public void testTokenGenerationWithBuilderDefaultsUsingIdentityProvider() { + IdentityProvider credentialsProvider = StaticCredentialsProvider.create( + AwsBasicCredentials.create("access_key", "secret_key") + ); + DefaultBuilder utilitiesBuilder = (DefaultBuilder) RdsUtilities.builder() + .credentialsProvider(credentialsProvider) + .region(Region.US_EAST_1); + + testTokenGenerationWithBuilderDefaults(utilitiesBuilder); + } + + private void testTokenGenerationWithBuilderDefaults(DefaultBuilder utilitiesBuilder) { DefaultRdsUtilities rdsUtilities = new DefaultRdsUtilities(utilitiesBuilder, fixedClock); String authenticationToken = rdsUtilities.generateAuthenticationToken(builder -> { @@ -42,22 +62,42 @@ public void testTokenGenerationWithBuilderDefaults() { } @Test - public void testTokenGenerationWithOverriddenCredentials() { + public void testTokenGenerationWithOverriddenCredentialsUsingAwsCredentialsProvider() { AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create("foo", "bar") ); DefaultBuilder utilitiesBuilder = (DefaultBuilder) RdsUtilities.builder() .credentialsProvider(credentialsProvider) .region(Region.US_EAST_1); + testTokenGenerationWithOverriddenCredentials(utilitiesBuilder, builder -> { + builder.credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create("access_key", "secret_key"))); + }); + } + + @Test + public void testTokenGenerationWithOverriddenCredentialsUsingIdentityProvider() { + IdentityProvider credentialsProvider = StaticCredentialsProvider.create( + AwsBasicCredentials.create("foo", "bar") + ); + DefaultBuilder utilitiesBuilder = (DefaultBuilder) RdsUtilities.builder() + .credentialsProvider(credentialsProvider) + .region(Region.US_EAST_1); + testTokenGenerationWithOverriddenCredentials(utilitiesBuilder, builder -> { + builder.credentialsProvider((IdentityProvider) StaticCredentialsProvider.create( + AwsBasicCredentials.create("access_key", "secret_key"))); + }); + } + + private void testTokenGenerationWithOverriddenCredentials(DefaultBuilder utilitiesBuilder, + Consumer credsBuilder) { DefaultRdsUtilities rdsUtilities = new DefaultRdsUtilities(utilitiesBuilder, fixedClock); String authenticationToken = rdsUtilities.generateAuthenticationToken(builder -> { builder.username("mySQLUser") .hostname("host.us-east-1.amazonaws.com") .port(3306) - .credentialsProvider(StaticCredentialsProvider.create( - AwsBasicCredentials.create("access_key", "secret_key") - )); + .applyMutation(credsBuilder); }); String expectedToken = "host.us-east-1.amazonaws.com:3306/?DBUser=mySQLUser&Action=connect&" + @@ -69,7 +109,7 @@ public void testTokenGenerationWithOverriddenCredentials() { @Test public void testTokenGenerationWithOverriddenRegion() { - AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( + IdentityProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create("access_key", "secret_key") ); DefaultBuilder utilitiesBuilder = (DefaultBuilder) RdsUtilities.builder() @@ -94,7 +134,7 @@ public void testTokenGenerationWithOverriddenRegion() { @Test public void testMissingRegionThrowsException() { - AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( + IdentityProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create("access_key", "secret_key") ); DefaultBuilder utilitiesBuilder = (DefaultBuilder) RdsUtilities.builder() diff --git a/test/service-test-utils/src/main/java/software/amazon/awssdk/testutils/service/AwsIntegrationTestBase.java b/test/service-test-utils/src/main/java/software/amazon/awssdk/testutils/service/AwsIntegrationTestBase.java index 2b9de9dd2b03..70c9564fd2ae 100644 --- a/test/service-test-utils/src/main/java/software/amazon/awssdk/testutils/service/AwsIntegrationTestBase.java +++ b/test/service-test-utils/src/main/java/software/amazon/awssdk/testutils/service/AwsIntegrationTestBase.java @@ -19,11 +19,12 @@ import java.io.InputStream; import reactor.blockhound.BlockHound; import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.utils.IoUtils; public abstract class AwsIntegrationTestBase { @@ -57,9 +58,9 @@ protected static AwsCredentials getCredentials() { } /** - * @return AwsCredentialsProvider to use during tests. Setup by base fixture + * @return {@link IdentityProvider} to use during tests. Setup by base fixture */ - protected static AwsCredentialsProvider getCredentialsProvider() { + protected static IdentityProvider getCredentialsProvider() { return StaticCredentialsProvider.create(CREDENTIALS); } From b2098a66be8a2d8bb8df74c9f0a6e2eff51f8207 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Wed, 29 Mar 2023 00:12:25 -0700 Subject: [PATCH 11/13] Remove unnecessary fallback from AuthorizationStrategyFactory --- .../auth/credentials/CredentialUtilsTest.java | 2 +- .../AuthorizationStrategyFactory.java | 5 +-- .../AwsRequestOverrideConfigurationTest.java | 2 +- .../AuthorizationStrategyFactoryTest.java | 45 ++----------------- 4 files changed, 6 insertions(+), 48 deletions(-) diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java index 2b68ad493a0c..10eb7855e6bc 100644 --- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java +++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java @@ -112,4 +112,4 @@ public void toCredentialsProvider_IdentityProvider_converts() { assertThat(credentials.accessKeyId()).isEqualTo("akid"); assertThat(credentials.secretAccessKey()).isEqualTo("skid"); } -} \ No newline at end of file +} diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java index 0cffb7e9b355..e56b44d01efe 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactory.java @@ -65,11 +65,8 @@ private TokenAuthorizationStrategy tokenAuthorizationStrategy() { private AwsCredentialsAuthorizationStrategy awsCredentialsAuthorizationStrategy() { Signer defaultSigner = clientConfiguration.option(SdkAdvancedClientOption.SIGNER); - // Older generated clients may still be using CREDENTIALS_PROVIDER, so fall back to that. IdentityProvider defaultCredentialsProvider = - clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) != null - ? clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER) - : clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER); + clientConfiguration.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); return AwsCredentialsAuthorizationStrategy.builder() .request(request) .defaultSigner(defaultSigner) diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java index 94ebe7bc810a..ef009f8242f4 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/AwsRequestOverrideConfigurationTest.java @@ -51,4 +51,4 @@ private void assertCredentialsEqual(AwsCredentialsProvider credentialsProvider, assertThat(creds1.accessKeyId()).isEqualTo(creds2.accessKeyId()); assertThat(creds1.secretAccessKey()).isEqualTo(creds2.secretAccessKey()); } -} \ No newline at end of file +} diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java index ec5ab60b60ef..1f48149c45ca 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/authcontext/AuthorizationStrategyFactoryTest.java @@ -16,35 +16,19 @@ package software.amazon.awssdk.awscore.internal.authcontext; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; -import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; -import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.core.CredentialType; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; -import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.metrics.MetricCollector; -@RunWith(MockitoJUnitRunner.class) public class AuthorizationStrategyFactoryTest { @Mock SdkRequest sdkRequest; @Mock MetricCollector metricCollector; - @Before - public void setUp() throws Exception { - when(sdkRequest.overrideConfiguration()).thenReturn(Optional.empty()); - } - @Test public void credentialTypeBearerToken_returnsTokenStrategy() { AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, @@ -55,33 +39,10 @@ public void credentialTypeBearerToken_returnsTokenStrategy() { @Test public void credentialTypeAwsCredentials_returnsCredentialsStrategy() { - SdkClientConfiguration configuration = SdkClientConfiguration - .builder() - .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, StaticCredentialsProvider.create(AwsBasicCredentials.create( - "akid", "skid"))) - .build(); - AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, configuration); + AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, + SdkClientConfiguration.builder().build()); AuthorizationStrategy authorizationStrategy = factory.strategyFor(CredentialType.of("AWS")); assertThat(authorizationStrategy).isExactlyInstanceOf(AwsCredentialsAuthorizationStrategy.class); - ExecutionAttributes attributes = new ExecutionAttributes(); - authorizationStrategy.addCredentialsToExecutionAttributes(attributes); - assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).accessKeyId()).isEqualTo("akid"); - assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).secretAccessKey()).isEqualTo("skid"); } - @Test - public void credentialTypeAwsCredentials_withOldClientOption_returnsCredentialsStrategy() { - SdkClientConfiguration configuration = SdkClientConfiguration - .builder() - .option(AwsClientOption.CREDENTIALS_PROVIDER, StaticCredentialsProvider.create(AwsBasicCredentials.create( - "akid", "skid"))) - .build(); - AuthorizationStrategyFactory factory = new AuthorizationStrategyFactory(sdkRequest, metricCollector, configuration); - AuthorizationStrategy authorizationStrategy = factory.strategyFor(CredentialType.of("AWS")); - assertThat(authorizationStrategy).isExactlyInstanceOf(AwsCredentialsAuthorizationStrategy.class); - ExecutionAttributes attributes = new ExecutionAttributes(); - authorizationStrategy.addCredentialsToExecutionAttributes(attributes); - assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).accessKeyId()).isEqualTo("akid"); - assertThat(attributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS).secretAccessKey()).isEqualTo("skid"); - } } From 22370c274eee2d286e219474f78ba8fc79d8586f Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Wed, 29 Mar 2023 00:44:24 -0700 Subject: [PATCH 12/13] Fix test in S3 --- .../crt/CrtCredentialProviderAdapterTest.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialProviderAdapterTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialProviderAdapterTest.java index a4da9d11f18b..f191d1effc70 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialProviderAdapterTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/CrtCredentialProviderAdapterTest.java @@ -20,24 +20,25 @@ import static org.mockito.Mockito.when; import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; import software.amazon.awssdk.auth.credentials.HttpCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.crt.auth.credentials.Credentials; import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.utils.SdkAutoCloseable; public class CrtCredentialProviderAdapterTest { @Test void crtCredentials_withSession_shouldConvert() { - AwsCredentialsProvider awsCredentialsProvider = StaticCredentialsProvider + IdentityProvider awsCredentialsProvider = StaticCredentialsProvider .create(AwsSessionCredentials.create("foo", "bar", "session")); CredentialsProvider crtCredentialsProvider = new CrtCredentialsProviderAdapter(awsCredentialsProvider) @@ -52,7 +53,7 @@ void crtCredentials_withSession_shouldConvert() { @Test void crtCredentials_withoutSession_shouldConvert() { - AwsCredentialsProvider awsCredentialsProvider = StaticCredentialsProvider + IdentityProvider awsCredentialsProvider = StaticCredentialsProvider .create(AwsBasicCredentials.create("foo", "bar")); CredentialsProvider crtCredentialsProvider = new CrtCredentialsProviderAdapter(awsCredentialsProvider) @@ -67,8 +68,8 @@ void crtCredentials_withoutSession_shouldConvert() { @Test void crtCredentials_provideAwsCredentials_shouldInvokeResolveAndClose() { - AwsCredentialsProvider awsCredentialsProvider = Mockito.mock(HttpCredentialsProvider.class); - AwsCredentials credentials = new AwsCredentials() { + IdentityProvider awsCredentialsProvider = Mockito.mock(HttpCredentialsProvider.class); + AwsCredentialsIdentity credentials = new AwsCredentialsIdentity() { @Override public String accessKeyId() { return "foo"; @@ -79,7 +80,7 @@ public String secretAccessKey() { return "bar"; } }; - when(awsCredentialsProvider.resolveCredentials()).thenReturn(credentials); + when(awsCredentialsProvider.resolveIdentity()).thenAnswer(invocation -> CompletableFuture.completedFuture(credentials)); CrtCredentialsProviderAdapter adapter = new CrtCredentialsProviderAdapter(awsCredentialsProvider); CredentialsProvider crtCredentialsProvider = adapter.crtCredentials(); @@ -87,7 +88,7 @@ public String secretAccessKey() { Credentials crtCredentials = crtCredentialsProvider.getCredentials().join(); assertThat(crtCredentials.getAccessKeyId()).isEqualTo("foo".getBytes(StandardCharsets.UTF_8)); assertThat(crtCredentials.getSecretAccessKey()).isEqualTo("bar".getBytes(StandardCharsets.UTF_8)); - verify(awsCredentialsProvider).resolveCredentials(); + verify(awsCredentialsProvider).resolveIdentity(); adapter.close(); verify((SdkAutoCloseable) awsCredentialsProvider).close(); @@ -95,7 +96,7 @@ public String secretAccessKey() { @Test void crtCredentials_anonymousCredentialsProvider_shouldWork() { - AwsCredentialsProvider awsCredentialsProvider = AnonymousCredentialsProvider.create(); + IdentityProvider awsCredentialsProvider = AnonymousCredentialsProvider.create(); CrtCredentialsProviderAdapter adapter = new CrtCredentialsProviderAdapter(awsCredentialsProvider); CredentialsProvider crtCredentialsProvider = adapter.crtCredentials(); @@ -104,9 +105,5 @@ void crtCredentials_anonymousCredentialsProvider_shouldWork() { assertThat(crtCredentials.getAccessKeyId()).isNull(); assertThat(crtCredentials.getSecretAccessKey()).isNull(); - } - - - } From c7fb92fece786f4356e28ccd447cdd8f35e4a5c8 Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Fri, 31 Mar 2023 16:35:14 -0700 Subject: [PATCH 13/13] Address PR feedback --- .../AwsCredentialsProviderChain.java | 1 - .../auth/credentials/CredentialUtils.java | 4 +++ .../auth/credentials/CredentialUtilsTest.java | 28 ++++++++++++++++++- .../client/config/AwsClientOption.java | 2 +- .../internal/crt/DefaultS3CrtAsyncClient.java | 28 +++++++++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java index 8a46cfc306e7..3dd4a4ae4011 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java @@ -45,7 +45,6 @@ *

This chain implements {@link AutoCloseable}. When closed, it will call the {@link AutoCloseable#close()} on any credential * providers in the chain that need to be closed.

*/ -// TODO: deprecate with new IdentityProvider chain in identity-spi @SdkPublicApi public final class AwsCredentialsProviderChain implements AwsCredentialsProvider, diff --git a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java index 2b855d145b3d..7eabc4ad18d8 100644 --- a/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java +++ b/core/auth/src/main/java/software/amazon/awssdk/auth/credentials/CredentialUtils.java @@ -63,6 +63,10 @@ public static AwsCredentials toCredentials(AwsCredentialsIdentity awsCredentials if (awsCredentialsIdentity == null) { return null; } + if (awsCredentialsIdentity instanceof AwsCredentials) { + return (AwsCredentials) awsCredentialsIdentity; + } + // identity-spi defines 2 known types - AwsCredentialsIdentity and a sub-type AwsSessionCredentialsIdentity if (awsCredentialsIdentity instanceof AwsSessionCredentialsIdentity) { AwsSessionCredentialsIdentity awsSessionCredentialsIdentity = (AwsSessionCredentialsIdentity) awsCredentialsIdentity; diff --git a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java index 10eb7855e6bc..bfd6e9e5c90a 100644 --- a/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java +++ b/core/auth/src/test/java/software/amazon/awssdk/auth/credentials/CredentialUtilsTest.java @@ -48,6 +48,14 @@ public void toCredentials_null_returnsNull() { assertThat(CredentialUtils.toCredentials(null)).isNull(); } + + @Test + public void toCredentials_AwsSessionCredentials_doesNotCreateNewObject() { + AwsSessionCredentialsIdentity input = AwsSessionCredentials.create("ak", "sk", "session"); + AwsCredentials output = CredentialUtils.toCredentials(input); + assertThat(output).isSameAs(input); + } + @Test public void toCredentials_AwsSessionCredentialsIdentity_returnsAwsSessionCredentials() { AwsCredentials awsCredentials = CredentialUtils.toCredentials(new AwsSessionCredentialsIdentity() { @@ -74,6 +82,13 @@ public String sessionToken() { assertThat(awsSessionCredentials.sessionToken()).isEqualTo("session"); } + @Test + public void toCredentials_AwsCredentials_doesNotCreateNewObject() { + AwsCredentialsIdentity input = AwsBasicCredentials.create("ak", "sk"); + AwsCredentials output = CredentialUtils.toCredentials(input); + assertThat(output).isSameAs(input); + } + @Test public void toCredentials_AwsCredentialsIdentity_returnsAwsCredentials() { AwsCredentials awsCredentials = CredentialUtils.toCredentials(new AwsCredentialsIdentity() { @@ -94,7 +109,18 @@ public String secretAccessKey() { @Test public void toCredentials_Anonymous_returnsAnonymous() { - AwsCredentials awsCredentials = CredentialUtils.toCredentials(AwsBasicCredentials.ANONYMOUS_CREDENTIALS); + AwsCredentials awsCredentials = CredentialUtils.toCredentials(new AwsCredentialsIdentity() { + @Override + public String accessKeyId() { + return null; + } + + @Override + public String secretAccessKey() { + return null; + } + }); + assertThat(awsCredentials.accessKeyId()).isNull(); assertThat(awsCredentials.secretAccessKey()).isNull(); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java index aefab749f178..44280cb5615f 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/config/AwsClientOption.java @@ -28,7 +28,7 @@ @SdkProtectedApi public final class AwsClientOption extends ClientOption { /** - // * This option is deprecated in favor of {@link #CREDENTIALS_IDENTITY_PROVIDER}. + * This option is deprecated in favor of {@link #CREDENTIALS_IDENTITY_PROVIDER}. * @see AwsClientBuilder#credentialsProvider(AwsCredentialsProvider) */ @Deprecated diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java index b8506e7ac03f..7ac41d4005fd 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/DefaultS3CrtAsyncClient.java @@ -119,6 +119,34 @@ public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientB private URI endpointOverride; private Boolean checksumValidationEnabled; + public IdentityProvider credentialsProvider() { + return credentialsProvider; + } + + public Region region() { + return region; + } + + public Long minimumPartSizeInBytes() { + return minimalPartSizeInBytes; + } + + public Double targetThroughputInGbps() { + return targetThroughputInGbps; + } + + public Integer maxConcurrency() { + return maxConcurrency; + } + + public URI endpointOverride() { + return endpointOverride; + } + + public Long readBufferSizeInBytes() { + return readBufferSizeInBytes; + } + @Override public S3CrtAsyncClientBuilder credentialsProvider( IdentityProvider credentialsProvider) {