From 445f58e9efc35ddd59f3df0cf3a9c38e290a8e8b Mon Sep 17 00:00:00 2001 From: Jaykumar Gosar Date: Wed, 28 Jun 2023 11:12:07 -0700 Subject: [PATCH] Extract common AuthSchemeInterceptor logic into a base class --- .../BaseAuthSchemeInterceptor.java | 112 ++++++++++++++++++ .../internal/AcmAuthSchemeInterceptor.java | 84 +------------ .../CodeCatalystAuthSchemeInterceptor.java | 81 +------------ 3 files changed, 118 insertions(+), 159 deletions(-) create mode 100644 core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/interceptor/BaseAuthSchemeInterceptor.java diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/interceptor/BaseAuthSchemeInterceptor.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/interceptor/BaseAuthSchemeInterceptor.java new file mode 100644 index 000000000000..b690ff6849bb --- /dev/null +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/interceptor/BaseAuthSchemeInterceptor.java @@ -0,0 +1,112 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.core.internal.interceptor; + +import static software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute.AUTH_SCHEMES; +import static software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute.IDENTITY_PROVIDER_CONFIGURATION; +import static software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME; + +import java.util.List; +import java.util.Map; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.SelectedAuthScheme; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.http.auth.spi.AuthScheme; +import software.amazon.awssdk.http.auth.spi.AuthSchemeOption; +import software.amazon.awssdk.http.auth.spi.AuthSchemeProvider; +import software.amazon.awssdk.http.auth.spi.IdentityProviderConfiguration; +import software.amazon.awssdk.identity.spi.Identity; +import software.amazon.awssdk.identity.spi.IdentityProvider; +import software.amazon.awssdk.utils.Logger; + +/** + * This is the base interceptor logic that does the Smithy Reference Architecture auth resolution logic. Subclasses need to use + * the service specific {@link AuthSchemeProvider} to resolve the list of {@link AuthSchemeOption}s. The base auth resolution + * logic here then selects the auth scheme for this request and is saved as ExecutionAttribute for use later. + */ +@SdkInternalApi +public abstract class BaseAuthSchemeInterceptor implements ExecutionInterceptor { + private static final Logger log = Logger.loggerFor(BaseAuthSchemeInterceptor.class); + + @Override + public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { + List authOptions = resolveAuthOptions(executionAttributes); + SelectedAuthScheme selectedAuthScheme = selectAuthScheme(authOptions, executionAttributes); + executionAttributes.putAttribute(SELECTED_AUTH_SCHEME, selectedAuthScheme); + } + + /** + * Invoke the auth scheme resolver to determine which auth options we should consider for this request. + */ + protected abstract List resolveAuthOptions(ExecutionAttributes executionAttributes); + + /** + * From a list of possible auth options for this request, determine which auth scheme should be used. + */ + private SelectedAuthScheme selectAuthScheme(List authOptions, ExecutionAttributes executionAttributes) { + Map> authSchemes = executionAttributes.getAttribute(AUTH_SCHEMES); + IdentityProviderConfiguration identityResolvers = executionAttributes.getAttribute(IDENTITY_PROVIDER_CONFIGURATION); + + StringBuilder failureReasons = new StringBuilder(); + // Check each option, in the order the auth scheme resolver proposed them. + for (AuthSchemeOption authOption : authOptions) { + // If we're using no-auth, don't consider which options are enabled. + if ("smithy.auth#noAuth".equals(authOption.schemeId())) { + return new SelectedAuthScheme<>(null, null, authOption); + } + + AuthScheme authScheme = authSchemes.get(authOption.schemeId()); + + SelectedAuthScheme selectedAuthScheme = + trySelectAuthScheme(authOption, authScheme, identityResolvers, failureReasons); + + // Check to see if selecting this auth option succeeded. + if (selectedAuthScheme != null) { + if (failureReasons.length() > 0) { + log.debug(() -> authOption.schemeId() + " auth will be used because " + failureReasons); + } + return selectedAuthScheme; + } + } + + // TODO: Exception type and message? + throw new IllegalStateException("Failed to determine how to authenticate the user:" + failureReasons); + } + + /** + * Try to select the provided auth scheme by ensuring it is non-null and that its identity resolver is configured. + */ + SelectedAuthScheme trySelectAuthScheme(AuthSchemeOption authOption, + AuthScheme authScheme, + IdentityProviderConfiguration identityProviders, + StringBuilder failureReasons) { + if (authScheme == null) { + failureReasons.append("\nAuth scheme '" + authOption.schemeId() + "' was not enabled for this request."); + return null; + } + + IdentityProvider identityProvider = authScheme.identityProvider(identityProviders); + + if (identityProvider == null) { + failureReasons.append("\nAuth scheme '" + authOption.schemeId() + "' did not have an identity resolver configured."); + return null; + } + + return new SelectedAuthScheme<>(identityProvider, authScheme.signer(), authOption); + } +} diff --git a/services/acm/src/main/java/software/amazon/awssdk/services/acm/auth/scheme/internal/AcmAuthSchemeInterceptor.java b/services/acm/src/main/java/software/amazon/awssdk/services/acm/auth/scheme/internal/AcmAuthSchemeInterceptor.java index 43a1ef8a7ed2..390d77e18329 100644 --- a/services/acm/src/main/java/software/amazon/awssdk/services/acm/auth/scheme/internal/AcmAuthSchemeInterceptor.java +++ b/services/acm/src/main/java/software/amazon/awssdk/services/acm/auth/scheme/internal/AcmAuthSchemeInterceptor.java @@ -14,43 +14,24 @@ package software.amazon.awssdk.services.acm.auth.scheme.internal; import java.util.List; -import java.util.Map; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.core.SelectedAuthScheme; -import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; -import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; -import software.amazon.awssdk.http.auth.spi.AuthScheme; +import software.amazon.awssdk.core.internal.interceptor.BaseAuthSchemeInterceptor; import software.amazon.awssdk.http.auth.spi.AuthSchemeOption; -import software.amazon.awssdk.http.auth.spi.IdentityProviderConfiguration; -import software.amazon.awssdk.identity.spi.Identity; -import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.acm.auth.scheme.AcmAuthSchemeParams; import software.amazon.awssdk.services.acm.auth.scheme.AcmAuthSchemeProvider; -import software.amazon.awssdk.utils.Logger; @Generated("software.amazon.awssdk:codegen") @SdkInternalApi -public final class AcmAuthSchemeInterceptor implements ExecutionInterceptor { - - private static final Logger log = Logger.loggerFor(AcmAuthSchemeInterceptor.class); +public final class AcmAuthSchemeInterceptor extends BaseAuthSchemeInterceptor { @Override - public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { - List authOptions = resolveAuthOptions(executionAttributes); - SelectedAuthScheme selectedAuthScheme = selectAuthScheme(authOptions, executionAttributes); - executionAttributes.putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedAuthScheme); - } - - /** - * Invoke the auth scheme resolver to determine which auth options we should consider for this request. - */ - private List resolveAuthOptions(ExecutionAttributes executionAttributes) { + protected List resolveAuthOptions(ExecutionAttributes executionAttributes) { // Prepare the inputs for the auth scheme resolver. We always include the // operationName, and we include the region if the service is modeled with // @sigv4. @@ -66,63 +47,4 @@ private List resolveAuthOptions(ExecutionAttributes executionA .region(region) .build()); } - - /** - * From a list of possible auth options for this request, determine which auth scheme should be used. - */ - private SelectedAuthScheme selectAuthScheme(List authOptions, ExecutionAttributes executionAttributes) { - Map> authSchemes = - executionAttributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES); - - IdentityProviderConfiguration identityResolvers = - executionAttributes.getAttribute(SdkInternalExecutionAttribute.IDENTITY_PROVIDER_CONFIGURATION); - - StringBuilder failureReasons = new StringBuilder(); - - // Check each option, in the order the auth scheme resolver proposed them. - for (AuthSchemeOption authOption : authOptions) { - // If we're using no-auth, don't consider which options are enabled. - if (authOption.schemeId().equals("smithy.auth#noAuth")) { - return new SelectedAuthScheme(null, null, authOption); - } - - AuthScheme authScheme = authSchemes.get(authOption.schemeId()); - - SelectedAuthScheme selectedAuthScheme = - trySelectAuthScheme(authOption, authScheme, identityResolvers, failureReasons); - - // Check to see if selecting this auth option succeeded. - if (selectedAuthScheme != null) { - if (failureReasons.length() > 0) { - log.debug(() -> authOption.schemeId() + " auth will be used because " + failureReasons); - } - return selectedAuthScheme; - } - } - - // TODO: Exception type and message? - throw new IllegalStateException("Failed to determine how to authenticate the user:" + failureReasons); - } - - /** - * Try to select the provided auth scheme by ensuring it is non-null and that its identity resolver is configured. - */ - SelectedAuthScheme trySelectAuthScheme(AuthSchemeOption authOption, - AuthScheme authScheme, - IdentityProviderConfiguration identityProviders, - StringBuilder failureReasons) { - if (authScheme == null) { - failureReasons.append("\nAuth scheme '" + authOption.schemeId() + "' was not enabled for this request."); - return null; - } - - IdentityProvider identityProvider = authScheme.identityProvider(identityProviders); - - if (identityProvider == null) { - failureReasons.append("\nAuth scheme '" + authOption.schemeId() + "' did not have an identity resolver configured."); - return null; - } - - return new SelectedAuthScheme<>(identityProvider, authScheme.signer(), authOption); - } } diff --git a/services/codecatalyst/src/main/java/software/amazon/awssdk/services/codecatalyst/auth/scheme/internal/CodeCatalystAuthSchemeInterceptor.java b/services/codecatalyst/src/main/java/software/amazon/awssdk/services/codecatalyst/auth/scheme/internal/CodeCatalystAuthSchemeInterceptor.java index fbe5a0bddc80..cbfee6ccb51b 100644 --- a/services/codecatalyst/src/main/java/software/amazon/awssdk/services/codecatalyst/auth/scheme/internal/CodeCatalystAuthSchemeInterceptor.java +++ b/services/codecatalyst/src/main/java/software/amazon/awssdk/services/codecatalyst/auth/scheme/internal/CodeCatalystAuthSchemeInterceptor.java @@ -14,21 +14,14 @@ package software.amazon.awssdk.services.codecatalyst.auth.scheme.internal; import java.util.List; -import java.util.Map; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.core.SelectedAuthScheme; -import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; -import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; -import software.amazon.awssdk.http.auth.spi.AuthScheme; +import software.amazon.awssdk.core.internal.interceptor.BaseAuthSchemeInterceptor; import software.amazon.awssdk.http.auth.spi.AuthSchemeOption; -import software.amazon.awssdk.http.auth.spi.IdentityProviderConfiguration; -import software.amazon.awssdk.identity.spi.Identity; -import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.codecatalyst.auth.scheme.CodeCatalystAuthSchemeParams; import software.amazon.awssdk.services.codecatalyst.auth.scheme.CodeCatalystAuthSchemeProvider; @@ -36,21 +29,12 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi -public final class CodeCatalystAuthSchemeInterceptor implements ExecutionInterceptor { +public final class CodeCatalystAuthSchemeInterceptor extends BaseAuthSchemeInterceptor { private static final Logger log = Logger.loggerFor(CodeCatalystAuthSchemeInterceptor.class); @Override - public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { - List authOptions = resolveAuthOptions(executionAttributes); - SelectedAuthScheme selectedAuthScheme = selectAuthScheme(authOptions, executionAttributes); - executionAttributes.putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedAuthScheme); - } - - /** - * Invoke the auth scheme resolver to determine which auth options we should consider for this request. - */ - private List resolveAuthOptions(ExecutionAttributes executionAttributes) { + protected List resolveAuthOptions(ExecutionAttributes executionAttributes) { // Prepare the inputs for the auth scheme resolver. We always include the // operationName, and we include the region if the service is modeled with // @sigv4. @@ -66,63 +50,4 @@ private List resolveAuthOptions(ExecutionAttributes executionA // .region(region.id()) .build()); } - - /** - * From a list of possible auth options for this request, determine which auth scheme should be used. - */ - private SelectedAuthScheme selectAuthScheme(List authOptions, ExecutionAttributes executionAttributes) { - Map> authSchemes = - executionAttributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES); - - IdentityProviderConfiguration identityResolvers = - executionAttributes.getAttribute(SdkInternalExecutionAttribute.IDENTITY_PROVIDER_CONFIGURATION); - - StringBuilder failureReasons = new StringBuilder(); - - // Check each option, in the order the auth scheme resolver proposed them. - for (AuthSchemeOption authOption : authOptions) { - // If we're using no-auth, don't consider which options are enabled. - if (authOption.schemeId().equals("smithy.auth#noAuth")) { - return new SelectedAuthScheme(null, null, authOption); - } - - AuthScheme authScheme = authSchemes.get(authOption.schemeId()); - - SelectedAuthScheme selectedAuthScheme = - trySelectAuthScheme(authOption, authScheme, identityResolvers, failureReasons); - - // Check to see if selecting this auth option succeeded. - if (selectedAuthScheme != null) { - if (failureReasons.length() > 0) { - log.debug(() -> authOption.schemeId() + " auth will be used because " + failureReasons); - } - return selectedAuthScheme; - } - } - - // TODO: Exception type and message? - throw new IllegalStateException("Failed to determine how to authenticate the user:" + failureReasons); - } - - /** - * Try to select the provided auth scheme by ensuring it is non-null and that its identity resolver is configured. - */ - SelectedAuthScheme trySelectAuthScheme(AuthSchemeOption authOption, - AuthScheme authScheme, - IdentityProviderConfiguration identityProviders, - StringBuilder failureReasons) { - if (authScheme == null) { - failureReasons.append("\nAuth scheme '" + authOption.schemeId() + "' was not enabled for this request."); - return null; - } - - IdentityProvider identityProvider = authScheme.identityProvider(identityProviders); - - if (identityProvider == null) { - failureReasons.append("\nAuth scheme '" + authOption.schemeId() + "' did not have an identity resolver configured."); - return null; - } - - return new SelectedAuthScheme<>(identityProvider, authScheme.signer(), authOption); - } }