From e2e2fbf7b85d1e0fea20264fc59ebf735c792b4c Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 15 Apr 2025 12:38:55 -0700 Subject: [PATCH 01/53] Prototype implementation of Auth Scheme Preference --- .../auth/scheme/AuthSchemeProviderSpec.java | 58 ++++++++++++++++++- .../ModelBasedAuthSchemeProviderSpec.java | 47 +++++++++++++-- .../awssdk/codegen/utils/AuthUtils.java | 2 +- 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index bc5255695ad1..593628dfcb01 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -18,9 +18,12 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; import javax.lang.model.element.Modifier; import software.amazon.awssdk.annotations.SdkPublicApi; @@ -29,6 +32,7 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; +import software.amazon.awssdk.utils.CollectionUtils; public class AuthSchemeProviderSpec implements ClassSpec { private final IntermediateModel intermediateModel; @@ -53,16 +57,57 @@ public TypeSpec poetSpec() { .addJavadoc(interfaceJavadoc()) .addMethod(resolveAuthSchemeMethod()) .addMethod(resolveAuthSchemeConsumerBuilderMethod()) + .addMethod(resolveCandidateAuthSchemeMethod()) + .addMethod(getAuthSchemePreferenceMethod()) .addMethod(defaultProviderMethod()) + .addMethod(defaultProviderWithAuthPreferenceMethod()) .build(); } private MethodSpec resolveAuthSchemeMethod() { MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme"); - b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); + b.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT); b.addParameter(authSchemeSpecUtils.parametersInterfaceName(), "authSchemeParams"); b.returns(authSchemeSpecUtils.resolverReturnType()); b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); + b.addStatement("$T candidateAuthSchemes = resolveCandidateAuthScheme(authSchemeParams)", authSchemeSpecUtils.resolverReturnType()); + b.addStatement("$T authSchemePreference = getAuthSchemePreference()", ParameterizedTypeName.get(List.class, + String.class)); + b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) + .addStatement("return candidateAuthSchemes") + .endControlFlow(); + + b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); + b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") + .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" + + ".ifPresent(a -> authSchemes.add(a))") + .endControlFlow(")"); + + b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") + .beginControlFlow("if (!authSchemes.contains(candidate))") + .addStatement("authSchemes.add(candidate)") + .endControlFlow() + .endControlFlow(")"); + + b.addStatement("return authSchemes"); + + return b.build(); + } + + private MethodSpec resolveCandidateAuthSchemeMethod() { + MethodSpec.Builder b = MethodSpec.methodBuilder("resolveCandidateAuthScheme"); + b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); + b.addParameter(authSchemeSpecUtils.parametersInterfaceName(), "authSchemeParams"); + b.returns(authSchemeSpecUtils.resolverReturnType()); + b.addJavadoc("Resolve candidate auth schemes based on the given set of parameters."); + return b.build(); + } + + private MethodSpec getAuthSchemePreferenceMethod() { + MethodSpec.Builder b = MethodSpec.methodBuilder("getAuthSchemePreference"); + b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); + b.returns(ParameterizedTypeName.get(List.class, String.class)); + b.addJavadoc("get the ordered list of auth scheme preferences."); return b.build(); } @@ -93,6 +138,17 @@ private MethodSpec defaultProviderMethod() { .build(); } + private MethodSpec defaultProviderWithAuthPreferenceMethod() { + return MethodSpec.methodBuilder("defaultProvider") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(className()) + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addJavadoc("Get the default auth scheme provider.") + // TODO: Add javadoc here for the parameter + .addStatement("return $T.create(authSchemePreference)", authSchemeSpecUtils.defaultAuthSchemeProviderName()) + .build(); + } + private CodeBlock interfaceJavadoc() { CodeBlock.Builder b = CodeBlock.builder(); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java index 79d5125e65c5..877a75566210 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java @@ -55,9 +55,13 @@ public TypeSpec poetSpec() { .addAnnotation(SdkInternalApi.class) .addSuperinterface(authSchemeSpecUtils.providerInterfaceName()) .addMethod(constructor()) + .addMethod(constructorWithAuthPreference()) .addField(defaultInstance()) + .addField(authPreference()) .addMethod(createMethod()) - .addMethod(resolveAuthSchemeMethod()) + .addMethod(createWithAuthPreferenceMethod()) + .addMethod(getAuthSchemePreferenceMethod()) + .addMethod(resolveCandidateAuthSchemeMethod()) .build(); } @@ -68,8 +72,25 @@ private FieldSpec defaultInstance() { .build(); } + private FieldSpec authPreference() { + return FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addModifiers(Modifier.PRIVATE, Modifier.FINAL) + .build(); + } + private MethodSpec constructor() { - return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build(); + return MethodSpec.constructorBuilder() + .addModifiers(Modifier.PRIVATE) + .addStatement("authSchemePreference = $T.emptyList()", Collections.class) + .build(); + } + + private MethodSpec constructorWithAuthPreference() { + return MethodSpec.constructorBuilder() + .addModifiers(Modifier.PRIVATE) + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addStatement("this.authSchemePreference = authSchemePreference") // TODO: Should we copy this? + .build(); } private MethodSpec createMethod() { @@ -80,8 +101,26 @@ private MethodSpec createMethod() { .build(); } - private MethodSpec resolveAuthSchemeMethod() { - MethodSpec.Builder spec = MethodSpec.methodBuilder("resolveAuthScheme") + private MethodSpec createWithAuthPreferenceMethod() { + return MethodSpec.methodBuilder("create") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(className()) + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addStatement("return new $T(authSchemePreference)", className()) + .build(); + } + + private MethodSpec getAuthSchemePreferenceMethod() { + return MethodSpec.methodBuilder("getAuthSchemePreference") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(ParameterizedTypeName.get(List.class, String.class)) + .addStatement("return authSchemePreference") // TODO: return copy? + .build(); + } + + private MethodSpec resolveCandidateAuthSchemeMethod() { + MethodSpec.Builder spec = MethodSpec.methodBuilder("resolveCandidateAuthScheme") .addModifiers(Modifier.PUBLIC) .addAnnotation(Override.class) .returns(authSchemeSpecUtils.resolverReturnType()) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java index f870ceea284d..a247710ea590 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java @@ -68,7 +68,7 @@ public static boolean isOpBearerAuth(IntermediateModel model, OperationModel opM } private static boolean isServiceBearerAuth(IntermediateModel model) { - return model.getMetadata().getAuthType() == AuthType.BEARER; + return model.getMetadata().getAuth().contains(AuthType.BEARER); } private static boolean isServiceSigv4a(IntermediateModel model) { From 6790d42bd0b2ca4992c8599a37cb23518ffc53c7 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 16 Apr 2025 07:50:55 -0700 Subject: [PATCH 02/53] Add tracking of explictly set token provider --- .../awssdk/codegen/poet/builder/AsyncClientBuilderClass.java | 3 +++ .../awssdk/codegen/poet/builder/SyncClientBuilderClass.java | 3 +++ .../awssdk/core/client/config/SdkAdvancedClientOption.java | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java index 0cc74f08bdb9..886c5ba0094e 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java @@ -30,6 +30,7 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.codegen.utils.AuthUtils; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.identity.spi.IdentityProvider; @@ -155,6 +156,8 @@ private MethodSpec tokenProviderMethod() { .returns(builderClassName) .addStatement("clientConfiguration.option($T.TOKEN_IDENTITY_PROVIDER, tokenProvider)", AwsClientOption.class) + .addStatement("clientConfiguration.option($T.TOKEN_PROVIDER_CONFIGURED_EXPLICITLY, true)", + SdkAdvancedClientOption.class) .addStatement("return this") .build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java index 5fc251b73d46..ad6bd09bc492 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.codegen.utils.AuthUtils; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.identity.spi.IdentityProvider; @@ -147,6 +148,8 @@ private MethodSpec tokenProviderMethodImpl() { .returns(builderClassName) .addStatement("clientConfiguration.option($T.TOKEN_IDENTITY_PROVIDER, tokenProvider)", AwsClientOption.class) + .addStatement("clientConfiguration.option($T.TOKEN_PROVIDER_CONFIGURED_EXPLICITLY, true)", + SdkAdvancedClientOption.class) .addStatement("return this") .build(); } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java index 8528c36852ab..a9157995418a 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java @@ -55,6 +55,11 @@ public class SdkAdvancedClientOption extends ClientOption { */ public static final SdkAdvancedClientOption TOKEN_SIGNER = new SdkAdvancedClientOption<>(Signer.class); + /** + * Set when a token provider is configured explicitly in code by a customer. + */ + public static final SdkAdvancedClientOption TOKEN_PROVIDER_CONFIGURED_EXPLICITLY = + new SdkAdvancedClientOption<>(Boolean.class); /** * SDK uses endpoint trait and hostPrefix trait specified in service model to modify * the endpoint host that the API request is sent to. From b894b88215761d101c16ef770d30596a4f08dbd2 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 16 Apr 2025 09:27:19 -0700 Subject: [PATCH 03/53] Use generated PreferredAuthSchemeProvider to wrap/delegate --- .../tasks/AuthSchemeGeneratorTasks.java | 6 ++ .../auth/scheme/AuthSchemeProviderSpec.java | 68 +++--------- .../poet/auth/scheme/AuthSchemeSpecUtils.java | 4 + .../ModelBasedAuthSchemeProviderSpec.java | 47 +------- .../PreferredAuthSchemeProviderSpec.java | 100 ++++++++++++++++++ 5 files changed, 127 insertions(+), 98 deletions(-) create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java index fbcec7931bd8..38c170898f27 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.codegen.poet.auth.scheme.EndpointAwareAuthSchemeParamsSpec; import software.amazon.awssdk.codegen.poet.auth.scheme.EndpointBasedAuthSchemeProviderSpec; import software.amazon.awssdk.codegen.poet.auth.scheme.ModelBasedAuthSchemeProviderSpec; +import software.amazon.awssdk.codegen.poet.auth.scheme.PreferredAuthSchemeProviderSpec; public final class AuthSchemeGeneratorTasks extends BaseGeneratorTasks { private final GeneratorTaskParams generatorTaskParams; @@ -45,6 +46,7 @@ protected List createTasks() { tasks.add(generateProviderInterface()); tasks.add(generateDefaultParamsImpl()); tasks.add(generateModelBasedProvider()); + tasks.add(generatePreferenceProvider()); tasks.add(generateAuthSchemeInterceptor()); if (authSchemeSpecUtils.useEndpointBasedAuthProvider()) { tasks.add(generateEndpointBasedProvider()); @@ -69,6 +71,10 @@ private GeneratorTask generateModelBasedProvider() { return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new ModelBasedAuthSchemeProviderSpec(model)); } + private GeneratorTask generatePreferenceProvider() { + return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new PreferredAuthSchemeProviderSpec(model)); + } + private GeneratorTask generateEndpointBasedProvider() { return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new EndpointBasedAuthSchemeProviderSpec(model)); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index 593628dfcb01..a70e7c373e59 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -18,11 +18,9 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import javax.lang.model.element.Modifier; @@ -32,7 +30,6 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; -import software.amazon.awssdk.utils.CollectionUtils; public class AuthSchemeProviderSpec implements ClassSpec { private final IntermediateModel intermediateModel; @@ -57,57 +54,17 @@ public TypeSpec poetSpec() { .addJavadoc(interfaceJavadoc()) .addMethod(resolveAuthSchemeMethod()) .addMethod(resolveAuthSchemeConsumerBuilderMethod()) - .addMethod(resolveCandidateAuthSchemeMethod()) - .addMethod(getAuthSchemePreferenceMethod()) .addMethod(defaultProviderMethod()) - .addMethod(defaultProviderWithAuthPreferenceMethod()) + .addMethod(defaultProviderWithPreferenceMethod()) .build(); } private MethodSpec resolveAuthSchemeMethod() { MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme"); - b.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT); - b.addParameter(authSchemeSpecUtils.parametersInterfaceName(), "authSchemeParams"); - b.returns(authSchemeSpecUtils.resolverReturnType()); - b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); - b.addStatement("$T candidateAuthSchemes = resolveCandidateAuthScheme(authSchemeParams)", authSchemeSpecUtils.resolverReturnType()); - b.addStatement("$T authSchemePreference = getAuthSchemePreference()", ParameterizedTypeName.get(List.class, - String.class)); - b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) - .addStatement("return candidateAuthSchemes") - .endControlFlow(); - - b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); - b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") - .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" - + ".ifPresent(a -> authSchemes.add(a))") - .endControlFlow(")"); - - b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") - .beginControlFlow("if (!authSchemes.contains(candidate))") - .addStatement("authSchemes.add(candidate)") - .endControlFlow() - .endControlFlow(")"); - - b.addStatement("return authSchemes"); - - return b.build(); - } - - private MethodSpec resolveCandidateAuthSchemeMethod() { - MethodSpec.Builder b = MethodSpec.methodBuilder("resolveCandidateAuthScheme"); b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); b.addParameter(authSchemeSpecUtils.parametersInterfaceName(), "authSchemeParams"); b.returns(authSchemeSpecUtils.resolverReturnType()); - b.addJavadoc("Resolve candidate auth schemes based on the given set of parameters."); - return b.build(); - } - - private MethodSpec getAuthSchemePreferenceMethod() { - MethodSpec.Builder b = MethodSpec.methodBuilder("getAuthSchemePreference"); - b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); - b.returns(ParameterizedTypeName.get(List.class, String.class)); - b.addJavadoc("get the ordered list of auth scheme preferences."); + b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); return b.build(); } @@ -131,21 +88,22 @@ private MethodSpec resolveAuthSchemeConsumerBuilderMethod() { private MethodSpec defaultProviderMethod() { return MethodSpec.methodBuilder("defaultProvider") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className()) - .addJavadoc("Get the default auth scheme provider.") - .addStatement("return $T.create()", authSchemeSpecUtils.defaultAuthSchemeProviderName()) - .build(); + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(className()) + .addJavadoc("Get the default auth scheme provider.") + .addStatement("return $T.create()", authSchemeSpecUtils.defaultAuthSchemeProviderName()) + .build(); } - private MethodSpec defaultProviderWithAuthPreferenceMethod() { + private MethodSpec defaultProviderWithPreferenceMethod() { return MethodSpec.methodBuilder("defaultProvider") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className()) .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addJavadoc("Get the default auth scheme provider.") - // TODO: Add javadoc here for the parameter - .addStatement("return $T.create(authSchemePreference)", authSchemeSpecUtils.defaultAuthSchemeProviderName()) + .returns(className()) + .addJavadoc("Get the default auth scheme provider with auth scheme preference.") + .addStatement("return new $T($T.create(), authSchemePreference)", + authSchemeSpecUtils.preferredAuthSchemeProviderName(), + authSchemeSpecUtils.defaultAuthSchemeProviderName()) .build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java index a02f3e8bc893..8be513dbf3e6 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java @@ -93,6 +93,10 @@ public ClassName defaultAuthSchemeProviderName() { return ClassName.get(internalPackage(), "Default" + providerInterfaceName().simpleName()); } + public ClassName preferredAuthSchemeProviderName() { + return ClassName.get(internalPackage(), "Preferred" + providerInterfaceName().simpleName()); + } + public ClassName modeledAuthSchemeProviderName() { return ClassName.get(internalPackage(), "Modeled" + providerInterfaceName().simpleName()); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java index 877a75566210..79d5125e65c5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java @@ -55,13 +55,9 @@ public TypeSpec poetSpec() { .addAnnotation(SdkInternalApi.class) .addSuperinterface(authSchemeSpecUtils.providerInterfaceName()) .addMethod(constructor()) - .addMethod(constructorWithAuthPreference()) .addField(defaultInstance()) - .addField(authPreference()) .addMethod(createMethod()) - .addMethod(createWithAuthPreferenceMethod()) - .addMethod(getAuthSchemePreferenceMethod()) - .addMethod(resolveCandidateAuthSchemeMethod()) + .addMethod(resolveAuthSchemeMethod()) .build(); } @@ -72,25 +68,8 @@ private FieldSpec defaultInstance() { .build(); } - private FieldSpec authPreference() { - return FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addModifiers(Modifier.PRIVATE, Modifier.FINAL) - .build(); - } - private MethodSpec constructor() { - return MethodSpec.constructorBuilder() - .addModifiers(Modifier.PRIVATE) - .addStatement("authSchemePreference = $T.emptyList()", Collections.class) - .build(); - } - - private MethodSpec constructorWithAuthPreference() { - return MethodSpec.constructorBuilder() - .addModifiers(Modifier.PRIVATE) - .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addStatement("this.authSchemePreference = authSchemePreference") // TODO: Should we copy this? - .build(); + return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build(); } private MethodSpec createMethod() { @@ -101,26 +80,8 @@ private MethodSpec createMethod() { .build(); } - private MethodSpec createWithAuthPreferenceMethod() { - return MethodSpec.methodBuilder("create") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className()) - .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addStatement("return new $T(authSchemePreference)", className()) - .build(); - } - - private MethodSpec getAuthSchemePreferenceMethod() { - return MethodSpec.methodBuilder("getAuthSchemePreference") - .addModifiers(Modifier.PUBLIC) - .addAnnotation(Override.class) - .returns(ParameterizedTypeName.get(List.class, String.class)) - .addStatement("return authSchemePreference") // TODO: return copy? - .build(); - } - - private MethodSpec resolveCandidateAuthSchemeMethod() { - MethodSpec.Builder spec = MethodSpec.methodBuilder("resolveCandidateAuthScheme") + private MethodSpec resolveAuthSchemeMethod() { + MethodSpec.Builder spec = MethodSpec.methodBuilder("resolveAuthScheme") .addModifiers(Modifier.PUBLIC) .addAnnotation(Override.class) .returns(authSchemeSpecUtils.resolverReturnType()) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java new file mode 100644 index 000000000000..cb156269e2ef --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java @@ -0,0 +1,100 @@ +/* + * 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.codegen.poet.auth.scheme; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.List; +import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.PoetUtils; +import software.amazon.awssdk.utils.CollectionUtils; + +public class PreferredAuthSchemeProviderSpec implements ClassSpec { + private final AuthSchemeSpecUtils authSchemeSpecUtils; + private final AuthSchemeCodegenKnowledgeIndex knowledgeIndex; + + public PreferredAuthSchemeProviderSpec(IntermediateModel intermediateModel) { + this.authSchemeSpecUtils = new AuthSchemeSpecUtils(intermediateModel); + this.knowledgeIndex = AuthSchemeCodegenKnowledgeIndex.of(intermediateModel); + } + + @Override + public ClassName className() { + return authSchemeSpecUtils.preferredAuthSchemeProviderName(); + } + + @Override + public TypeSpec poetSpec() { + return PoetUtils.createClassBuilder(className()) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addAnnotation(SdkInternalApi.class) + .addField( + authSchemeSpecUtils.providerInterfaceName(), "delegate", + Modifier.PRIVATE, Modifier.FINAL) + .addField( + ParameterizedTypeName.get(List.class, String.class), "authSchemePreference", + Modifier.PRIVATE, Modifier.FINAL) + .addSuperinterface(authSchemeSpecUtils.providerInterfaceName()) + .addMethod(constructor()) + .addMethod(resolveAuthSchemeMethod()) + .build(); + } + private MethodSpec constructor() { + return MethodSpec + .constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(authSchemeSpecUtils.providerInterfaceName(), "delegate") + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addStatement("this.delegate = delegate") + .addStatement("this.authSchemePreference = authSchemePreference") + .build(); + } + + private MethodSpec resolveAuthSchemeMethod() { + MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(authSchemeSpecUtils.resolverReturnType()) + .addParameter(authSchemeSpecUtils.parametersInterfaceName(), "params"); + b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); + b.addStatement("$T candidateAuthSchemes = delegate.resolveAuthScheme(params)", + authSchemeSpecUtils.resolverReturnType()); + b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) + .addStatement("return candidateAuthSchemes") + .endControlFlow(); + + b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); + b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") + .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" + + ".ifPresent(a -> authSchemes.add(a))") + .endControlFlow(")"); + + b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") + .beginControlFlow("if (!authSchemes.contains(candidate))") + .addStatement("authSchemes.add(candidate)") + .endControlFlow() + .endControlFlow(")"); + + b.addStatement("return authSchemes"); + return b.build(); + } +} From 2bdaac718ff13f310c0698d42a21e5931a4b067a Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 16 Apr 2025 13:31:18 -0700 Subject: [PATCH 04/53] Add generic-service environment token provider + customization config (support for bedrock) --- .../customization/CustomizationConfig.java | 14 ++++ .../poet/builder/BaseClientBuilderClass.java | 64 ++++++++++++++----- 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java index 32cecd79feb5..6cc3ac5b7212 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java @@ -350,6 +350,12 @@ public class CustomizationConfig { */ private boolean enableFastUnmarshaller; + /** + * A boolean flag to indicate if bearer token sourced from the environment support should be added to the + * generated service. + */ + private boolean enableEnvironmentBearerToken = false; + private CustomizationConfig() { } @@ -924,4 +930,12 @@ public boolean getEnableFastUnmarshaller() { public void setEnableFastUnmarshaller(boolean enableFastUnmarshaller) { this.enableFastUnmarshaller = enableFastUnmarshaller; } + + public boolean isEnableEnvironmentBearerToken() { + return enableEnvironmentBearerToken; + } + + public void setEnableEnvironmentBearerToken(boolean enableEnvironmentBearerToken) { + this.enableEnvironmentBearerToken = enableEnvironmentBearerToken; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 1ca3f9b38ba5..50614f55fe87 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -41,6 +41,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.signer.Aws4Signer; +import software.amazon.awssdk.auth.token.credentials.StaticTokenProvider; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; @@ -88,6 +89,7 @@ import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.Validate; import software.amazon.awssdk.utils.internal.CodegenNamingUtils; +import software.amazon.awssdk.utils.internal.SystemSettingUtils; public class BaseClientBuilderClass implements ClassSpec { private static final ParameterizedTypeName GENERIC_AUTH_SCHEME_TYPE = @@ -266,24 +268,17 @@ private MethodSpec serviceNameMethod() { private MethodSpec mergeServiceDefaultsMethod() { boolean crc32FromCompressedDataEnabled = model.getCustomizationConfig().isCalculateCrc32FromCompressedData(); + boolean enableEnvironmentBearerToken = model.getCustomizationConfig().isEnableEnvironmentBearerToken(); MethodSpec.Builder builder = MethodSpec.methodBuilder("mergeServiceDefaults") .addAnnotation(Override.class) .addModifiers(PROTECTED, FINAL) .returns(SdkClientConfiguration.class) .addParameter(SdkClientConfiguration.class, "config") - .addCode("return config.merge(c -> c"); + .beginControlFlow("return config.merge(c ->"); + builder.addCode("c"); builder.addCode(".option($T.ENDPOINT_PROVIDER, defaultEndpointProvider())", SdkClientOption.class); - - if (authSchemeSpecUtils.useSraAuth()) { - builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); - builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); - } else { - if (defaultAwsAuthSignerMethod().isPresent()) { - builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); - } - } builder.addCode(".option($T.CRC32_FROM_COMPRESSED_DATA_ENABLED, $L)\n", SdkClientOption.class, crc32FromCompressedDataEnabled); @@ -293,16 +288,53 @@ private MethodSpec mergeServiceDefaultsMethod() { SdkClientOption.class, ClassName.bestGuess(clientConfigClassName)); } - if (AuthUtils.usesBearerAuth(model)) { + if (enableEnvironmentBearerToken) { + // this applies only on SRA auth AND bearer it should be validated already, so skip those + builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", - AwsClientOption.class, TokenUtils.class); - builder.addCode(".option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())\n", AwsClientOption.class); - if (!authSchemeSpecUtils.useSraAuth()) { - builder.addCode(".option($T.TOKEN_SIGNER, defaultTokenSigner())", SdkAdvancedClientOption.class); + AwsClientOption.class, TokenUtils.class); + builder.addCode(";\n"); + builder.addStatement("$T tokenFromEnv = $T.resolveEnvironmentVariable($S)", + ParameterizedTypeName.get(Optional.class, String.class), + SystemSettingUtils.class, + "AWS_BEARER_TOKEN_" + StringUtils.upperCase(model.getMetadata().getSigningName())); + + builder + .beginControlFlow("if (tokenFromEnv.isPresent() && c.option($T.AUTH_SCHEME_PROVIDER) == null && c.option($T" + + ".TOKEN_IDENTITY_PROVIDER) == null)", + SdkClientOption.class, AwsClientOption.class) + + .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, $T.defaultProvider($T.singletonList($S)))", + SdkClientOption.class, authSchemeSpecUtils.providerInterfaceName(), Collections.class, + "smithy.api#httpBearerAuth") + .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", + AwsClientOption.class, StaticTokenProvider.class); + builder.nextControlFlow("else") + .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())", AwsClientOption.class) + .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); + builder.endControlFlow(); + } else { + if (authSchemeSpecUtils.useSraAuth()) { + builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); + builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); + } else { + if (defaultAwsAuthSignerMethod().isPresent()) { + builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); + } + } + + if (AuthUtils.usesBearerAuth(model)) { + builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", + AwsClientOption.class, TokenUtils.class); + builder.addCode(".option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())\n", AwsClientOption.class); + if (!authSchemeSpecUtils.useSraAuth()) { + builder.addCode(".option($T.TOKEN_SIGNER, defaultTokenSigner())", SdkAdvancedClientOption.class); + } } + builder.addCode(";\n"); } - builder.addCode(");"); + builder.endControlFlow(")"); return builder.build(); } From f72dac14ce848052098d9f2860649e38ba3deb7d Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 16 Apr 2025 09:27:19 -0700 Subject: [PATCH 05/53] Use generated PreferredAuthSchemeProvider to wrap/delegate --- .../tasks/AuthSchemeGeneratorTasks.java | 6 ++ .../auth/scheme/AuthSchemeProviderSpec.java | 67 +++--------- .../poet/auth/scheme/AuthSchemeSpecUtils.java | 4 + .../ModelBasedAuthSchemeProviderSpec.java | 47 +------- .../PreferredAuthSchemeProviderSpec.java | 100 ++++++++++++++++++ 5 files changed, 126 insertions(+), 98 deletions(-) create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java index fbcec7931bd8..38c170898f27 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.codegen.poet.auth.scheme.EndpointAwareAuthSchemeParamsSpec; import software.amazon.awssdk.codegen.poet.auth.scheme.EndpointBasedAuthSchemeProviderSpec; import software.amazon.awssdk.codegen.poet.auth.scheme.ModelBasedAuthSchemeProviderSpec; +import software.amazon.awssdk.codegen.poet.auth.scheme.PreferredAuthSchemeProviderSpec; public final class AuthSchemeGeneratorTasks extends BaseGeneratorTasks { private final GeneratorTaskParams generatorTaskParams; @@ -45,6 +46,7 @@ protected List createTasks() { tasks.add(generateProviderInterface()); tasks.add(generateDefaultParamsImpl()); tasks.add(generateModelBasedProvider()); + tasks.add(generatePreferenceProvider()); tasks.add(generateAuthSchemeInterceptor()); if (authSchemeSpecUtils.useEndpointBasedAuthProvider()) { tasks.add(generateEndpointBasedProvider()); @@ -69,6 +71,10 @@ private GeneratorTask generateModelBasedProvider() { return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new ModelBasedAuthSchemeProviderSpec(model)); } + private GeneratorTask generatePreferenceProvider() { + return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new PreferredAuthSchemeProviderSpec(model)); + } + private GeneratorTask generateEndpointBasedProvider() { return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new EndpointBasedAuthSchemeProviderSpec(model)); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index 593628dfcb01..af532c83785c 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -18,11 +18,9 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import javax.lang.model.element.Modifier; @@ -32,7 +30,6 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; -import software.amazon.awssdk.utils.CollectionUtils; public class AuthSchemeProviderSpec implements ClassSpec { private final IntermediateModel intermediateModel; @@ -57,57 +54,17 @@ public TypeSpec poetSpec() { .addJavadoc(interfaceJavadoc()) .addMethod(resolveAuthSchemeMethod()) .addMethod(resolveAuthSchemeConsumerBuilderMethod()) - .addMethod(resolveCandidateAuthSchemeMethod()) - .addMethod(getAuthSchemePreferenceMethod()) .addMethod(defaultProviderMethod()) - .addMethod(defaultProviderWithAuthPreferenceMethod()) + .addMethod(defaultProviderWithPreferenceMethod()) .build(); } private MethodSpec resolveAuthSchemeMethod() { MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme"); - b.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT); - b.addParameter(authSchemeSpecUtils.parametersInterfaceName(), "authSchemeParams"); - b.returns(authSchemeSpecUtils.resolverReturnType()); - b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); - b.addStatement("$T candidateAuthSchemes = resolveCandidateAuthScheme(authSchemeParams)", authSchemeSpecUtils.resolverReturnType()); - b.addStatement("$T authSchemePreference = getAuthSchemePreference()", ParameterizedTypeName.get(List.class, - String.class)); - b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) - .addStatement("return candidateAuthSchemes") - .endControlFlow(); - - b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); - b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") - .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" - + ".ifPresent(a -> authSchemes.add(a))") - .endControlFlow(")"); - - b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") - .beginControlFlow("if (!authSchemes.contains(candidate))") - .addStatement("authSchemes.add(candidate)") - .endControlFlow() - .endControlFlow(")"); - - b.addStatement("return authSchemes"); - - return b.build(); - } - - private MethodSpec resolveCandidateAuthSchemeMethod() { - MethodSpec.Builder b = MethodSpec.methodBuilder("resolveCandidateAuthScheme"); b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); b.addParameter(authSchemeSpecUtils.parametersInterfaceName(), "authSchemeParams"); b.returns(authSchemeSpecUtils.resolverReturnType()); - b.addJavadoc("Resolve candidate auth schemes based on the given set of parameters."); - return b.build(); - } - - private MethodSpec getAuthSchemePreferenceMethod() { - MethodSpec.Builder b = MethodSpec.methodBuilder("getAuthSchemePreference"); - b.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); - b.returns(ParameterizedTypeName.get(List.class, String.class)); - b.addJavadoc("get the ordered list of auth scheme preferences."); + b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); return b.build(); } @@ -131,21 +88,21 @@ private MethodSpec resolveAuthSchemeConsumerBuilderMethod() { private MethodSpec defaultProviderMethod() { return MethodSpec.methodBuilder("defaultProvider") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className()) - .addJavadoc("Get the default auth scheme provider.") - .addStatement("return $T.create()", authSchemeSpecUtils.defaultAuthSchemeProviderName()) - .build(); + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(className()) + .addJavadoc("Get the default auth scheme provider.") + .addStatement("return $T.create()", authSchemeSpecUtils.defaultAuthSchemeProviderName()) + .build(); } - private MethodSpec defaultProviderWithAuthPreferenceMethod() { + private MethodSpec defaultProviderWithPreferenceMethod() { return MethodSpec.methodBuilder("defaultProvider") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className()) .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addJavadoc("Get the default auth scheme provider.") - // TODO: Add javadoc here for the parameter - .addStatement("return $T.create(authSchemePreference)", authSchemeSpecUtils.defaultAuthSchemeProviderName()) + .returns(className()) + .addJavadoc("Get the default auth scheme provider with auth scheme preference.") + .addStatement("return new $T(defaultProvider(), authSchemePreference)", + authSchemeSpecUtils.preferredAuthSchemeProviderName()) .build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java index a02f3e8bc893..8be513dbf3e6 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java @@ -93,6 +93,10 @@ public ClassName defaultAuthSchemeProviderName() { return ClassName.get(internalPackage(), "Default" + providerInterfaceName().simpleName()); } + public ClassName preferredAuthSchemeProviderName() { + return ClassName.get(internalPackage(), "Preferred" + providerInterfaceName().simpleName()); + } + public ClassName modeledAuthSchemeProviderName() { return ClassName.get(internalPackage(), "Modeled" + providerInterfaceName().simpleName()); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java index 877a75566210..79d5125e65c5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/ModelBasedAuthSchemeProviderSpec.java @@ -55,13 +55,9 @@ public TypeSpec poetSpec() { .addAnnotation(SdkInternalApi.class) .addSuperinterface(authSchemeSpecUtils.providerInterfaceName()) .addMethod(constructor()) - .addMethod(constructorWithAuthPreference()) .addField(defaultInstance()) - .addField(authPreference()) .addMethod(createMethod()) - .addMethod(createWithAuthPreferenceMethod()) - .addMethod(getAuthSchemePreferenceMethod()) - .addMethod(resolveCandidateAuthSchemeMethod()) + .addMethod(resolveAuthSchemeMethod()) .build(); } @@ -72,25 +68,8 @@ private FieldSpec defaultInstance() { .build(); } - private FieldSpec authPreference() { - return FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addModifiers(Modifier.PRIVATE, Modifier.FINAL) - .build(); - } - private MethodSpec constructor() { - return MethodSpec.constructorBuilder() - .addModifiers(Modifier.PRIVATE) - .addStatement("authSchemePreference = $T.emptyList()", Collections.class) - .build(); - } - - private MethodSpec constructorWithAuthPreference() { - return MethodSpec.constructorBuilder() - .addModifiers(Modifier.PRIVATE) - .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addStatement("this.authSchemePreference = authSchemePreference") // TODO: Should we copy this? - .build(); + return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build(); } private MethodSpec createMethod() { @@ -101,26 +80,8 @@ private MethodSpec createMethod() { .build(); } - private MethodSpec createWithAuthPreferenceMethod() { - return MethodSpec.methodBuilder("create") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className()) - .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addStatement("return new $T(authSchemePreference)", className()) - .build(); - } - - private MethodSpec getAuthSchemePreferenceMethod() { - return MethodSpec.methodBuilder("getAuthSchemePreference") - .addModifiers(Modifier.PUBLIC) - .addAnnotation(Override.class) - .returns(ParameterizedTypeName.get(List.class, String.class)) - .addStatement("return authSchemePreference") // TODO: return copy? - .build(); - } - - private MethodSpec resolveCandidateAuthSchemeMethod() { - MethodSpec.Builder spec = MethodSpec.methodBuilder("resolveCandidateAuthScheme") + private MethodSpec resolveAuthSchemeMethod() { + MethodSpec.Builder spec = MethodSpec.methodBuilder("resolveAuthScheme") .addModifiers(Modifier.PUBLIC) .addAnnotation(Override.class) .returns(authSchemeSpecUtils.resolverReturnType()) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java new file mode 100644 index 000000000000..cb156269e2ef --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java @@ -0,0 +1,100 @@ +/* + * 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.codegen.poet.auth.scheme; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.List; +import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.PoetUtils; +import software.amazon.awssdk.utils.CollectionUtils; + +public class PreferredAuthSchemeProviderSpec implements ClassSpec { + private final AuthSchemeSpecUtils authSchemeSpecUtils; + private final AuthSchemeCodegenKnowledgeIndex knowledgeIndex; + + public PreferredAuthSchemeProviderSpec(IntermediateModel intermediateModel) { + this.authSchemeSpecUtils = new AuthSchemeSpecUtils(intermediateModel); + this.knowledgeIndex = AuthSchemeCodegenKnowledgeIndex.of(intermediateModel); + } + + @Override + public ClassName className() { + return authSchemeSpecUtils.preferredAuthSchemeProviderName(); + } + + @Override + public TypeSpec poetSpec() { + return PoetUtils.createClassBuilder(className()) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addAnnotation(SdkInternalApi.class) + .addField( + authSchemeSpecUtils.providerInterfaceName(), "delegate", + Modifier.PRIVATE, Modifier.FINAL) + .addField( + ParameterizedTypeName.get(List.class, String.class), "authSchemePreference", + Modifier.PRIVATE, Modifier.FINAL) + .addSuperinterface(authSchemeSpecUtils.providerInterfaceName()) + .addMethod(constructor()) + .addMethod(resolveAuthSchemeMethod()) + .build(); + } + private MethodSpec constructor() { + return MethodSpec + .constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(authSchemeSpecUtils.providerInterfaceName(), "delegate") + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addStatement("this.delegate = delegate") + .addStatement("this.authSchemePreference = authSchemePreference") + .build(); + } + + private MethodSpec resolveAuthSchemeMethod() { + MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(authSchemeSpecUtils.resolverReturnType()) + .addParameter(authSchemeSpecUtils.parametersInterfaceName(), "params"); + b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); + b.addStatement("$T candidateAuthSchemes = delegate.resolveAuthScheme(params)", + authSchemeSpecUtils.resolverReturnType()); + b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) + .addStatement("return candidateAuthSchemes") + .endControlFlow(); + + b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); + b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") + .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" + + ".ifPresent(a -> authSchemes.add(a))") + .endControlFlow(")"); + + b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") + .beginControlFlow("if (!authSchemes.contains(candidate))") + .addStatement("authSchemes.add(candidate)") + .endControlFlow() + .endControlFlow(")"); + + b.addStatement("return authSchemes"); + return b.build(); + } +} From 26b8fdaf6cd57dbb803b0b6d1f1d6e81ebb96034 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 1 May 2025 10:13:27 -0700 Subject: [PATCH 06/53] Include tokenProvider in service config when bearer is on the model --- .../ServiceClientConfigurationUtils.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java index efe1a90ae9f1..fe786fdbc499 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java @@ -33,6 +33,7 @@ import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils; import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; +import software.amazon.awssdk.codegen.utils.AuthUtils; import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.ClientOption; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -43,6 +44,7 @@ import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; +import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.Validate; @@ -100,9 +102,33 @@ private List fields(IntermediateModel model) { authSchemeProviderField() )); fields.addAll(addCustomClientParams(model)); + fields.addAll(addModeledIdentityProviders(model)); return fields; } + private List addModeledIdentityProviders(IntermediateModel model) { + List identityProviderFields = new ArrayList<>(); + if (AuthUtils.usesBearerAuth(model)) { + identityProviderFields.add(tokenIdentityProviderField()); + } + return identityProviderFields; + } + + private Field tokenIdentityProviderField() { + TypeName tokenIdentityProviderType = + ParameterizedTypeName.get(ClassName.get(IdentityProvider.class), + WildcardTypeName.subtypeOf(TokenIdentity.class)); + + return fieldBuilder("tokenProvider", tokenIdentityProviderType) + .doc("token provider") + .isInherited(false) + .localSetter(basicLocalSetterCode("tokenProvider")) + .localGetter(basicLocalGetterCode("tokenProvider")) + .configSetter(basicConfigSetterCode(AwsClientOption.TOKEN_IDENTITY_PROVIDER, "tokenProvider")) + .configGetter(basicConfigGetterCode(AwsClientOption.TOKEN_IDENTITY_PROVIDER)) + .build(); + } + private List addCustomClientParams(IntermediateModel model) { List customClientParamFields = new ArrayList<>(); From 14682dcec7e4c67e01be9d6594e29ade2e953b47 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 1 May 2025 11:38:40 -0700 Subject: [PATCH 07/53] Support sourcing token from jvm settings + env variable. --- .../poet/builder/BaseClientBuilderClass.java | 47 +++++++++++++++---- .../awssdk/codegen/utils/AuthUtils.java | 2 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 50614f55fe87..945f8a507796 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -87,9 +87,9 @@ import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.StringUtils; +import software.amazon.awssdk.utils.SystemSetting; import software.amazon.awssdk.utils.Validate; import software.amazon.awssdk.utils.internal.CodegenNamingUtils; -import software.amazon.awssdk.utils.internal.SystemSettingUtils; public class BaseClientBuilderClass implements ClassSpec { private static final ParameterizedTypeName GENERIC_AUTH_SCHEME_TYPE = @@ -294,10 +294,34 @@ private MethodSpec mergeServiceDefaultsMethod() { builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", AwsClientOption.class, TokenUtils.class); builder.addCode(";\n"); - builder.addStatement("$T tokenFromEnv = $T.resolveEnvironmentVariable($S)", - ParameterizedTypeName.get(Optional.class, String.class), - SystemSettingUtils.class, - "AWS_BEARER_TOKEN_" + StringUtils.upperCase(model.getMetadata().getSigningName())); + String signingName = model.getMetadata().getSigningName(); + // TODO: is this the right transformation + String systemPropertyName = "aws.bearerToken" + StringUtils.capitalize(signingName); + String envName = "AWS_BEARER_TOKEN_" + StringUtils.upperCase(signingName); + TypeSpec inlineSystemSetting = TypeSpec.anonymousClassBuilder("") + .addSuperinterface(SystemSetting.class) + .addMethod(MethodSpec.methodBuilder("property") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", systemPropertyName) + .build()) + .addMethod(MethodSpec.methodBuilder("environmentVariable") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", envName) + .build()) + .addMethod(MethodSpec.methodBuilder("defaultValue") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return null") + .build()) + .build(); + builder.addStatement("$T tokenSystemSetting = $L", SystemSetting.class, inlineSystemSetting); + builder.addStatement("$T tokenFromEnv = tokenSystemSetting.getStringValue()", + ParameterizedTypeName.get(Optional.class, String.class)); builder .beginControlFlow("if (tokenFromEnv.isPresent() && c.option($T.AUTH_SCHEME_PROVIDER) == null && c.option($T" @@ -324,11 +348,16 @@ private MethodSpec mergeServiceDefaultsMethod() { } if (AuthUtils.usesBearerAuth(model)) { - builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", - AwsClientOption.class, TokenUtils.class); - builder.addCode(".option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())\n", AwsClientOption.class); + builder.addCode( + ".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", + AwsClientOption.class, TokenUtils.class); + builder.addCode( + ".option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())\n", + AwsClientOption.class); if (!authSchemeSpecUtils.useSraAuth()) { - builder.addCode(".option($T.TOKEN_SIGNER, defaultTokenSigner())", SdkAdvancedClientOption.class); + builder.addCode( + ".option($T.TOKEN_SIGNER, defaultTokenSigner())", + SdkAdvancedClientOption.class); } } builder.addCode(";\n"); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java index a247710ea590..1088a49cf043 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java @@ -68,7 +68,7 @@ public static boolean isOpBearerAuth(IntermediateModel model, OperationModel opM } private static boolean isServiceBearerAuth(IntermediateModel model) { - return model.getMetadata().getAuth().contains(AuthType.BEARER); + return model.getMetadata().getAuthType() == AuthType.BEARER || model.getMetadata().getAuth().contains(AuthType.BEARER); } private static boolean isServiceSigv4a(IntermediateModel model) { From a6a1346e9e32a5a142e37a00e62cf89663c28c90 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 2 May 2025 09:55:05 -0700 Subject: [PATCH 08/53] Refactor + use namingStrategy + add tests --- .../codegen/naming/DefaultNamingStrategy.java | 16 + .../awssdk/codegen/naming/NamingStrategy.java | 15 + .../poet/builder/BaseClientBuilderClass.java | 107 +++--- .../naming/DefaultNamingStrategyTest.java | 33 ++ .../customization.config | 4 + .../endpoint-rule-set.json | 355 ++++++++++++++++++ .../endpoint-tests.json | 5 + .../environmenttokenprovider/service-2.json | 38 ++ .../EnvironmentTokenProviderTest.java | 141 +++++++ 9 files changed, 666 insertions(+), 48 deletions(-) create mode 100644 test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/customization.config create mode 100644 test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-rule-set.json create mode 100644 test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-tests.json create mode 100644 test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/service-2.json create mode 100644 test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java index e5a4904f295f..efb230313efb 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java @@ -432,6 +432,22 @@ private boolean isDisallowedNameForShape(String name, Shape parentShape) { } } + @Override + public String getSigningName() { + return Optional.ofNullable(serviceModel.getMetadata().getSigningName()) + .orElseGet(() -> serviceModel.getMetadata().getEndpointPrefix()); + } + + @Override + public String getSigningNameForEnvironmentVariables() { + return screamCase(getSigningName()); + } + + @Override + public String getSigningNameForSystemProperties() { + return pascalCase(getSigningName()); + } + @Override public void validateCustomerVisibleNaming(IntermediateModel trimmedModel) { Metadata metadata = trimmedModel.getMetadata(); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java index 1fe32773d71f..dd434a0546e5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java @@ -200,6 +200,21 @@ public interface NamingStrategy { */ String getExistenceCheckMethodName(String memberName, Shape parentShape); + /** + * Retrieve the service's signing name that should be used based on the model. + */ + String getSigningName(); + + /** + * Retrieve the service name that should be used for environment variables. + */ + String getSigningNameForEnvironmentVariables(); + + /** + * Retrieve the service name that should be used for system properties. + */ + String getSigningNameForSystemProperties(); + /** * Verify the customer-visible naming in the provided intermediate model will compile and is idiomatic to Java. */ diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 945f8a507796..94fe60e08c31 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -52,6 +52,7 @@ import software.amazon.awssdk.codegen.model.intermediate.OperationModel; import software.amazon.awssdk.codegen.model.service.AuthType; import software.amazon.awssdk.codegen.model.service.ClientContextParam; +import software.amazon.awssdk.codegen.naming.NamingStrategy; import software.amazon.awssdk.codegen.poet.ClassSpec; import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils; @@ -289,54 +290,7 @@ private MethodSpec mergeServiceDefaultsMethod() { } if (enableEnvironmentBearerToken) { - // this applies only on SRA auth AND bearer it should be validated already, so skip those - builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); - builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", - AwsClientOption.class, TokenUtils.class); - builder.addCode(";\n"); - String signingName = model.getMetadata().getSigningName(); - // TODO: is this the right transformation - String systemPropertyName = "aws.bearerToken" + StringUtils.capitalize(signingName); - String envName = "AWS_BEARER_TOKEN_" + StringUtils.upperCase(signingName); - TypeSpec inlineSystemSetting = TypeSpec.anonymousClassBuilder("") - .addSuperinterface(SystemSetting.class) - .addMethod(MethodSpec.methodBuilder("property") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return $S", systemPropertyName) - .build()) - .addMethod(MethodSpec.methodBuilder("environmentVariable") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return $S", envName) - .build()) - .addMethod(MethodSpec.methodBuilder("defaultValue") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return null") - .build()) - .build(); - builder.addStatement("$T tokenSystemSetting = $L", SystemSetting.class, inlineSystemSetting); - builder.addStatement("$T tokenFromEnv = tokenSystemSetting.getStringValue()", - ParameterizedTypeName.get(Optional.class, String.class)); - - builder - .beginControlFlow("if (tokenFromEnv.isPresent() && c.option($T.AUTH_SCHEME_PROVIDER) == null && c.option($T" - + ".TOKEN_IDENTITY_PROVIDER) == null)", - SdkClientOption.class, AwsClientOption.class) - - .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, $T.defaultProvider($T.singletonList($S)))", - SdkClientOption.class, authSchemeSpecUtils.providerInterfaceName(), Collections.class, - "smithy.api#httpBearerAuth") - .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", - AwsClientOption.class, StaticTokenProvider.class); - builder.nextControlFlow("else") - .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())", AwsClientOption.class) - .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); - builder.endControlFlow(); + configureEnvironmentBearerToken(builder); } else { if (authSchemeSpecUtils.useSraAuth()) { builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); @@ -367,6 +321,63 @@ private MethodSpec mergeServiceDefaultsMethod() { return builder.build(); } + private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { + // this applies only on SRA auth AND bearer it should be validated already, so skip those + builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); + builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", + AwsClientOption.class, TokenUtils.class); + builder.addCode(";\n"); + + builder.addStatement("$T tokenSystemSetting = $L", SystemSetting.class, bearerTokenSystemSetting()); + builder.addStatement("$T tokenFromEnv = tokenSystemSetting.getStringValue()", + ParameterizedTypeName.get(Optional.class, String.class)); + + builder + .beginControlFlow("if (tokenFromEnv.isPresent() && c.option($T.AUTH_SCHEME_PROVIDER) == null && c.option($T" + + ".TOKEN_IDENTITY_PROVIDER) == null)", + SdkClientOption.class, AwsClientOption.class) + + .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, $T.defaultProvider($T.singletonList($S)))", + SdkClientOption.class, authSchemeSpecUtils.providerInterfaceName(), Collections.class, + "smithy.api#httpBearerAuth") + .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", + AwsClientOption.class, StaticTokenProvider.class); + builder.nextControlFlow("else") + .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())", AwsClientOption.class) + .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); + builder.endControlFlow(); + } + + private TypeSpec bearerTokenSystemSetting() { + NamingStrategy namingStrategy = model.getNamingStrategy(); + + String systemPropertyName = "aws.bearerToken" + namingStrategy.getSigningNameForSystemProperties(); + String envName = "AWS_BEARER_TOKEN_" + namingStrategy.getSigningNameForEnvironmentVariables(); + + return TypeSpec.anonymousClassBuilder("") + .addSuperinterface(SystemSetting.class) + .addMethod(MethodSpec.methodBuilder("property") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", systemPropertyName) + .build()) + .addMethod(MethodSpec.methodBuilder("environmentVariable") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", envName) + .build()) + .addMethod(MethodSpec.methodBuilder("defaultValue") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return null") + .build()) + .build(); + + } + private Optional mergeInternalDefaultsMethod() { String userAgent = model.getCustomizationConfig().getUserAgent(); RetryMode defaultRetryMode = model.getCustomizationConfig().getDefaultRetryMode(); diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java index 6b8756474405..cec5a7fd4bb2 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategyTest.java @@ -337,6 +337,39 @@ public void validateAllowsUnderscoresWithCustomization() { strategy.validateCustomerVisibleNaming(model); } + @Test + public void getSigningNameForEnvironmentVariables_convertsDashAndUppercases() { + when(serviceModel.getMetadata()).thenReturn(serviceMetadata); + when(serviceMetadata.getSigningName()).thenReturn("signing-name"); + + assertThat(strat.getSigningNameForEnvironmentVariables()).isEqualTo("SIGNING_NAME"); + } + + @Test + public void getSigningNameForSystemProperties_convertsDashAndUppercasesWords() { + when(serviceModel.getMetadata()).thenReturn(serviceMetadata); + when(serviceMetadata.getSigningName()).thenReturn("signing-name"); + + assertThat(strat.getSigningNameForSystemProperties()).isEqualTo("SigningName"); + } + + @Test + public void getSigningName_Uses_EndpointPrefix_whenSigningNameUnset() { + when(serviceModel.getMetadata()).thenReturn(serviceMetadata); + when(serviceMetadata.getSigningName()).thenReturn(null); + when(serviceMetadata.getEndpointPrefix()).thenReturn("EndpointPrefixFoo"); + + assertThat(strat.getSigningName()).isEqualTo("EndpointPrefixFoo"); + } + + @Test + public void getSigningName_Uses_SigningName() { + when(serviceModel.getMetadata()).thenReturn(serviceMetadata); + when(serviceMetadata.getSigningName()).thenReturn("Foo"); + + assertThat(strat.getSigningName()).isEqualTo("Foo"); + } + @Test public void validateServiceIdentifiersForEnvVarsAndProfileProperty() { when(serviceModel.getMetadata()).thenReturn(serviceMetadata); diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/customization.config b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/customization.config new file mode 100644 index 000000000000..86839537eeab --- /dev/null +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/customization.config @@ -0,0 +1,4 @@ +{ + "skipEndpointTestGeneration": true, + "enableEnvironmentBearerToken": true +} diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-rule-set.json b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-rule-set.json new file mode 100644 index 000000000000..cc38f1ffb165 --- /dev/null +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-rule-set.json @@ -0,0 +1,355 @@ +{ + "version": "1.3", + "parameters": { + "Region": { + "builtIn": "AWS::Region", + "required": true, + "documentation": "The AWS region used to dispatch the request.", + "type": "String" + }, + "UseDualStack": { + "builtIn": "AWS::UseDualStack", + "required": true, + "default": false, + "documentation": "When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.", + "type": "Boolean" + }, + "UseFIPS": { + "builtIn": "AWS::UseFIPS", + "required": true, + "default": false, + "documentation": "When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.", + "type": "Boolean" + }, + "Endpoint": { + "builtIn": "SDK::Endpoint", + "required": false, + "documentation": "Override the endpoint used to send this request", + "type": "String" + } + }, + "rules": [ + { + "conditions": [ + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "PartitionResult" + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "error": "Invalid Configuration: FIPS and custom endpoint are not supported", + "type": "error" + }, + { + "conditions": [], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "error": "Invalid Configuration: Dualstack and custom endpoint are not supported", + "type": "error" + }, + { + "conditions": [], + "endpoint": { + "url": { + "ref": "Endpoint" + }, + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "environment-token" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsDualStack" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://environment-token-fips.{Region}.{PartitionResult#dualStackDnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "environment-token" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + }, + { + "conditions": [], + "error": "FIPS and DualStack are enabled, but this partition does not support one or both", + "type": "error" + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://environment-token-fips.{Region}.{PartitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "environment-token" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] + }, + { + "conditions": [], + "error": "FIPS is enabled but this partition does not support FIPS", + "type": "error" + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsDualStack" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://environment-token.{Region}.{PartitionResult#dualStackDnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "environment-token" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + }, + { + "conditions": [], + "error": "DualStack is enabled but this partition does not support DualStack", + "type": "error" + } + ] + }, + { + "conditions": [], + "endpoint": { + "url": "https://environment-token.{Region}.{PartitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "environment-token" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] +} \ No newline at end of file diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-tests.json b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-tests.json new file mode 100644 index 000000000000..f94902ff9d99 --- /dev/null +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/endpoint-tests.json @@ -0,0 +1,5 @@ +{ + "testCases": [ + ], + "version": "1.0" +} \ No newline at end of file diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/service-2.json b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/service-2.json new file mode 100644 index 000000000000..c70811a87f80 --- /dev/null +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/environmenttokenprovider/service-2.json @@ -0,0 +1,38 @@ +{ + "version":"2.0", + "metadata":{ + "apiVersion":"2016-03-11", + "endpointPrefix":"environment-token", + "auth":["aws.auth#sigv4", "smithy.api#httpBearerAuth"], + "jsonVersion":"1.1", + "protocol":"rest-json", + "serviceAbbreviation":"EnvironmentTokenProviderService", + "serviceFullName":"Environment Token Provider Service", + "serviceId":"EnvironmentTokenProviderService", + "signatureVersion":"v4", + "targetPrefix":"EnvironmentTokenProviderService", + "timestampFormat":"unixTimestamp", + "uid":"restjson-2016-03-11" + }, + "operations":{ + "OneOperation":{ + "name":"OneOperation", + "http":{ + "method":"POST", + "requestUri":"/2016-03-11/oneoperation" + }, + "input":{"shape":"OneShape"} + } + }, + "shapes": { + "OneShape": { + "type": "structure", + "members": { + "StringMember": { + "shape": "String" + } + } + }, + "String":{"type":"string"} + } +} diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java new file mode 100644 index 000000000000..d44a7c1c992b --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java @@ -0,0 +1,141 @@ +/* + * 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.services.environmenttokenprovider; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.AfterEach; +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.StaticCredentialsProvider; +import software.amazon.awssdk.http.HttpExecuteResponse; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.http.SdkHttpResponse; +import software.amazon.awssdk.services.environmenttokenprovider.auth.scheme.EnvironmentTokenProviderAuthSchemeProvider; +import software.amazon.awssdk.testutils.EnvironmentVariableHelper; +import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient; + +public class EnvironmentTokenProviderTest { + private static final String ENV_NAME = "AWS_BEARER_TOKEN_ENVIRONMENT_TOKEN"; + private static final String SYSTEM_PROPERTY_NAME = "aws.bearerTokenEnvironmentToken"; + public static final String ENV_TOKEN = "env-test-token"; + public static final String SYSTEM_TEST_TOKEN = "system-test-token"; + + private MockSyncHttpClient mockHttpClient; + private String systemPropertyBeforeTest; + + private final EnvironmentVariableHelper environmentVariableHelper = new EnvironmentVariableHelper(); + + @BeforeEach + void setUp() { + mockHttpClient = new MockSyncHttpClient(); + systemPropertyBeforeTest = System.getProperty(SYSTEM_PROPERTY_NAME); + } + + @AfterEach + void tearDown() { + mockHttpClient.reset(); + environmentVariableHelper.reset(); + if (systemPropertyBeforeTest != null) { + System.setProperty(SYSTEM_PROPERTY_NAME, systemPropertyBeforeTest); + } else { + System.clearProperty(SYSTEM_PROPERTY_NAME); + } + } + + @Test + public void usesSigv4WhenTokenUnset() { + mockHttpClient.stubNextResponse(mockResponse()); + + EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + .builder() + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid"))) + .httpClient(mockHttpClient) + .build(); + + client.oneOperation(b -> { + }); + + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).startsWith("AWS4-HMAC-SHA256 Credential=akid/"); + } + + @Test + public void usesBearerAuthWithTokenFromEnvironmentWhenSet() { + environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); + mockHttpClient.stubNextResponse(mockResponse()); + + EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + .builder() + .httpClient(mockHttpClient) + .build(); + + client.oneOperation(b -> { + }); + + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo(String.format("Bearer %s", ENV_TOKEN)); + } + + @Test + public void usesBearerAuthWithTokenPreferredFromSystemProperties() { + environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); + System.setProperty(SYSTEM_PROPERTY_NAME, SYSTEM_TEST_TOKEN); + + + mockHttpClient.stubNextResponse(mockResponse()); + + EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + .builder() + .httpClient(mockHttpClient) + .build(); + + client.oneOperation(b -> { + }); + + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()) + .isEqualTo(String.format("Bearer %s", SYSTEM_TEST_TOKEN)); + } + + // TODO: Additional priority tests when auth scheme preference is complete + + @Test + public void usesSigv4WhenAuthSchemeProviderIsManuallyConfigured() { + mockHttpClient.stubNextResponse(mockResponse()); + environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); + + EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + .builder() + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid"))) + .authSchemeProvider(EnvironmentTokenProviderAuthSchemeProvider.defaultProvider()) + .httpClient(mockHttpClient) + .build(); + + client.oneOperation(b -> { + }); + + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).startsWith("AWS4-HMAC-SHA256 Credential=akid/"); + } + + private HttpExecuteResponse mockResponse() { + return HttpExecuteResponse.builder() + .response(SdkHttpResponse.builder().statusCode(200).build()) + .build(); + } +} From 60165c1ee7eb638ed5d44f21e5332d9257ea5cd2 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 2 May 2025 13:09:58 -0700 Subject: [PATCH 09/53] Set business metric using an interceptor --- .../poet/builder/BaseClientBuilderClass.java | 103 +++++++++++++----- .../useragent/BusinessMetricFeatureId.java | 1 + 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 94fe60e08c31..7a3c69312fb8 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -63,6 +63,7 @@ import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.codegen.utils.AuthUtils; import software.amazon.awssdk.core.SdkPlugin; +import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; import software.amazon.awssdk.core.checksums.RequestChecksumCalculationResolver; import software.amazon.awssdk.core.checksums.ResponseChecksumValidation; @@ -72,13 +73,18 @@ import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.endpointdiscovery.providers.DefaultEndpointDiscoveryProviderChain; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; +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.SdkInternalExecutionAttribute; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.ProtocolNegotiation; import software.amazon.awssdk.http.SdkHttpConfigurationOption; import software.amazon.awssdk.http.auth.aws.signer.RegionSet; +import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; @@ -340,44 +346,81 @@ private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, $T.defaultProvider($T.singletonList($S)))", SdkClientOption.class, authSchemeSpecUtils.providerInterfaceName(), Collections.class, "smithy.api#httpBearerAuth") - .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", - AwsClientOption.class, StaticTokenProvider.class); + .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", + AwsClientOption.class, StaticTokenProvider.class) + .addStatement("$T interceptors = c.option($T.EXECUTION_INTERCEPTORS)", + ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), SdkClientOption.class) + .addStatement("$T envTokenMetricInterceptors = $T.singletonList($L)", + ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), Collections.class, + envTokenMetricInterceptor()) + .addStatement("c.option($T.EXECUTION_INTERCEPTORS, $T.mergeLists(interceptors, envTokenMetricInterceptors))", + SdkClientOption.class, CollectionUtils.class); builder.nextControlFlow("else") .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())", AwsClientOption.class) .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); builder.endControlFlow(); } - private TypeSpec bearerTokenSystemSetting() { + private TypeSpec bearerTokenSystemSetting() { NamingStrategy namingStrategy = model.getNamingStrategy(); String systemPropertyName = "aws.bearerToken" + namingStrategy.getSigningNameForSystemProperties(); String envName = "AWS_BEARER_TOKEN_" + namingStrategy.getSigningNameForEnvironmentVariables(); return TypeSpec.anonymousClassBuilder("") - .addSuperinterface(SystemSetting.class) - .addMethod(MethodSpec.methodBuilder("property") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return $S", systemPropertyName) - .build()) - .addMethod(MethodSpec.methodBuilder("environmentVariable") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return $S", envName) - .build()) - .addMethod(MethodSpec.methodBuilder("defaultValue") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return null") - .build()) - .build(); + .addSuperinterface(SystemSetting.class) + .addMethod(MethodSpec.methodBuilder("property") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", systemPropertyName) + .build()) + .addMethod(MethodSpec.methodBuilder("environmentVariable") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", envName) + .build()) + .addMethod(MethodSpec.methodBuilder("defaultValue") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return null") + .build()) + .build(); } + private TypeSpec envTokenMetricInterceptor() { + MethodSpec beforeExeuction = + MethodSpec + .methodBuilder("beforeExecution") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .addParameter(Context.BeforeExecution.class, "context") + .addParameter(ExecutionAttributes.class, "executionAttributes") + .addStatement("$T selectedAuthScheme = executionAttributes.getAttribute($T.SELECTED_AUTH_SCHEME)", + SelectedAuthScheme.class, SdkInternalExecutionAttribute.class) + .beginControlFlow("if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals($T" + + ".SCHEME_ID) && selectedAuthScheme.identity().isDone())", BearerAuthScheme.class) + .beginControlFlow("if (selectedAuthScheme.identity().getNow(null) instanceof $T)", TokenIdentity.class) + + .addStatement("$T configuredToken = ($T) selectedAuthScheme.identity().getNow(null)", + TokenIdentity.class, TokenIdentity.class) + .beginControlFlow("if (configuredToken.token().equals(tokenFromEnv.get()))") + .addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS)" + + ".addMetric($T.BEARER_SERVICE_ENV_VARS.value())", + SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class) + .endControlFlow() + .endControlFlow() + .endControlFlow() + .build(); + return TypeSpec.anonymousClassBuilder("") + .addSuperinterface(ExecutionInterceptor.class) + .addMethod(beforeExeuction) + .build(); + } + private Optional mergeInternalDefaultsMethod() { String userAgent = model.getCustomizationConfig().getUserAgent(); RetryMode defaultRetryMode = model.getCustomizationConfig().getDefaultRetryMode(); @@ -514,7 +557,7 @@ private MethodSpec finalizeServiceConfigurationMethod() { // serviceConfigBuilder; the service configuration classes (e.g. S3Configuration) return primitive booleans that // have a default when not present. builder.addStatement("builder.option($T.DUALSTACK_ENDPOINT_ENABLED, serviceConfigBuilder.dualstackEnabled())", - AwsClientOption.class); + AwsClientOption.class); } if (model.getCustomizationConfig().getServiceConfig().hasFipsProperty()) { @@ -524,14 +567,14 @@ private MethodSpec finalizeServiceConfigurationMethod() { if (model.getEndpointOperation().isPresent()) { builder.addStatement("builder.option($T.ENDPOINT_DISCOVERY_ENABLED, endpointDiscoveryEnabled)\n", - SdkClientOption.class); + SdkClientOption.class); } if (StringUtils.isNotBlank(model.getCustomizationConfig().getCustomRetryStrategy())) { builder.addStatement("builder.option($1T.RETRY_STRATEGY, $2T.resolveRetryStrategy(config))", - SdkClientOption.class, - PoetUtils.classNameFromFqcn(model.getCustomizationConfig().getCustomRetryStrategy())); + SdkClientOption.class, + PoetUtils.classNameFromFqcn(model.getCustomizationConfig().getCustomRetryStrategy())); } if (StringUtils.isNotBlank(model.getCustomizationConfig().getCustomRetryPolicy())) { @@ -557,7 +600,7 @@ private MethodSpec finalizeServiceConfigurationMethod() { if (endpointParamsKnowledgeIndex.hasAccountIdEndpointModeBuiltIn()) { builder.addStatement("builder.option($T.$L, resolveAccountIdEndpointMode(config))", - AwsClientOption.class, model.getNamingStrategy().getEnumValueName("accountIdEndpointMode")); + AwsClientOption.class, model.getNamingStrategy().getEnumValueName("accountIdEndpointMode")); } String serviceNameForEnvVar = model.getNamingStrategy().getServiceNameForEnvironmentVariables(); @@ -1039,10 +1082,10 @@ private MethodSpec internalPluginsMethod() { List internalPlugins = model.getCustomizationConfig().getInternalPlugins(); if (internalPlugins.isEmpty()) { return builder.addStatement("return $T.emptyList()", Collections.class) - .build(); + .build(); } - builder.addStatement("$T internalPlugins = new $T<>()", parameterizedTypeName, ArrayList.class); + builder.addStatement("$T internalPlugins = new $T<>()", parameterizedTypeName, ArrayList.class); for (String internalPlugin : internalPlugins) { String arguments = internalPluginNewArguments(internalPlugin); diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/useragent/BusinessMetricFeatureId.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/useragent/BusinessMetricFeatureId.java index 3779726894da..7f1483d56895 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/useragent/BusinessMetricFeatureId.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/useragent/BusinessMetricFeatureId.java @@ -41,6 +41,7 @@ public enum BusinessMetricFeatureId { ACCOUNT_ID_MODE_REQUIRED("R"), RESOLVED_ACCOUNT_ID("T"), DDB_MAPPER("d"), + BEARER_SERVICE_ENV_VARS("3"), UNKNOWN("Unknown"); private static final Map VALUE_MAP = From 8feab9e8cb145c7cc4887415a10159c73101e7da Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 2 May 2025 13:59:18 -0700 Subject: [PATCH 10/53] Add ability to override token provider on request --- .../AwsRequestOverrideConfiguration.java | 36 ++++++++++++++- .../internal/AwsExecutionContextBuilder.java | 44 ++++++++++--------- .../AwsExecutionContextBuilderTest.java | 19 +++++++- .../EnvironmentTokenProviderTest.java | 26 +++++++++++ 4 files changed, 101 insertions(+), 24 deletions(-) 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 cde970af6402..a73691ab1df1 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 @@ -23,6 +23,7 @@ import software.amazon.awssdk.core.RequestOverrideConfiguration; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; +import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.utils.builder.SdkBuilder; /** @@ -31,10 +32,12 @@ @SdkPublicApi public final class AwsRequestOverrideConfiguration extends RequestOverrideConfiguration { private final IdentityProvider credentialsProvider; + private final IdentityProvider tokenIdentityProvider; private AwsRequestOverrideConfiguration(BuilderImpl builder) { super(builder); this.credentialsProvider = builder.awsCredentialsProvider; + this.tokenIdentityProvider = builder.tokenIdentityProvider; } /** @@ -75,6 +78,16 @@ public Optional> credentialsI return Optional.ofNullable(credentialsProvider); } + /** + * The optional {@link IdentityProvider} that will provide a token identity to be used to + * authenticate this request. + * + * @return The optional {@link IdentityProvider}. + */ + public Optional> tokenIdentityProvider() { + return Optional.ofNullable(tokenIdentityProvider); + } + @Override public Builder toBuilder() { return new BuilderImpl(this); @@ -97,7 +110,8 @@ public boolean equals(Object o) { return false; } AwsRequestOverrideConfiguration that = (AwsRequestOverrideConfiguration) o; - return Objects.equals(credentialsProvider, that.credentialsProvider); + return Objects.equals(credentialsProvider, that.credentialsProvider) && + Objects.equals(tokenIdentityProvider, that.tokenIdentityProvider); } @Override @@ -105,6 +119,7 @@ public int hashCode() { int hashCode = 1; hashCode = 31 * hashCode + super.hashCode(); hashCode = 31 * hashCode + Objects.hashCode(credentialsProvider); + hashCode = 31 * hashCode + Objects.hashCode(tokenIdentityProvider); return hashCode; } @@ -139,6 +154,17 @@ default Builder credentialsProvider(IdentityProvider} that will provide a token identity to be used + * to authenticate this request. + * + * @param tokenIdentityProvider The {@link IdentityProvider}. + * @return This object for chaining. + */ + default Builder tokenIdentityProvider(IdentityProvider tokenIdentityProvider) { + throw new UnsupportedOperationException(); + } + @Override AwsRequestOverrideConfiguration build(); } @@ -146,6 +172,7 @@ default Builder credentialsProvider(IdentityProvider implements Builder { private IdentityProvider awsCredentialsProvider; + private IdentityProvider tokenIdentityProvider; private BuilderImpl() { } @@ -157,6 +184,7 @@ private BuilderImpl(RequestOverrideConfiguration requestOverrideConfiguration) { private BuilderImpl(AwsRequestOverrideConfiguration awsRequestOverrideConfig) { super(awsRequestOverrideConfig); this.awsCredentialsProvider = awsRequestOverrideConfig.credentialsProvider; + this.tokenIdentityProvider = awsRequestOverrideConfig.tokenIdentityProvider; } @Override @@ -170,6 +198,12 @@ public AwsCredentialsProvider credentialsProvider() { return CredentialUtils.toCredentialsProvider(awsCredentialsProvider); } + @Override + public Builder tokenIdentityProvider(IdentityProvider tokenIdentityProvider) { + this.tokenIdentityProvider = tokenIdentityProvider; + return this; + } + @Override public AwsRequestOverrideConfiguration build() { return new AwsRequestOverrideConfiguration(this); 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 63bbcaa6cdb0..6a6397f95f6f 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 @@ -68,8 +68,8 @@ private AwsExecutionContextBuilder() { * Used by both sync and async clients to create the execution context, and run initial interceptors. */ public static ExecutionContext - invokeInterceptorsAndCreateExecutionContext(ClientExecutionParams executionParams, - SdkClientConfiguration clientConfig) { + invokeInterceptorsAndCreateExecutionContext(ClientExecutionParams executionParams, + SdkClientConfiguration clientConfig) { // Note: This is currently copied to DefaultS3Presigner and other presigners. // Don't edit this without considering those @@ -134,13 +134,13 @@ private AwsExecutionContextBuilder() { putAuthSchemeResolutionAttributes(executionAttributes, clientConfig, originalRequest); ExecutionInterceptorChain executionInterceptorChain = - new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS)); + new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS)); InterceptorContext interceptorContext = InterceptorContext.builder() - .request(originalRequest) - .asyncRequestBody(executionParams.getAsyncRequestBody()) - .requestBody(executionParams.getRequestBody()) - .build(); + .request(originalRequest) + .asyncRequestBody(executionParams.getAsyncRequestBody()) + .requestBody(executionParams.getRequestBody()) + .build(); interceptorContext = runInitialInterceptors(interceptorContext, executionAttributes, executionInterceptorChain); SdkRequest modifiedRequests = interceptorContext.request(); @@ -217,9 +217,6 @@ private static void putAuthSchemeResolutionAttributes(ExecutionAttributes execut .putAttribute(SdkInternalExecutionAttribute.IDENTITY_PROVIDERS, identityProviders); } - // TODO(sra-identity-and-auth): This is hard coding the logic for the credentialsIdentityProvider from - // AwsRequestOverrideConfiguration. Currently, AwsRequestOverrideConfiguration does not support overriding the - // tokenIdentityProvider. When adding that support this method will need to be updated. private static IdentityProviders resolveIdentityProviders(SdkRequest originalRequest, SdkClientConfiguration clientConfig) { IdentityProviders identityProviders = @@ -232,19 +229,23 @@ private static IdentityProviders resolveIdentityProviders(SdkRequest originalReq return null; } - return originalRequest.overrideConfiguration() - .filter(c -> c instanceof AwsRequestOverrideConfiguration) - .map(c -> (AwsRequestOverrideConfiguration) c) - .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider) - .map(identityProvider -> - identityProviders.copy(b -> b.putIdentityProvider(identityProvider))) - .orElse(identityProviders); + return originalRequest + .overrideConfiguration() + .filter(c -> c instanceof AwsRequestOverrideConfiguration) + .map(c -> (AwsRequestOverrideConfiguration) c) + .map(c -> { + return identityProviders.copy(b -> { + c.credentialsIdentityProvider().ifPresent(b::putIdentityProvider); + c.tokenIdentityProvider().ifPresent(b::putIdentityProvider); + }); + }) + .orElse(identityProviders); } /** * Finalize {@link SdkRequest} by running beforeExecution and modifyRequest interceptors. * - * @param interceptorContext containing the immutable SdkRequest information the interceptor can act on + * @param interceptorContext containing the immutable SdkRequest information the interceptor can act on * @param executionAttributes mutable container of attributes concerning the execution and request * @return the {@link InterceptorContext} returns a context with a new SdkRequest */ @@ -277,12 +278,13 @@ private static MetricCollector resolveMetricCollector(ClientExecutionParams clientCredentialsProvider = StaticCredentialsProvider.create(AwsBasicCredentials.create("foo", "bar")); + IdentityProvider clientTokenProvider = StaticTokenProvider.create(() -> "client-token"); IdentityProviders identityProviders = - IdentityProviders.builder().putIdentityProvider(clientCredentialsProvider).build(); + IdentityProviders.builder() + .putIdentityProvider(clientCredentialsProvider) + .putIdentityProvider(clientTokenProvider) + .build(); SdkClientConfiguration clientConfig = testClientConfiguration() .option(SdkClientOption.IDENTITY_PROVIDERS, identityProviders) .build(); IdentityProvider requestCredentialsProvider = StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid")); + IdentityProvider requestTokenProvider = StaticTokenProvider.create(() -> "request-token"); Optional overrideConfiguration = - Optional.of(AwsRequestOverrideConfiguration.builder().credentialsProvider(requestCredentialsProvider).build()); + Optional.of(AwsRequestOverrideConfiguration.builder() + .credentialsProvider(requestCredentialsProvider) + .tokenIdentityProvider(requestTokenProvider) + .build()); when(sdkRequest.overrideConfiguration()).thenReturn(overrideConfiguration); ClientExecutionParams executionParams = clientExecutionParams(); @@ -420,6 +430,11 @@ public void invokeInterceptorsAndCreateExecutionContext_requestOverrideForIdenti actualIdentityProviders.identityProvider(AwsCredentialsIdentity.class); assertThat(actualIdentityProvider).isSameAs(requestCredentialsProvider); + + IdentityProvider actualTokenProvider = + actualIdentityProviders.identityProvider(TokenIdentity.class); + + assertThat(actualTokenProvider).isSameAs(requestTokenProvider); } private ClientExecutionParams clientExecutionParams() { diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java index d44a7c1c992b..aa7422d77dd5 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java @@ -22,10 +22,13 @@ import org.junit.jupiter.api.Test; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.auth.token.credentials.StaticTokenProvider; +import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpResponse; import software.amazon.awssdk.services.environmenttokenprovider.auth.scheme.EnvironmentTokenProviderAuthSchemeProvider; +import software.amazon.awssdk.services.environmenttokenprovider.model.OneOperationRequest; import software.amazon.awssdk.testutils.EnvironmentVariableHelper; import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient; @@ -89,6 +92,8 @@ public void usesBearerAuthWithTokenFromEnvironmentWhenSet() { SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo(String.format("Bearer %s", ENV_TOKEN)); + assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) + .matches(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); } @Test @@ -133,6 +138,27 @@ public void usesSigv4WhenAuthSchemeProviderIsManuallyConfigured() { assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).startsWith("AWS4-HMAC-SHA256 Credential=akid/"); } + @Test + public void metricNotSetWhenTokenOverriddenOnOperation() { + environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); + mockHttpClient.stubNextResponse(mockResponse()); + + EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + .builder() + .httpClient(mockHttpClient) + .build(); + + client.oneOperation(OneOperationRequest.builder() + .overrideConfiguration(c -> c.tokenIdentityProvider( + StaticTokenProvider.create(() -> "operation-token"))) + .build()); + + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo("Bearer operation-token"); + assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) + .doesNotMatch(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); + } + private HttpExecuteResponse mockResponse() { return HttpExecuteResponse.builder() .response(SdkHttpResponse.builder().statusCode(200).build()) From fc6d3e63d723eef8dff84911834c3dc4dd3a3d2f Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Fri, 2 May 2025 13:06:20 -0700 Subject: [PATCH 11/53] Adding functionality to config preferred authschemeProvider --- .../tasks/AuthSchemeGeneratorTasks.java | 6 ++ .../auth/scheme/AuthSchemeProviderSpec.java | 76 +++++++++++++ .../poet/auth/scheme/AuthSchemeSpecUtils.java | 9 ++ .../PreferredAuthSchemeProviderSpec.java | 101 ++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java index fbcec7931bd8..38c170898f27 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/AuthSchemeGeneratorTasks.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.codegen.poet.auth.scheme.EndpointAwareAuthSchemeParamsSpec; import software.amazon.awssdk.codegen.poet.auth.scheme.EndpointBasedAuthSchemeProviderSpec; import software.amazon.awssdk.codegen.poet.auth.scheme.ModelBasedAuthSchemeProviderSpec; +import software.amazon.awssdk.codegen.poet.auth.scheme.PreferredAuthSchemeProviderSpec; public final class AuthSchemeGeneratorTasks extends BaseGeneratorTasks { private final GeneratorTaskParams generatorTaskParams; @@ -45,6 +46,7 @@ protected List createTasks() { tasks.add(generateProviderInterface()); tasks.add(generateDefaultParamsImpl()); tasks.add(generateModelBasedProvider()); + tasks.add(generatePreferenceProvider()); tasks.add(generateAuthSchemeInterceptor()); if (authSchemeSpecUtils.useEndpointBasedAuthProvider()) { tasks.add(generateEndpointBasedProvider()); @@ -69,6 +71,10 @@ private GeneratorTask generateModelBasedProvider() { return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new ModelBasedAuthSchemeProviderSpec(model)); } + private GeneratorTask generatePreferenceProvider() { + return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new PreferredAuthSchemeProviderSpec(model)); + } + private GeneratorTask generateEndpointBasedProvider() { return new PoetGeneratorTask(authSchemeInternalDir(), model.getFileHeader(), new EndpointBasedAuthSchemeProviderSpec(model)); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index bc5255695ad1..84ad362ea975 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -17,12 +17,16 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.ClassSpec; @@ -54,6 +58,9 @@ public TypeSpec poetSpec() { .addMethod(resolveAuthSchemeMethod()) .addMethod(resolveAuthSchemeConsumerBuilderMethod()) .addMethod(defaultProviderMethod()) + .addMethod(staticBuilderMethodSpec()) + .addType(builderInterfaceSpec()) + .addType(builderClassSpec()) .build(); } @@ -104,4 +111,73 @@ private CodeBlock interfaceJavadoc() { return b.build(); } + + private MethodSpec staticBuilderMethodSpec() { + return MethodSpec.methodBuilder("builder") + .addJavadoc("Create a builder for the auth scheme provider.") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(className().nestedClass("Builder")) + .addStatement("return new $T()", ClassName.get(className().packageName(), + className().simpleName(), + className().simpleName() + "Builder") + ) + .build(); + } + + + private TypeSpec builderInterfaceSpec() { + return TypeSpec.interfaceBuilder("Builder") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addMethod(MethodSpec.methodBuilder("build") + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addJavadoc("Returns a {@link $T} object that is created from the " + + "properties that have been set on the builder.", + className()) + .returns(className()) + .build()) + + .addMethod(MethodSpec.methodBuilder("withPreferredAuthSchemes") + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addJavadoc("Set the preferred auth schemes in order of preference.") + .returns(className().nestedClass("Builder")) + .addParameter( + ParameterizedTypeName.get(List.class, String.class), + "authSchemePreference" + ) + .build()) + .build(); + } + + private TypeSpec builderClassSpec() { + return TypeSpec.classBuilder(authSchemeSpecUtils.authSchemeProviderBuilderName()) + .addAnnotation(SdkInternalApi.class) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC) + .addSuperinterface(className().nestedClass("Builder")) + .addField( + FieldSpec + .builder(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addModifiers(Modifier.PRIVATE) + .build()) + .addMethod( + MethodSpec + .methodBuilder("withPreferredAuthSchemes").addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .addParameter( + ParameterizedTypeName.get(List.class, String.class), + "authSchemePreference" + ) + .returns(className().nestedClass("Builder")) + .addStatement("this.authSchemePreference = new $T<>(authSchemePreference)", ArrayList.class).addStatement("return this") + .build()) + .addMethod( + MethodSpec + .methodBuilder("build").addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(className()) + .addStatement("return new $T(defaultProvider(), authSchemePreference)", + authSchemeSpecUtils.preferredAuthSchemeProviderName()) + .build()) + .build(); + } } + diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java index a02f3e8bc893..f6ea9e684b59 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecUtils.java @@ -97,6 +97,15 @@ public ClassName modeledAuthSchemeProviderName() { return ClassName.get(internalPackage(), "Modeled" + providerInterfaceName().simpleName()); } + public ClassName preferredAuthSchemeProviderName() { + return ClassName.get(internalPackage(), "Preferred" + providerInterfaceName().simpleName()); + } + + public ClassName authSchemeProviderBuilderName() { + return ClassName.get(basePackage(), + intermediateModel.getMetadata().getServiceName() + "AuthSchemeProviderBuilder"); + } + public ClassName authSchemeInterceptor() { return ClassName.get(internalPackage(), intermediateModel.getMetadata().getServiceName() + "AuthSchemeInterceptor"); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java new file mode 100644 index 000000000000..2b43bc1691ef --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java @@ -0,0 +1,101 @@ +/* + * 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.codegen.poet.auth.scheme; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.PoetUtils; +import software.amazon.awssdk.utils.CollectionUtils; + +public class PreferredAuthSchemeProviderSpec implements ClassSpec { + private final AuthSchemeSpecUtils authSchemeSpecUtils; + + public PreferredAuthSchemeProviderSpec(IntermediateModel intermediateModel) { + this.authSchemeSpecUtils = new AuthSchemeSpecUtils(intermediateModel); + } + + @Override + public ClassName className() { + return authSchemeSpecUtils.preferredAuthSchemeProviderName(); + } + + @Override + public TypeSpec poetSpec() { + return PoetUtils.createClassBuilder(className()) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addAnnotation(SdkInternalApi.class) + .addField( + authSchemeSpecUtils.providerInterfaceName(), "delegate", + Modifier.PRIVATE, Modifier.FINAL) + .addField( + ParameterizedTypeName.get(List.class, String.class), "authSchemePreference", + Modifier.PRIVATE, Modifier.FINAL) + .addSuperinterface(authSchemeSpecUtils.providerInterfaceName()) + .addMethod(constructor()) + .addMethod(resolveAuthSchemeMethod()) + .build(); + } + + private MethodSpec constructor() { + return MethodSpec + .constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(authSchemeSpecUtils.providerInterfaceName(), "delegate") + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .addStatement("this.delegate = delegate") + .addStatement("this.authSchemePreference = authSchemePreference != null ? authSchemePreference : $T.emptyList()", + Collections.class) + .build(); + } + + private MethodSpec resolveAuthSchemeMethod() { + MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(authSchemeSpecUtils.resolverReturnType()) + .addParameter(authSchemeSpecUtils.parametersInterfaceName(), "params"); + b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); + b.addStatement("$T candidateAuthSchemes = delegate.resolveAuthScheme(params)", + authSchemeSpecUtils.resolverReturnType()); + b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) + .addStatement("return candidateAuthSchemes") + .endControlFlow(); + + b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); + b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") + .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" + + ".ifPresent(a -> authSchemes.add(a))") + .endControlFlow(")"); + + b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") + .beginControlFlow("if (!authSchemes.contains(candidate))") + .addStatement("authSchemes.add(candidate)") + .endControlFlow() + .endControlFlow(")"); + + b.addStatement("return authSchemes"); + return b.build(); + } +} \ No newline at end of file From f18fcc2188e09c493292e545a9b495d3274e5c09 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Sun, 4 May 2025 19:22:35 -0700 Subject: [PATCH 12/53] adding test coverage --- .../scheme/query-auth-scheme-provider.java | 54 ++++++--- ...oint-auth-params-auth-scheme-provider.java | 54 ++++++--- .../PreferredAuthSchemeProviderTest.java | 106 ++++++++++++++++++ 3 files changed, 184 insertions(+), 30 deletions(-) create mode 100644 test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java index a4f84dc2665a..ba478a5c69d6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java @@ -1,27 +1,15 @@ -/* - * 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.services.query.auth.scheme; +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.DefaultQueryAuthSchemeProvider; +import software.amazon.awssdk.services.query.auth.scheme.internal.PreferredQueryAuthSchemeProvider; /** * An auth scheme provider for Query service. The auth scheme provider takes a set of parameters using @@ -50,4 +38,40 @@ default List resolveAuthScheme(Consumer authSchemePreference); + } + + @SdkInternalApi + final class QueryAuthSchemeProviderBuilder implements Builder { + private List authSchemePreference; + + @Override + public Builder withPreferredAuthSchemes(List authSchemePreference) { + this.authSchemePreference = new ArrayList<>(authSchemePreference); + return this; + } + + @Override + public QueryAuthSchemeProvider build() { + return new PreferredQueryAuthSchemeProvider(defaultProvider(), authSchemePreference); + } + } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java index a4f84dc2665a..ba478a5c69d6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java @@ -1,27 +1,15 @@ -/* - * 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.services.query.auth.scheme; +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.DefaultQueryAuthSchemeProvider; +import software.amazon.awssdk.services.query.auth.scheme.internal.PreferredQueryAuthSchemeProvider; /** * An auth scheme provider for Query service. The auth scheme provider takes a set of parameters using @@ -50,4 +38,40 @@ default List resolveAuthScheme(Consumer authSchemePreference); + } + + @SdkInternalApi + final class QueryAuthSchemeProviderBuilder implements Builder { + private List authSchemePreference; + + @Override + public Builder withPreferredAuthSchemes(List authSchemePreference) { + this.authSchemePreference = new ArrayList<>(authSchemePreference); + return this; + } + + @Override + public QueryAuthSchemeProvider build() { + return new PreferredQueryAuthSchemeProvider(defaultProvider(), authSchemePreference); + } + } } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java new file mode 100644 index 000000000000..75154d2d9d73 --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java @@ -0,0 +1,106 @@ +/* + * 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.services; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.multiauth.auth.scheme.MultiauthAuthSchemeParams; +import software.amazon.awssdk.services.multiauth.auth.scheme.MultiauthAuthSchemeProvider; + +public class PreferredAuthSchemeProviderTest { + + private static final String OPERATION_SIGV4A_ONLY = "multiAuthWithOnlySigv4a"; + private static final String OPERATION_SIGV4A_AND_SIGV4 = "multiAuthWithOnlySigv4aAndSigv4"; + + private static final String SIGV4 = "aws.auth#sigv4"; + private static final String SIGV4A = "aws.auth#sigv4a"; + private static final String BEARER = "aws.auth#bearer"; + private static final String ANONYMOUS = "aws.auth#noauth"; + + @ParameterizedTest(name = "{3}") + @MethodSource("authSchemeTestCases") + void testAuthSchemePreference(List preferredAuthSchemes, String operation, String expectedFirstScheme, String testName) { + MultiauthAuthSchemeProvider provider = MultiauthAuthSchemeProvider + .builder() + .withPreferredAuthSchemes(preferredAuthSchemes) + .build(); + + MultiauthAuthSchemeParams params = MultiauthAuthSchemeParams + .builder() + .region(Region.US_WEST_2) + .operation(operation) + .build(); + + List authSchemes = provider.resolveAuthScheme(params); + + Assertions.assertFalse(authSchemes.isEmpty()); + Assertions.assertEquals(expectedFirstScheme, authSchemes.get(0).schemeId()); + } + + static Stream authSchemeTestCases() { + return Stream.of( + Arguments.of( + Arrays.asList(BEARER, ANONYMOUS), + OPERATION_SIGV4A_AND_SIGV4, + SIGV4A, + "Unsupported auth schemes only" + ), + + Arguments.of( + Arrays.asList(BEARER, SIGV4, ANONYMOUS), + OPERATION_SIGV4A_AND_SIGV4, + SIGV4, + "Mix of supported and unsupported schemes" + ), + + Arguments.of( + Arrays.asList(SIGV4, SIGV4A), + OPERATION_SIGV4A_AND_SIGV4, + SIGV4, + "All supported schemes in reverse order" + ), + + Arguments.of( + Arrays.asList(SIGV4, SIGV4A), + OPERATION_SIGV4A_ONLY, + SIGV4A, + "Operation with only one supported scheme" + ), + + Arguments.of( + Collections.emptyList(), + OPERATION_SIGV4A_AND_SIGV4, + SIGV4A, + "Empty preference list" + ), + + Arguments.of( + Arrays.asList(SIGV4A, SIGV4, BEARER), + OPERATION_SIGV4A_AND_SIGV4, + SIGV4A, + "First preference is supported" + ) + ); + } +} From 72b138642e95406d401e616384d878a22e09eb7a Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Sun, 4 May 2025 19:57:32 -0700 Subject: [PATCH 13/53] fix formatting checkstyle --- .../codegen/poet/auth/scheme/AuthSchemeProviderSpec.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index 84ad362ea975..944223765a69 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -167,7 +167,8 @@ private TypeSpec builderClassSpec() { "authSchemePreference" ) .returns(className().nestedClass("Builder")) - .addStatement("this.authSchemePreference = new $T<>(authSchemePreference)", ArrayList.class).addStatement("return this") + .addStatement("this.authSchemePreference = new $T<>(authSchemePreference)", ArrayList.class) + .addStatement("return this") .build()) .addMethod( MethodSpec From 39dc9e4f075b2400f24c4258ef4b074b178c584f Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Sun, 4 May 2025 20:06:33 -0700 Subject: [PATCH 14/53] Added changelog --- .changes/next-release/feature-AWSSDKforJavav2-8e1c19d.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/next-release/feature-AWSSDKforJavav2-8e1c19d.json diff --git a/.changes/next-release/feature-AWSSDKforJavav2-8e1c19d.json b/.changes/next-release/feature-AWSSDKforJavav2-8e1c19d.json new file mode 100644 index 000000000000..9b79be5ad7e0 --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-8e1c19d.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Added ability to configure preferred authentication schemes when multiple auth options are available." +} From 345bb934df049c49a89bb2917655b9b85e07ad1e Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Mon, 5 May 2025 09:24:04 -0700 Subject: [PATCH 15/53] Fix checkstyle on prefered auth scheme provider --- .../PreferredAuthSchemeProviderSpec.java | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java index cb156269e2ef..c62df7804702 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java @@ -30,11 +30,9 @@ public class PreferredAuthSchemeProviderSpec implements ClassSpec { private final AuthSchemeSpecUtils authSchemeSpecUtils; - private final AuthSchemeCodegenKnowledgeIndex knowledgeIndex; public PreferredAuthSchemeProviderSpec(IntermediateModel intermediateModel) { this.authSchemeSpecUtils = new AuthSchemeSpecUtils(intermediateModel); - this.knowledgeIndex = AuthSchemeCodegenKnowledgeIndex.of(intermediateModel); } @Override @@ -58,6 +56,7 @@ public TypeSpec poetSpec() { .addMethod(resolveAuthSchemeMethod()) .build(); } + private MethodSpec constructor() { return MethodSpec .constructorBuilder() @@ -70,31 +69,31 @@ private MethodSpec constructor() { } private MethodSpec resolveAuthSchemeMethod() { - MethodSpec.Builder b = MethodSpec.methodBuilder("resolveAuthScheme") - .addModifiers(Modifier.PUBLIC) - .addAnnotation(Override.class) - .returns(authSchemeSpecUtils.resolverReturnType()) - .addParameter(authSchemeSpecUtils.parametersInterfaceName(), "params"); - b.addJavadoc("Resolve the auth schemes based on the given set of parameters."); - b.addStatement("$T candidateAuthSchemes = delegate.resolveAuthScheme(params)", - authSchemeSpecUtils.resolverReturnType()); - b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) - .addStatement("return candidateAuthSchemes") - .endControlFlow(); + MethodSpec.Builder builder = MethodSpec.methodBuilder("resolveAuthScheme") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(authSchemeSpecUtils.resolverReturnType()) + .addParameter(authSchemeSpecUtils.parametersInterfaceName(), "params"); + builder.addJavadoc("Resolve the auth schemes based on the given set of parameters."); + builder.addStatement("$T candidateAuthSchemes = delegate.resolveAuthScheme(params)", + authSchemeSpecUtils.resolverReturnType()); + builder.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) + .addStatement("return candidateAuthSchemes") + .endControlFlow(); - b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); - b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") - .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" - + ".ifPresent(a -> authSchemes.add(a))") - .endControlFlow(")"); + builder.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); + builder.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") + .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" + + ".ifPresent(a -> authSchemes.add(a))") + .endControlFlow(")"); - b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") - .beginControlFlow("if (!authSchemes.contains(candidate))") - .addStatement("authSchemes.add(candidate)") - .endControlFlow() - .endControlFlow(")"); + builder.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") + .beginControlFlow("if (!authSchemes.contains(candidate))") + .addStatement("authSchemes.add(candidate)") + .endControlFlow() + .endControlFlow(")"); - b.addStatement("return authSchemes"); - return b.build(); + builder.addStatement("return authSchemes"); + return builder.build(); } } From e55fe523a95ed568c80d13b5a0fa42c7b71b04c7 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Mon, 5 May 2025 09:24:26 -0700 Subject: [PATCH 16/53] Add validation of service+customization --- .../codegen/poet/builder/BaseClientBuilderClass.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 7a3c69312fb8..f76a12a957ed 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -306,7 +306,6 @@ private MethodSpec mergeServiceDefaultsMethod() { builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); } } - if (AuthUtils.usesBearerAuth(model)) { builder.addCode( ".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", @@ -328,7 +327,14 @@ private MethodSpec mergeServiceDefaultsMethod() { } private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { - // this applies only on SRA auth AND bearer it should be validated already, so skip those + if (!authSchemeSpecUtils.useSraAuth()) { + throw new IllegalStateException("The enableEnvironmentBearerToken customization requires SRA Auth."); + } + if (!AuthUtils.usesBearerAuth(model)) { + throw new IllegalStateException("The enableEnvironmentBearerToken customization requires the service to model and " + + "support smithy.api#httpBearerAuth."); + } + builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", AwsClientOption.class, TokenUtils.class); From 1849a83d40de70128530b7ae8bc0c6a0218e72e5 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Mon, 5 May 2025 13:05:44 -0700 Subject: [PATCH 17/53] Refactor env token customizaiton logic + add more tests --- .../poet/builder/AsyncClientBuilderClass.java | 3 - .../poet/builder/BaseClientBuilderClass.java | 71 ++++++++----------- .../poet/builder/SyncClientBuilderClass.java | 3 - .../awssdk/codegen/utils/AuthUtils.java | 3 +- .../awssdk/codegen/utils/AuthUtilsTest.java | 20 ++++-- ...test-no-auth-ops-client-builder-class.java | 26 +++++-- ...test-no-auth-ops-client-builder-class.java | 31 +++++++- 7 files changed, 95 insertions(+), 62 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java index 886c5ba0094e..0cc74f08bdb9 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/AsyncClientBuilderClass.java @@ -30,7 +30,6 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.codegen.utils.AuthUtils; -import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.identity.spi.IdentityProvider; @@ -156,8 +155,6 @@ private MethodSpec tokenProviderMethod() { .returns(builderClassName) .addStatement("clientConfiguration.option($T.TOKEN_IDENTITY_PROVIDER, tokenProvider)", AwsClientOption.class) - .addStatement("clientConfiguration.option($T.TOKEN_PROVIDER_CONFIGURED_EXPLICITLY, true)", - SdkAdvancedClientOption.class) .addStatement("return this") .build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index f76a12a957ed..0df13bcafad7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -274,18 +274,28 @@ private MethodSpec serviceNameMethod() { } private MethodSpec mergeServiceDefaultsMethod() { - boolean crc32FromCompressedDataEnabled = model.getCustomizationConfig().isCalculateCrc32FromCompressedData(); - boolean enableEnvironmentBearerToken = model.getCustomizationConfig().isEnableEnvironmentBearerToken(); - MethodSpec.Builder builder = MethodSpec.methodBuilder("mergeServiceDefaults") .addAnnotation(Override.class) .addModifiers(PROTECTED, FINAL) .returns(SdkClientConfiguration.class) - .addParameter(SdkClientConfiguration.class, "config") - .beginControlFlow("return config.merge(c ->"); + .addParameter(SdkClientConfiguration.class, "config"); - builder.addCode("c"); + if (model.getCustomizationConfig().isEnableEnvironmentBearerToken()) { + configureEnvironmentBearerToken(builder); + } + boolean crc32FromCompressedDataEnabled = model.getCustomizationConfig().isCalculateCrc32FromCompressedData(); + + builder.addCode("return config.merge(c -> c"); builder.addCode(".option($T.ENDPOINT_PROVIDER, defaultEndpointProvider())", SdkClientOption.class); + + if (authSchemeSpecUtils.useSraAuth()) { + builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); + builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); + } else { + if (defaultAwsAuthSignerMethod().isPresent()) { + builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); + } + } builder.addCode(".option($T.CRC32_FROM_COMPRESSED_DATA_ENABLED, $L)\n", SdkClientOption.class, crc32FromCompressedDataEnabled); @@ -295,34 +305,16 @@ private MethodSpec mergeServiceDefaultsMethod() { SdkClientOption.class, ClassName.bestGuess(clientConfigClassName)); } - if (enableEnvironmentBearerToken) { - configureEnvironmentBearerToken(builder); - } else { - if (authSchemeSpecUtils.useSraAuth()) { - builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); - builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); - } else { - if (defaultAwsAuthSignerMethod().isPresent()) { - builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); - } - } - if (AuthUtils.usesBearerAuth(model)) { - builder.addCode( - ".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", - AwsClientOption.class, TokenUtils.class); - builder.addCode( - ".option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())\n", - AwsClientOption.class); - if (!authSchemeSpecUtils.useSraAuth()) { - builder.addCode( - ".option($T.TOKEN_SIGNER, defaultTokenSigner())", - SdkAdvancedClientOption.class); - } + if (AuthUtils.usesBearerAuth(model)) { + builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", + AwsClientOption.class, TokenUtils.class); + builder.addCode(".option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())\n", AwsClientOption.class); + if (!authSchemeSpecUtils.useSraAuth()) { + builder.addCode(".option($T.TOKEN_SIGNER, defaultTokenSigner())", SdkAdvancedClientOption.class); } - builder.addCode(";\n"); } - builder.endControlFlow(")"); + builder.addCode(");"); return builder.build(); } @@ -335,20 +327,15 @@ private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { + "support smithy.api#httpBearerAuth."); } - builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); - builder.addCode(".lazyOption($1T.TOKEN_PROVIDER, p -> $2T.toSdkTokenProvider(p.get($1T.TOKEN_IDENTITY_PROVIDER)))", - AwsClientOption.class, TokenUtils.class); - builder.addCode(";\n"); - builder.addStatement("$T tokenSystemSetting = $L", SystemSetting.class, bearerTokenSystemSetting()); builder.addStatement("$T tokenFromEnv = tokenSystemSetting.getStringValue()", ParameterizedTypeName.get(Optional.class, String.class)); builder - .beginControlFlow("if (tokenFromEnv.isPresent() && c.option($T.AUTH_SCHEME_PROVIDER) == null && c.option($T" + .beginControlFlow("if (tokenFromEnv.isPresent() && config.option($T.AUTH_SCHEME_PROVIDER) == null && config.option($T" + ".TOKEN_IDENTITY_PROVIDER) == null)", SdkClientOption.class, AwsClientOption.class) - + .beginControlFlow("config = config.merge(c -> ") .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, $T.defaultProvider($T.singletonList($S)))", SdkClientOption.class, authSchemeSpecUtils.providerInterfaceName(), Collections.class, "smithy.api#httpBearerAuth") @@ -360,11 +347,9 @@ private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), Collections.class, envTokenMetricInterceptor()) .addStatement("c.option($T.EXECUTION_INTERCEPTORS, $T.mergeLists(interceptors, envTokenMetricInterceptors))", - SdkClientOption.class, CollectionUtils.class); - builder.nextControlFlow("else") - .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())", AwsClientOption.class) - .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider())", SdkClientOption.class); - builder.endControlFlow(); + SdkClientOption.class, CollectionUtils.class) + .endControlFlow(");") + .endControlFlow(); } private TypeSpec bearerTokenSystemSetting() { diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java index ad6bd09bc492..5fc251b73d46 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/SyncClientBuilderClass.java @@ -28,7 +28,6 @@ import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.codegen.utils.AuthUtils; -import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.identity.spi.IdentityProvider; @@ -148,8 +147,6 @@ private MethodSpec tokenProviderMethodImpl() { .returns(builderClassName) .addStatement("clientConfiguration.option($T.TOKEN_IDENTITY_PROVIDER, tokenProvider)", AwsClientOption.class) - .addStatement("clientConfiguration.option($T.TOKEN_PROVIDER_CONFIGURED_EXPLICITLY, true)", - SdkAdvancedClientOption.class) .addStatement("return this") .build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java index 1088a49cf043..004d64fac245 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/utils/AuthUtils.java @@ -68,7 +68,8 @@ public static boolean isOpBearerAuth(IntermediateModel model, OperationModel opM } private static boolean isServiceBearerAuth(IntermediateModel model) { - return model.getMetadata().getAuthType() == AuthType.BEARER || model.getMetadata().getAuth().contains(AuthType.BEARER); + return model.getMetadata().getAuthType() == AuthType.BEARER || + (model.getMetadata().getAuth() != null && model.getMetadata().getAuth().contains(AuthType.BEARER)); } private static boolean isServiceSigv4a(IntermediateModel model) { diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/utils/AuthUtilsTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/utils/AuthUtilsTest.java index 66e2311978ee..f93f0172fbc9 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/utils/AuthUtilsTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/utils/AuthUtilsTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -30,15 +31,17 @@ import software.amazon.awssdk.codegen.model.intermediate.Metadata; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; import software.amazon.awssdk.codegen.model.service.AuthType; +import software.amazon.awssdk.utils.CollectionUtils; public class AuthUtilsTest { @ParameterizedTest @MethodSource("serviceValues") public void testIfServiceHasBearerAuth(AuthType serviceAuthType, + List serviceAuthTypes, List opAuthTypes, Boolean expectedResult) { - IntermediateModel model = modelWith(serviceAuthType); + IntermediateModel model = modelWith(serviceAuthType, serviceAuthTypes); model.setOperations(createOperations(opAuthTypes)); assertThat(AuthUtils.usesBearerAuth(model)).isEqualTo(expectedResult); } @@ -47,10 +50,11 @@ private static Stream serviceValues() { List oneBearerOp = Arrays.asList(AuthType.BEARER, AuthType.S3V4, AuthType.NONE); List noBearerOp = Arrays.asList(AuthType.S3V4, AuthType.S3V4, AuthType.NONE); - return Stream.of(Arguments.of(AuthType.BEARER, noBearerOp, true), - Arguments.of(AuthType.BEARER, oneBearerOp, true), - Arguments.of(AuthType.S3V4, noBearerOp, false), - Arguments.of(AuthType.S3V4, oneBearerOp, true)); + return Stream.of(Arguments.of(AuthType.BEARER, Collections.emptyList(), noBearerOp, true), + Arguments.of(AuthType.BEARER, Collections.emptyList(), oneBearerOp, true), + Arguments.of(AuthType.S3V4, Collections.emptyList(), noBearerOp, false), + Arguments.of(AuthType.S3V4, Collections.emptyList(), oneBearerOp, true), + Arguments.of(AuthType.S3V4, oneBearerOp, noBearerOp, true)); } @ParameterizedTest @@ -106,6 +110,12 @@ private static IntermediateModel modelWith(AuthType authType) { return model; } + private static IntermediateModel modelWith(AuthType authType, List authTypes) { + IntermediateModel model = modelWith(authType); + model.getMetadata().setAuth(authTypes); + return model; + } + private static Map createOperations(List opAuthTypes) { return IntStream.range(0, opAuthTypes.size()) .boxed() diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index 5552d96a771f..738141c6fbb0 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -8,6 +8,8 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.credentials.TokenUtils; +import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -25,6 +27,7 @@ import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; @@ -34,6 +37,7 @@ import software.amazon.awssdk.services.database.endpoints.internal.DatabaseResolveEndpointInterceptor; import software.amazon.awssdk.services.database.internal.DatabaseServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.Validate; /** * Internal base class for {@link DefaultDatabaseClientBuilder} and {@link DefaultDatabaseAsyncClientBuilder}. @@ -56,10 +60,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> c + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -78,6 +86,10 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { IdentityProviders.Builder result = IdentityProviders.builder(); + IdentityProvider tokenIdentityProvider = c.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER); + if (tokenIdentityProvider != null) { + result.putIdentityProvider(tokenIdentityProvider); + } IdentityProvider credentialsIdentityProvider = c.get(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); if (credentialsIdentityProvider != null) { result.putIdentityProvider(credentialsIdentityProvider); @@ -140,6 +152,10 @@ private Map> authSchemes() { return schemes; } + private IdentityProvider defaultTokenProvider() { + return DefaultAwsTokenProvider.create(); + } + @Override protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List internalPlugins = internalPlugins(config); @@ -186,5 +202,7 @@ private List internalPlugins(SdkClientConfiguration config) { } protected static void validateClientOptions(SdkClientConfiguration c) { + Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java index 4d892e050a7d..42082408dd47 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java @@ -6,7 +6,10 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.signer.Aws4Signer; +import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -22,6 +25,7 @@ import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointProvider; @@ -50,9 +54,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> c + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); } @Override @@ -70,6 +79,10 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { IdentityProviders.Builder result = IdentityProviders.builder(); + IdentityProvider tokenIdentityProvider = c.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER); + if (tokenIdentityProvider != null) { + result.putIdentityProvider(tokenIdentityProvider); + } IdentityProvider credentialsIdentityProvider = c.get(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); if (credentialsIdentityProvider != null) { result.putIdentityProvider(credentialsIdentityProvider); @@ -109,6 +122,14 @@ private DatabaseEndpointProvider defaultEndpointProvider() { return DatabaseEndpointProvider.defaultProvider(); } + private IdentityProvider defaultTokenProvider() { + return DefaultAwsTokenProvider.create(); + } + + private Signer defaultTokenSigner() { + return BearerTokenSigner.create(); + } + @Override protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List internalPlugins = internalPlugins(config); @@ -157,5 +178,9 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), + "The 'tokenProvider' must be configured in the client builder."); } } From e834b54cad9abf98d215f4c2ac300a33819eb215 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 9 May 2025 07:19:30 -0700 Subject: [PATCH 18/53] Testing and cleanup --- .../config/customization/CustomizationConfig.java | 2 +- .../poet/builder/BaseClientBuilderClass.java | 2 +- .../AwsRequestOverrideConfigurationTest.java | 13 +++++++++++++ .../http/auth/spi/scheme/AuthSchemeProvider.java | 1 + .../core/client/config/SdkAdvancedClientOption.java | 5 ----- .../services/bearerauth/ClientBuilderTest.java | 3 +++ 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java index 6cc3ac5b7212..88435b2650c7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java @@ -351,7 +351,7 @@ public class CustomizationConfig { private boolean enableFastUnmarshaller; /** - * A boolean flag to indicate if bearer token sourced from the environment support should be added to the + * A boolean flag to indicate if support for configuring a bearer token sourced from the environment should be added to the * generated service. */ private boolean enableEnvironmentBearerToken = false; diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 0df13bcafad7..7e730fef0345 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -348,7 +348,7 @@ private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { envTokenMetricInterceptor()) .addStatement("c.option($T.EXECUTION_INTERCEPTORS, $T.mergeLists(interceptors, envTokenMetricInterceptors))", SdkClientOption.class, CollectionUtils.class) - .endControlFlow(");") + .endControlFlow(")") .endControlFlow(); } 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 ef009f8242f4..b751535e8e7c 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 @@ -22,8 +22,10 @@ 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.token.credentials.StaticTokenProvider; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; +import software.amazon.awssdk.identity.spi.TokenIdentity; public class AwsRequestOverrideConfigurationTest { @@ -44,6 +46,17 @@ public void testCredentialsProviderWorksWithBothOldAndNewInterfaceTypes() { assertCredentialsEqual(configuration2.credentialsProvider().get(), configuration1.credentialsIdentityProvider().get()); } + @Test + public void testTokenIdentityProvider() { + IdentityProvider tokenIdentityProvider = StaticTokenProvider.create(() -> "test-token"); + + AwsRequestOverrideConfiguration configuration1 = AwsRequestOverrideConfiguration + .builder().tokenIdentityProvider(tokenIdentityProvider).build(); + + assertThat(configuration1.tokenIdentityProvider().get().resolveIdentity().join().token()) + .isEqualTo(tokenIdentityProvider.resolveIdentity().join().token()); + } + private void assertCredentialsEqual(AwsCredentialsProvider credentialsProvider, IdentityProvider identityProvider) { AwsCredentials creds1 = credentialsProvider.resolveCredentials(); diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java index d08bdbe520c1..bb194ba42645 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java @@ -23,4 +23,5 @@ */ @SdkPublicApi public interface AuthSchemeProvider { + } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java index a9157995418a..8528c36852ab 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkAdvancedClientOption.java @@ -55,11 +55,6 @@ public class SdkAdvancedClientOption extends ClientOption { */ public static final SdkAdvancedClientOption TOKEN_SIGNER = new SdkAdvancedClientOption<>(Signer.class); - /** - * Set when a token provider is configured explicitly in code by a customer. - */ - public static final SdkAdvancedClientOption TOKEN_PROVIDER_CONFIGURED_EXPLICITLY = - new SdkAdvancedClientOption<>(Boolean.class); /** * SDK uses endpoint trait and hostPrefix trait specified in service model to modify * the endpoint host that the API request is sent to. diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/bearerauth/ClientBuilderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/bearerauth/ClientBuilderTest.java index e9ff4da41fa1..371d089dea2b 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/bearerauth/ClientBuilderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/bearerauth/ClientBuilderTest.java @@ -57,6 +57,9 @@ public void syncClient_customTokenIdentityProviderSet_presentInFinalConfig() { assertThat(config.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER)) .isSameAs(mockProvider); + + assertThat(builder.buildClient().serviceClientConfiguration().tokenProvider()) + .isSameAs(mockProvider); } @Test From f31aa2a553e5a263200887cd1b5398c0d0ed62ba Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Mon, 19 May 2025 12:46:47 -0700 Subject: [PATCH 19/53] Adding test coverage --- .../PreferredAuthSchemeProviderSpec.java | 24 +- .../poet/builder/BaseClientBuilderClass.java | 8 + ...test-bearer-auth-client-builder-class.java | 52 +++-- .../sra/test-client-builder-class.java | 116 ++++----- ...-client-builder-endpoints-auth-params.java | 72 +++--- ...lient-builder-internal-defaults-class.java | 44 ++-- ...-composed-sync-default-client-builder.java | 72 +++--- ...ulti-auth-sigv4a-client-builder-class.java | 6 + ...test-no-auth-ops-client-builder-class.java | 48 ++-- ...-no-auth-service-client-builder-class.java | 48 ++-- .../sra/test-query-client-builder-class.java | 70 +++--- .../auth/AuthSchemePreferenceProvider.java | 122 ++++++++++ .../awssdk/profiles/ProfileProperty.java | 2 + .../amazon/awssdk/core/SdkSystemSetting.java | 9 +- .../VersionedRecordExtensionTest.java | 2 +- .../multiauth/service-2.json | 25 +- .../PreferredAuthSchemeProviderTest.java | 61 ++++- .../AuthSchemePreferenceProviderTest.java | 221 ++++++++++++++++++ .../MultiAuthSigningPropertiesTest.java | 2 + 19 files changed, 745 insertions(+), 259 deletions(-) create mode 100644 core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java create mode 100644 test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java index 2b43bc1691ef..a81efc30f705 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpec.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.lang.model.element.Modifier; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; @@ -65,7 +66,8 @@ private MethodSpec constructor() { .addParameter(authSchemeSpecUtils.providerInterfaceName(), "delegate") .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") .addStatement("this.delegate = delegate") - .addStatement("this.authSchemePreference = authSchemePreference != null ? authSchemePreference : $T.emptyList()", + .addStatement("this.authSchemePreference = authSchemePreference != null ? authSchemePreference " + + ": $T.emptyList()", Collections.class) .build(); } @@ -80,22 +82,28 @@ private MethodSpec resolveAuthSchemeMethod() { b.addStatement("$T candidateAuthSchemes = delegate.resolveAuthScheme(params)", authSchemeSpecUtils.resolverReturnType()); b.beginControlFlow("if ($T.isNullOrEmpty(authSchemePreference))", CollectionUtils.class) - .addStatement("return candidateAuthSchemes") - .endControlFlow(); + .addStatement("return candidateAuthSchemes") + .endControlFlow(); b.addStatement("$T authSchemes = new $T<>()", authSchemeSpecUtils.resolverReturnType(), ArrayList.class); - b.beginControlFlow("authSchemePreference.forEach( preferredSchemeId -> ") - .addStatement("candidateAuthSchemes.stream().filter(a -> a.schemeId().equals(preferredSchemeId)).findFirst()" - + ".ifPresent(a -> authSchemes.add(a))") - .endControlFlow(")"); + + b.beginControlFlow("authSchemePreference.forEach(preferredSchemeId -> "); + + b.beginControlFlow("candidateAuthSchemes.stream().filter(candidate -> "); + b.addStatement("String candidateSchemeName = candidate.schemeId().contains(\"#\") ? " + + "candidate.schemeId().split(\"#\")[1] : candidate.schemeId()"); + b.addStatement("return candidateSchemeName.equals(preferredSchemeId)"); + b.endControlFlow(").findFirst().ifPresent(authSchemes::add)"); + b.endControlFlow(")"); b.beginControlFlow("candidateAuthSchemes.forEach(candidate -> ") .beginControlFlow("if (!authSchemes.contains(candidate))") .addStatement("authSchemes.add(candidate)") .endControlFlow() - .endControlFlow(")"); + .endControlFlow(")"); b.addStatement("return authSchemes"); return b.build(); } + } \ No newline at end of file diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 1ca3f9b38ba5..7b1e0c200664 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -46,6 +46,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.codegen.internal.Utils; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; @@ -832,6 +833,13 @@ private MethodSpec defaultAuthSchemeProviderMethod() { return MethodSpec.methodBuilder("defaultAuthSchemeProvider") .addModifiers(PRIVATE) .returns(authSchemeSpecUtils.providerInterfaceName()) + .addStatement("$T authSchemePreferenceProvider = " + + "$T.builder().build()", AuthSchemePreferenceProvider.class, AuthSchemePreferenceProvider.class) + .addStatement("List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference()") + .beginControlFlow("if(preferences != null && !preferences.isEmpty())") + .addStatement("return $T.builder().withPreferredAuthSchemes(preferences).build()", + authSchemeSpecUtils.providerInterfaceName()) + .endControlFlow() .addStatement("return $T.defaultProvider()", authSchemeSpecUtils.providerInterfaceName()) .build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index 92a36dc95428..316f764b1013 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -13,6 +13,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -59,13 +60,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -76,7 +77,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -92,21 +93,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -125,6 +126,11 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return JsonAuthSchemeProvider.defaultProvider(); } @@ -194,6 +200,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index 4539aed74c0b..8339b1be808e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -15,6 +15,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin1; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin2; @@ -70,14 +71,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -88,82 +89,82 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); ServiceConfiguration.Builder serviceConfigBuilder = ((ServiceConfiguration) config - .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder - .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config - .option(SdkClientOption.PROFILE_NAME)); + .option(SdkClientOption.PROFILE_NAME)); if (serviceConfigBuilder.dualstackEnabled() != null) { Validate.validState( - config.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED) == null, - "Dualstack has been configured on both ServiceConfiguration and the client/global level. Please limit dualstack configuration to one location."); + config.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED) == null, + "Dualstack has been configured on both ServiceConfiguration and the client/global level. Please limit dualstack configuration to one location."); } else { serviceConfigBuilder.dualstackEnabled(config.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)); } if (serviceConfigBuilder.fipsModeEnabled() != null) { Validate.validState( - config.option(AwsClientOption.FIPS_ENDPOINT_ENABLED) == null, - "Fips has been configured on both ServiceConfiguration and the client/global level. Please limit fips configuration to one location."); + config.option(AwsClientOption.FIPS_ENDPOINT_ENABLED) == null, + "Fips has been configured on both ServiceConfiguration and the client/global level. Please limit fips configuration to one location."); } else { serviceConfigBuilder.fipsModeEnabled(config.option(AwsClientOption.FIPS_ENDPOINT_ENABLED)); } if (serviceConfigBuilder.useArnRegionEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.USE_ARN_REGION) == null, - "UseArnRegion has been configured on both ServiceConfiguration and the client/global level. Please limit UseArnRegion configuration to one location."); + clientContextParams.get(JsonClientContextParams.USE_ARN_REGION) == null, + "UseArnRegion has been configured on both ServiceConfiguration and the client/global level. Please limit UseArnRegion configuration to one location."); } else { serviceConfigBuilder.useArnRegionEnabled(clientContextParams.get(JsonClientContextParams.USE_ARN_REGION)); } if (serviceConfigBuilder.multiRegionEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS) == null, - "DisableMultiRegionAccessPoints has been configured on both ServiceConfiguration and the client/global level. Please limit DisableMultiRegionAccessPoints configuration to one location."); + clientContextParams.get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS) == null, + "DisableMultiRegionAccessPoints has been configured on both ServiceConfiguration and the client/global level. Please limit DisableMultiRegionAccessPoints configuration to one location."); } else if (clientContextParams.get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS) != null) { serviceConfigBuilder.multiRegionEnabled(!clientContextParams - .get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS)); + .get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS)); } if (serviceConfigBuilder.pathStyleAccessEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.FORCE_PATH_STYLE) == null, - "ForcePathStyle has been configured on both ServiceConfiguration and the client/global level. Please limit ForcePathStyle configuration to one location."); + clientContextParams.get(JsonClientContextParams.FORCE_PATH_STYLE) == null, + "ForcePathStyle has been configured on both ServiceConfiguration and the client/global level. Please limit ForcePathStyle configuration to one location."); } else { serviceConfigBuilder.pathStyleAccessEnabled(clientContextParams.get(JsonClientContextParams.FORCE_PATH_STYLE)); } if (serviceConfigBuilder.accelerateModeEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.ACCELERATE) == null, - "Accelerate has been configured on both ServiceConfiguration and the client/global level. Please limit Accelerate configuration to one location."); + clientContextParams.get(JsonClientContextParams.ACCELERATE) == null, + "Accelerate has been configured on both ServiceConfiguration and the client/global level. Please limit Accelerate configuration to one location."); } else { serviceConfigBuilder.accelerateModeEnabled(clientContextParams.get(JsonClientContextParams.ACCELERATE)); } Boolean checksumValidationEnabled = serviceConfigBuilder.checksumValidationEnabled(); if (checksumValidationEnabled != null) { Validate.validState( - config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION) == null, - "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); + config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION) == null, + "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); Validate.validState( - config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION) == null, - "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); + config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION) == null, + "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); if (checksumValidationEnabled) { config = config.toBuilder() - .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_SUPPORTED) - .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_SUPPORTED).build(); + .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_SUPPORTED) + .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_SUPPORTED).build(); } else { config = config.toBuilder() - .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_REQUIRED) - .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_REQUIRED).build(); + .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_REQUIRED) + .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_REQUIRED).build(); } } ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); clientContextParams.put(JsonClientContextParams.USE_ARN_REGION, finalServiceConfig.useArnRegionEnabled()); clientContextParams.put(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS, - !finalServiceConfig.multiRegionEnabled()); + !finalServiceConfig.multiRegionEnabled()); clientContextParams.put(JsonClientContextParams.FORCE_PATH_STYLE, finalServiceConfig.pathStyleAccessEnabled()); clientContextParams.put(JsonClientContextParams.ACCELERATE, finalServiceConfig.accelerateModeEnabled()); SdkClientConfiguration.Builder builder = config.toBuilder(); @@ -188,21 +189,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon } builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); builder.lazyOption(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, c -> resolveResponseChecksumValidation(clientConfig)); @@ -224,6 +225,11 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return JsonAuthSchemeProvider.defaultProvider(); } @@ -325,9 +331,9 @@ private RequestChecksumCalculation resolveRequestChecksumCalculation(SdkClientCo RequestChecksumCalculation configuredChecksumCalculation = config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION); if (configuredChecksumCalculation == null) { configuredChecksumCalculation = RequestChecksumCalculationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); } return configuredChecksumCalculation; } @@ -336,15 +342,15 @@ private ResponseChecksumValidation resolveResponseChecksumValidation(SdkClientCo ResponseChecksumValidation configuredChecksumValidation = config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION); if (configuredChecksumValidation == null) { configuredChecksumValidation = ResponseChecksumValidationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); } return configuredChecksumValidation; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index 80511b9556ce..367eb3f56dbd 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -15,6 +15,7 @@ import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; @@ -69,13 +70,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -86,7 +87,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new QueryRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -108,21 +109,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, clientContextParams.build()); builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") - .serviceProfileProperty("query_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); builder.lazyOption(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, c -> resolveResponseChecksumValidation(clientConfig)); @@ -144,6 +145,11 @@ public B authSchemeProvider(QueryAuthSchemeProvider authSchemeProvider) { } private QueryAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return QueryAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return QueryAuthSchemeProvider.defaultProvider(); } @@ -244,9 +250,9 @@ private AccountIdEndpointMode resolveAccountIdEndpointMode(SdkClientConfiguratio AccountIdEndpointMode configuredMode = config.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE); if (configuredMode == null) { configuredMode = AccountIdEndpointModeResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) - .resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) + .resolve(); } return configuredMode; } @@ -255,9 +261,9 @@ private RequestChecksumCalculation resolveRequestChecksumCalculation(SdkClientCo RequestChecksumCalculation configuredChecksumCalculation = config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION); if (configuredChecksumCalculation == null) { configuredChecksumCalculation = RequestChecksumCalculationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); } return configuredChecksumCalculation; } @@ -266,21 +272,21 @@ private ResponseChecksumValidation resolveResponseChecksumValidation(SdkClientCo ResponseChecksumValidation configuredChecksumValidation = config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION); if (configuredChecksumValidation == null) { configuredChecksumValidation = ResponseChecksumValidationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); } return configuredChecksumValidation; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } public B sigv4aSigningRegionSet(RegionSet sigv4aSigningRegionSet) { clientConfiguration.option(AwsClientOption.AWS_SIGV4A_SIGNING_REGION_SET, - sigv4aSigningRegionSet == null ? Collections.emptySet() : sigv4aSigningRegionSet.asSet()); + sigv4aSigningRegionSet == null ? Collections.emptySet() : sigv4aSigningRegionSet.asSet()); return thisBuilder(); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index 21854bd71571..2fdda8def833 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -11,6 +11,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -55,9 +56,9 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -76,7 +77,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -92,21 +93,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -125,6 +126,11 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index c441fcd575e4..766f5b942bcb 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -13,6 +13,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; @@ -65,14 +66,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -83,17 +84,17 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); ServiceConfiguration.Builder serviceConfigBuilder = ((ServiceConfiguration) config - .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder - .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config - .option(SdkClientOption.PROFILE_NAME)); + .option(SdkClientOption.PROFILE_NAME)); ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { @@ -111,21 +112,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); builder.lazyOption(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, c -> resolveResponseChecksumValidation(clientConfig)); @@ -147,6 +148,11 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return JsonAuthSchemeProvider.defaultProvider(); } @@ -244,9 +250,9 @@ private RequestChecksumCalculation resolveRequestChecksumCalculation(SdkClientCo RequestChecksumCalculation configuredChecksumCalculation = config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION); if (configuredChecksumCalculation == null) { configuredChecksumCalculation = RequestChecksumCalculationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); } return configuredChecksumCalculation; } @@ -255,15 +261,15 @@ private ResponseChecksumValidation resolveResponseChecksumValidation(SdkClientCo ResponseChecksumValidation configuredChecksumValidation = config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION); if (configuredChecksumValidation == null) { configuredChecksumValidation = ResponseChecksumValidationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); } return configuredChecksumValidation; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java index 51c803fcad77..98efb07e4281 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java @@ -11,6 +11,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -120,6 +121,11 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index 5552d96a771f..b62f7273ebc9 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -11,6 +11,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -41,7 +42,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { private final Map> additionalAuthSchemes = new HashMap<>(); @Override @@ -57,9 +58,9 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -70,7 +71,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -86,21 +87,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -119,6 +120,11 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return DatabaseAuthSchemeProvider.defaultProvider(); } @@ -150,7 +156,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 9f49074aa7d7..b92b497a00f8 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -11,6 +11,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; @@ -38,7 +39,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { private final Map> additionalAuthSchemes = new HashMap<>(); @Override @@ -54,9 +55,9 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); } @Override @@ -67,7 +68,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -79,21 +80,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); return builder.build(); } @@ -112,6 +113,11 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return DatabaseAuthSchemeProvider.defaultProvider(); } @@ -139,7 +145,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index 724eb838439d..e485412a3e13 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -15,6 +15,7 @@ import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; @@ -67,13 +68,13 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, + .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); } @Override @@ -84,7 +85,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new QueryRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/query/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -106,21 +107,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.CLIENT_CONTEXT_PARAMS, clientContextParams.build()); builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") - .serviceProfileProperty("query_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); builder.lazyOption(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, c -> resolveResponseChecksumValidation(clientConfig)); @@ -142,6 +143,11 @@ public B authSchemeProvider(QueryAuthSchemeProvider authSchemeProvider) { } private QueryAuthSchemeProvider defaultAuthSchemeProvider() { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder().build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return QueryAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } return QueryAuthSchemeProvider.defaultProvider(); } @@ -240,9 +246,9 @@ private AccountIdEndpointMode resolveAccountIdEndpointMode(SdkClientConfiguratio AccountIdEndpointMode configuredMode = config.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE); if (configuredMode == null) { configuredMode = AccountIdEndpointModeResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) - .resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).defaultMode(AccountIdEndpointMode.PREFERRED) + .resolve(); } return configuredMode; } @@ -251,9 +257,9 @@ private RequestChecksumCalculation resolveRequestChecksumCalculation(SdkClientCo RequestChecksumCalculation configuredChecksumCalculation = config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION); if (configuredChecksumCalculation == null) { configuredChecksumCalculation = RequestChecksumCalculationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); } return configuredChecksumCalculation; } @@ -262,15 +268,15 @@ private ResponseChecksumValidation resolveResponseChecksumValidation(SdkClientCo ResponseChecksumValidation configuredChecksumValidation = config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION); if (configuredChecksumValidation == null) { configuredChecksumValidation = ResponseChecksumValidationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); } return configuredChecksumValidation; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java new file mode 100644 index 000000000000..171a9f33ca18 --- /dev/null +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java @@ -0,0 +1,122 @@ +/* + * 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.internal.auth; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.profiles.Profile; +import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.profiles.ProfileFileSystemSetting; +import software.amazon.awssdk.profiles.ProfileProperty; +import software.amazon.awssdk.utils.Validate; + +@SdkProtectedApi +public class AuthSchemePreferenceProvider { + private static final String AUTH_SCHEME_PREFERENCE_SYSTEM_PROPERTY = "aws.authSchemePreference"; + private final Supplier profileFile; + private final String profileName; + + private AuthSchemePreferenceProvider(Builder builder) { + this.profileFile = Validate.paramNotNull(builder.profileFile, "profileFile"); + this.profileName = builder.profileName; + } + + public static Builder builder() { + return new Builder(); + } + + public List resolveAuthSchemePreference() { + List jvmPrefList = fromJvmProperty(); + if (jvmPrefList != null && !jvmPrefList.isEmpty()) { + return jvmPrefList; + } + + List envVarPrefList = fromEnvVariable(); + if (envVarPrefList != null && !envVarPrefList.isEmpty()) { + return envVarPrefList; + } + + List profileFilePrefList = fromProfileFile(); + if (profileFilePrefList != null && !profileFilePrefList.isEmpty()) { + return profileFilePrefList; + } + + return Collections.emptyList(); + } + + private List fromEnvVariable() { + Optional value = SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.getStringValue(); + if (value.isPresent()) { + return parseAuthSchemeList(value.get()); + } + return Collections.emptyList(); + } + + private List fromJvmProperty() { + String value = System.getProperty(AUTH_SCHEME_PREFERENCE_SYSTEM_PROPERTY); + return parseAuthSchemeList(value); + } + + private List fromProfileFile() { + ProfileFile profileFile = this.profileFile.get(); + + Optional profile = profileFile.profile(ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow()); + + String unformattedAuthSchemePreferenceList = + profile + .flatMap(p -> p.property(ProfileProperty.AUTH_SCHEME_PREFERENCE)) + .orElse(null); + + return unformattedAuthSchemePreferenceList != null + ? parseAuthSchemeList(unformattedAuthSchemePreferenceList) + : Collections.emptyList(); + } + + public static final class Builder { + private Supplier profileFile = ProfileFile::defaultProfileFile; + private String profileName; + + public AuthSchemePreferenceProvider.Builder profileFile(Supplier profileFile) { + this.profileFile = profileFile; + return this; + } + + public AuthSchemePreferenceProvider.Builder profileName(String profileName) { + this.profileName = profileName; + return this; + } + + public AuthSchemePreferenceProvider build() { + return new AuthSchemePreferenceProvider(this); + } + } + + private static List parseAuthSchemeList(String unformattedList) { + if (unformattedList == null) { + return Collections.emptyList(); + } + + unformattedList = unformattedList.replaceAll("\\s+",""); + String[] splitByTabs = unformattedList.split("\t"); + String finalFormat = String.join("", splitByTabs); + return Arrays.asList(finalFormat.split(",")); + } +} diff --git a/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileProperty.java b/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileProperty.java index 434e27b3b6f2..cd97c6047a55 100644 --- a/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileProperty.java +++ b/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileProperty.java @@ -151,6 +151,8 @@ public final class ProfileProperty { public static final String USE_DUALSTACK_ENDPOINT = "use_dualstack_endpoint"; + public static final String AUTH_SCHEME_PREFERENCE = "auth_scheme_preference"; + public static final String USE_FIPS_ENDPOINT = "use_fips_endpoint"; public static final String EC2_METADATA_SERVICE_ENDPOINT_MODE = "ec2_metadata_service_endpoint_mode"; diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java index f55eb73cbc7f..2b37adc5091c 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java @@ -256,7 +256,14 @@ public enum SdkSystemSetting implements SystemSetting { * Configure the SIGV4A signing region set. * This is a non-empty, comma-delimited list of AWS region names used during signing. */ - AWS_SIGV4A_SIGNING_REGION_SET("aws.sigv4a.signing.region.set", null) + AWS_SIGV4A_SIGNING_REGION_SET("aws.sigv4a.signing.region.set", null), + + + /** + * Configure the preferred auth scheme to use. + * This is a comma-delimited list of AWS auth scheme names used during signing. + */ + AWS_AUTH_SCHEME_PREFERENCE("AWS_AUTH_SCHEME_PREFERENCE", null) ; private final String systemProperty; diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtensionTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtensionTest.java index 4f61db7487e9..b7cbb4eb428a 100644 --- a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtensionTest.java +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtensionTest.java @@ -166,7 +166,7 @@ public void beforeWrite_returnsNoOpModification_ifVersionAttributeNotDefined() { } @Test(expected = IllegalArgumentException.class) - public void beforeWrite_throwsIllegalArgumentException_ifVersionAttributeIsWrongType() { + public void beforeWrite_throwsIllegalArgumentException_ifVersioPnAttributeIsWrongType() { FakeItem fakeItem = createUniqueFakeItem(); Map fakeItemWIthBadVersion = new HashMap<>(FakeItem.getTableSchema().itemToMap(fakeItem, true)); diff --git a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/multiauth/service-2.json b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/multiauth/service-2.json index b5047e2734fc..6fd1f03e1fd1 100644 --- a/test/codegen-generated-classes-test/src/main/resources/codegen-resources/multiauth/service-2.json +++ b/test/codegen-generated-classes-test/src/main/resources/codegen-resources/multiauth/service-2.json @@ -13,7 +13,7 @@ "timestampFormat":"unixTimestamp", "uid":"restjson-2016-03-11" }, - "operations":{ + "operations": { "multiAuthWithOnlySigv4a":{ "name":"multiAuthWithOnlySigv4a", "http":{ @@ -26,6 +26,18 @@ "ApiType":{"value":"NoEndpointSigningProperties"} } }, + "multiAuthWithOnlySigv4":{ + "name":"multiAuthWithOnlySigv4", + "http":{ + "method":"POST", + "requestUri":"/2016-03-11/multiAuthWithOnlySigv4" + }, + "input":{"shape":"SampleRequest"}, + "auth": ["aws.auth#sigv4"], + "staticContextParams":{ + "ApiType":{"value":"NoEndpointSigningProperties"} + } + }, "multiAuthWithOnlySigv4aAndSigv4":{ "name":"multiAuthWithOnlySigv4aAndSigv4", "http":{ @@ -72,6 +84,17 @@ "value": "onlySigv4a" } } + }, + "multiAuthWithoutAuthScheme":{ + "name":"multiAuthWithoutAuthScheme", + "http":{ + "method":"POST", + "requestUri":"/2016-03-11/multiAuthWithoutAuthScheme" + }, + "input":{"shape":"SampleRequest"}, + "staticContextParams":{ + "ApiType":{"value":"NoEndpointSigningProperties"} + } } }, "shapes": { diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java index 75154d2d9d73..06f0ac8776d3 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java @@ -30,13 +30,17 @@ public class PreferredAuthSchemeProviderTest { + private static final String OPERATION_SIGV4_ONLY = "multiAuthWithOnlySigv4a"; private static final String OPERATION_SIGV4A_ONLY = "multiAuthWithOnlySigv4a"; private static final String OPERATION_SIGV4A_AND_SIGV4 = "multiAuthWithOnlySigv4aAndSigv4"; + private static final String OPERATION_NOAUTH = "multiAuthNoAuth"; - private static final String SIGV4 = "aws.auth#sigv4"; - private static final String SIGV4A = "aws.auth#sigv4a"; - private static final String BEARER = "aws.auth#bearer"; - private static final String ANONYMOUS = "aws.auth#noauth"; + private static final String SIGV4 = "sigv4"; + private static final String PREFIXED_SIGV4 = "aws.auth#sigv4"; + private static final String PREFIXED_SIGV4A = "aws.auth#sigv4a"; + private static final String SIGV4A = "sigv4a"; + private static final String BEARER = "bearer"; + private static final String ANONYMOUS = "noauth"; @ParameterizedTest(name = "{3}") @MethodSource("authSchemeTestCases") @@ -63,42 +67,77 @@ static Stream authSchemeTestCases() { Arguments.of( Arrays.asList(BEARER, ANONYMOUS), OPERATION_SIGV4A_AND_SIGV4, - SIGV4A, + PREFIXED_SIGV4A, "Unsupported auth schemes only" ), + Arguments.of( + Arrays.asList(SIGV4, SIGV4A), + OPERATION_NOAUTH, + PREFIXED_SIGV4, + "Operation with no auth scheme should default to Sigv4" + ), + + Arguments.of( + Arrays.asList(SIGV4A), + OPERATION_NOAUTH, + PREFIXED_SIGV4A, + "" + ), + + Arguments.of( + Arrays.asList(SIGV4A, SIGV4), + OPERATION_NOAUTH, + PREFIXED_SIGV4A, + "" + ), + + Arguments.of( + Arrays.asList(SIGV4A, SIGV4), + OPERATION_NOAUTH, + PREFIXED_SIGV4A, + "" + ), + Arguments.of( Arrays.asList(BEARER, SIGV4, ANONYMOUS), OPERATION_SIGV4A_AND_SIGV4, - SIGV4, + PREFIXED_SIGV4, "Mix of supported and unsupported schemes" ), Arguments.of( Arrays.asList(SIGV4, SIGV4A), OPERATION_SIGV4A_AND_SIGV4, - SIGV4, + PREFIXED_SIGV4, "All supported schemes in reverse order" ), + Arguments.of( + Arrays.asList(SIGV4A), + OPERATION_SIGV4_ONLY, + PREFIXED_SIGV4, + "Operation with only sigv4 supported scheme" + ), + Arguments.of( Arrays.asList(SIGV4, SIGV4A), OPERATION_SIGV4A_ONLY, - SIGV4A, - "Operation with only one supported scheme" + PREFIXED_SIGV4A, + "Operation with only sigv4a supported scheme" ), Arguments.of( Collections.emptyList(), OPERATION_SIGV4A_AND_SIGV4, - SIGV4A, + PREFIXED_SIGV4A, "Empty preference list" ), Arguments.of( Arrays.asList(SIGV4A, SIGV4, BEARER), OPERATION_SIGV4A_AND_SIGV4, - SIGV4A, + PREFIXED_SIGV4A, "First preference is supported" ) ); diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java new file mode 100644 index 000000000000..46c74df83a7b --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java @@ -0,0 +1,221 @@ +/* + * 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.services.multiauth; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.core.SdkSystemSetting; +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.SdkInternalExecutionAttribute; +import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.profiles.ProfileProperty; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.multiauth.auth.scheme.MultiauthAuthSchemeProvider; +import software.amazon.awssdk.services.multiauth.model.MultiAuthWithOnlySigv4AAndSigv4Request; +import software.amazon.awssdk.testutils.EnvironmentVariableHelper; +import software.amazon.awssdk.utils.StringInputStream; + +public class AuthSchemePreferenceProviderTest { + private final EnvironmentVariableHelper helper = new EnvironmentVariableHelper(); + + @AfterEach + void tearDown() { + System.clearProperty(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.property()); + helper.reset(); + } + + @ParameterizedTest + @MethodSource("schemeParsingCases") + void parsesAuthSchemeCorrectly(String authSchemePreference, List actual) { + System.setProperty(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.property(), authSchemePreference); + AuthSchemePreferenceProvider provider = AuthSchemePreferenceProvider.builder().build(); + List pref = provider.resolveAuthSchemePreference(); + assertThat(pref).isEqualTo(actual); + } + + static Stream schemeParsingCases() { + return Stream.of( + Arguments.of("scheme1, scheme2 , \tscheme3 \t", Arrays.asList("scheme1", "scheme2", "scheme3")), + Arguments.of("scheme1, scheme2 \t scheme3 scheme4", Arrays.asList("scheme1", "scheme2scheme3scheme4")), + Arguments.of("sigv4, sig v 4 a, bearer", Arrays.asList("sigv4", "sigv4a", "bearer")), + Arguments.of("", Collections.singletonList("")) + + ); + } + + @ParameterizedTest + @MethodSource("testCases") + void resolvesAuthSchemePreference(TestCase testCase) { + try { + MultiauthClientBuilder builder = + MultiauthClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(AnonymousCredentialsProvider.create()); + + if (testCase.clientSetting != null) { + builder.authSchemeProvider(MultiauthAuthSchemeProvider.builder().withPreferredAuthSchemes(testCase.clientSetting).build()); + } + + if (testCase.systemPropSetting != null) { + System.setProperty(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.property(), testCase.systemPropSetting); + } + + if (testCase.envVarSetting != null) { + helper.set(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.environmentVariable(), testCase.envVarSetting); + } + + ProfileFile.Builder profileFile = ProfileFile.builder().type(ProfileFile.Type.CONFIGURATION); + + if (testCase.profileSetting != null) { + profileFile.content(new StringInputStream("[default]\n" + + ProfileProperty.AUTH_SCHEME_PREFERENCE + " = " + testCase.profileSetting)); + } else { + profileFile.content(new StringInputStream("")); + } + + AutSchemeCapturingInterceptor interceptor = new AutSchemeCapturingInterceptor(); + + builder.overrideConfiguration(c -> c.defaultProfileFile(profileFile.build()) + .defaultProfileName("default") + .addExecutionInterceptor(interceptor)); + + MultiauthClient client = builder.build(); + + try { + client.multiAuthWithOnlySigv4aAndSigv4(MultiAuthWithOnlySigv4AAndSigv4Request.builder().build()); + } catch (AutSchemeCapturingInterceptor.CaptureException e) { + // expected + } + + assertThat(interceptor.authScheme()).isEqualTo(testCase.expectedValues.get(0)); + } finally { + tearDown(); + } + } + + static Stream testCases() { + return Stream.of( + // Arguments.of(new TestCase( + // null, + // null, + // null, + // Arrays.asList("sigv4", "noauth"), + // Arrays.asList("sigv4", "noauth"), + // "Client config is used when set")), + // + // Arguments.of(new TestCase( + // null, + // null, + // "sigv4,sigv4a,bearer", + // null, + // Arrays.asList("sigv4", "sigv4a", "bearer"), + // "System property value is used")), + + Arguments.of(new TestCase( + null, + "sigv4a,sigv4,bearer", + null, + null, + Arrays.asList("sigv4a", "sigv4", "bearer"), + "Environment variable is used when other properties is null")) + + // Arguments.of(new TestCase( + // "bearer,sigv4,sigv4a", + // null, + // null, + // null, + // Arrays.asList("bearer", "sigv4", "sigv4a"), + // "Profile setting is used when others are null")), + // + // Arguments.of(new TestCase( + // "bearer,sigv4,sigv4a", + // "sigv4a,sigv4,bearer", + // "sigv4,sigv4a,bearer", + // null, + // Arrays.asList("sigv4", "sigv4a", "bearer"), + // "JVM system property has precedence over env var and profile")), + // + // Arguments.of(new TestCase( + // "bearer,sigv4,sigv4a", + // "sigv4a,sigv4,bearer", + // "sigv4,sigv4a,bearer", + // Arrays.asList("noauth", "sigv4a", "bearer"), + // Arrays.asList("noauth", "sigv4a", "bearer"), + // "Client config has highest precedence")) + ); + } + + public static class TestCase { + private final String profileSetting; + private final String envVarSetting; + private final String systemPropSetting; + private final List clientSetting; + private final List expectedValues; + private final String caseName; + + public TestCase(String profileSetting, String envVarSetting, String systemPropSetting, List clientSetting, + List expectedValues, String caseName) { + this.profileSetting = profileSetting; + this.envVarSetting = envVarSetting; + this.systemPropSetting = systemPropSetting; + this.clientSetting = clientSetting; + this.expectedValues = expectedValues; + + this.caseName = caseName; + } + + @Override + public String toString() { + return caseName; + } + } + + public static class AutSchemeCapturingInterceptor implements ExecutionInterceptor { + private final AtomicReference authScheme = new AtomicReference<>(); + + @Override + public void beforeTransmission(Context.BeforeTransmission context, ExecutionAttributes executionAttributes) { + SelectedAuthScheme scheme = executionAttributes.getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME); + String schemeId = scheme.authSchemeOption().schemeId(); + authScheme.set(schemeId.replace("aws.auth#", "")); + throw new CaptureException(); + } + + + public String authScheme() { + return this.authScheme.get(); + } + + public static class CaptureException extends RuntimeException { + } + } +} + + diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java index 639f5097146b..ebe63f18562f 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.when; import java.util.Arrays; +import java.util.List; import java.util.StringJoiner; import java.util.concurrent.CompletableFuture; import org.assertj.core.api.Assertions; @@ -34,6 +35,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner; From a0094edb3090f3cf858e53482c9a271041480b58 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 08:08:37 -0700 Subject: [PATCH 20/53] Use SdkSystemSetting for both env and system --- .../auth/AuthSchemePreferenceProvider.java | 24 +++++-------------- .../amazon/awssdk/core/SdkSystemSetting.java | 3 +-- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java index 171a9f33ca18..7a9e00a09bdd 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java @@ -24,13 +24,11 @@ import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.profiles.Profile; import software.amazon.awssdk.profiles.ProfileFile; -import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; import software.amazon.awssdk.utils.Validate; @SdkProtectedApi public class AuthSchemePreferenceProvider { - private static final String AUTH_SCHEME_PREFERENCE_SYSTEM_PROPERTY = "aws.authSchemePreference"; private final Supplier profileFile; private final String profileName; @@ -44,14 +42,9 @@ public static Builder builder() { } public List resolveAuthSchemePreference() { - List jvmPrefList = fromJvmProperty(); - if (jvmPrefList != null && !jvmPrefList.isEmpty()) { - return jvmPrefList; - } - - List envVarPrefList = fromEnvVariable(); - if (envVarPrefList != null && !envVarPrefList.isEmpty()) { - return envVarPrefList; + List systemSettingList = fromSystemSetting(); + if (systemSettingList != null && !systemSettingList.isEmpty()) { + return systemSettingList; } List profileFilePrefList = fromProfileFile(); @@ -62,7 +55,7 @@ public List resolveAuthSchemePreference() { return Collections.emptyList(); } - private List fromEnvVariable() { + private List fromSystemSetting() { Optional value = SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.getStringValue(); if (value.isPresent()) { return parseAuthSchemeList(value.get()); @@ -70,15 +63,10 @@ private List fromEnvVariable() { return Collections.emptyList(); } - private List fromJvmProperty() { - String value = System.getProperty(AUTH_SCHEME_PREFERENCE_SYSTEM_PROPERTY); - return parseAuthSchemeList(value); - } - private List fromProfileFile() { ProfileFile profileFile = this.profileFile.get(); - Optional profile = profileFile.profile(ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow()); + Optional profile = profileFile.profile(profileName); String unformattedAuthSchemePreferenceList = profile @@ -114,7 +102,7 @@ private static List parseAuthSchemeList(String unformattedList) { return Collections.emptyList(); } - unformattedList = unformattedList.replaceAll("\\s+",""); + unformattedList = unformattedList.replaceAll("\\s+", ""); String[] splitByTabs = unformattedList.split("\t"); String finalFormat = String.join("", splitByTabs); return Arrays.asList(finalFormat.split(",")); diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java index 2b37adc5091c..65889c2d08fd 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java @@ -263,8 +263,7 @@ public enum SdkSystemSetting implements SystemSetting { * Configure the preferred auth scheme to use. * This is a comma-delimited list of AWS auth scheme names used during signing. */ - AWS_AUTH_SCHEME_PREFERENCE("AWS_AUTH_SCHEME_PREFERENCE", null) - ; + AWS_AUTH_SCHEME_PREFERENCE("aws.authSchemePreference", null); private final String systemProperty; private final String defaultValue; From c4b6fbdb544d28bcc1d005152fd03f057cb84676 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 08:48:47 -0700 Subject: [PATCH 21/53] Add changelog --- .changes/next-release/feature-AWSSDKforJavav2-1932d6a.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/next-release/feature-AWSSDKforJavav2-1932d6a.json diff --git a/.changes/next-release/feature-AWSSDKforJavav2-1932d6a.json b/.changes/next-release/feature-AWSSDKforJavav2-1932d6a.json new file mode 100644 index 000000000000..4500cbe3abac --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-1932d6a.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Adds support for configuring bearer auth using a token sourced from the environment for services with the `enableEnvironmentBearerToken` customization flag." +} From f46a7732787c94bb72ddb8f8be69183e356a03d6 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 09:22:56 -0700 Subject: [PATCH 22/53] Add profiles to service pom --- services/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/pom.xml b/services/pom.xml index 9ec42eaeb927..bf79123843bb 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -509,6 +509,11 @@ retries-spi ${awsjavasdk.version} + + software.amazon.awssdk + profiles + ${awsjavasdk.version} + apache-client software.amazon.awssdk From 48784f55d68e40e1ae2afbfd0cb0d37f413c76d5 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 09:41:21 -0700 Subject: [PATCH 23/53] Minor cleanups --- .../awssdk/awscore/internal/AwsExecutionContextBuilder.java | 2 +- .../src/main/resources/codegen-resources/customization.config | 3 +-- .../src/main/resources/codegen-resources/service-2.json | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) 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 6a6397f95f6f..c6bc03a1d47f 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 @@ -245,7 +245,7 @@ private static IdentityProviders resolveIdentityProviders(SdkRequest originalReq /** * Finalize {@link SdkRequest} by running beforeExecution and modifyRequest interceptors. * - * @param interceptorContext containing the immutable SdkRequest information the interceptor can act on + * @param interceptorContext containing the immutable SdkRequest information the interceptor can act on * @param executionAttributes mutable container of attributes concerning the execution and request * @return the {@link InterceptorContext} returns a context with a new SdkRequest */ diff --git a/services/bedrockruntime/src/main/resources/codegen-resources/customization.config b/services/bedrockruntime/src/main/resources/codegen-resources/customization.config index 42aa381cf2ea..e824e95e8fbd 100644 --- a/services/bedrockruntime/src/main/resources/codegen-resources/customization.config +++ b/services/bedrockruntime/src/main/resources/codegen-resources/customization.config @@ -1,4 +1,3 @@ { - "enableGenerateCompiledEndpointRules": true, - "enableEnvironmentBearerToken": true + "enableGenerateCompiledEndpointRules": true } diff --git a/services/bedrockruntime/src/main/resources/codegen-resources/service-2.json b/services/bedrockruntime/src/main/resources/codegen-resources/service-2.json index 85754e48986a..d38e1adb49af 100644 --- a/services/bedrockruntime/src/main/resources/codegen-resources/service-2.json +++ b/services/bedrockruntime/src/main/resources/codegen-resources/service-2.json @@ -2,7 +2,7 @@ "version":"2.0", "metadata":{ "apiVersion":"2023-09-30", - "auth":["aws.auth#sigv4", "smithy.http#bearer"], + "auth":["aws.auth#sigv4"], "endpointPrefix":"bedrock-runtime", "protocol":"rest-json", "protocolSettings":{"h2":"optional"}, From 6ae2294add68885d919dffc75fe02832667a9993 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 10:21:03 -0700 Subject: [PATCH 24/53] Fix test --- .../PreferredAuthSchemeProviderTest.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java index 06f0ac8776d3..ad53ba5041a2 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java @@ -30,7 +30,7 @@ public class PreferredAuthSchemeProviderTest { - private static final String OPERATION_SIGV4_ONLY = "multiAuthWithOnlySigv4a"; + private static final String OPERATION_SIGV4_ONLY = "multiAuthWithOnlySigv4"; private static final String OPERATION_SIGV4A_ONLY = "multiAuthWithOnlySigv4a"; private static final String OPERATION_SIGV4A_AND_SIGV4 = "multiAuthWithOnlySigv4aAndSigv4"; private static final String OPERATION_NOAUTH = "multiAuthNoAuth"; @@ -78,27 +78,6 @@ static Stream authSchemeTestCases() { "Operation with no auth scheme should default to Sigv4" ), - Arguments.of( - Arrays.asList(SIGV4A), - OPERATION_NOAUTH, - PREFIXED_SIGV4A, - "" - ), - - Arguments.of( - Arrays.asList(SIGV4A, SIGV4), - OPERATION_NOAUTH, - PREFIXED_SIGV4A, - "" - ), - - Arguments.of( - Arrays.asList(SIGV4A, SIGV4), - OPERATION_NOAUTH, - PREFIXED_SIGV4A, - "" - ), - Arguments.of( Arrays.asList(BEARER, SIGV4, ANONYMOUS), OPERATION_SIGV4A_AND_SIGV4, From 4ae9a446e68b4d43fa69f4cb454a728c8a04436c Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 10:25:41 -0700 Subject: [PATCH 25/53] Fix protocol test dependencies --- test/protocol-tests/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index f6419b41bef4..a416f50f0119 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -87,6 +87,11 @@ aws-core ${awsjavasdk.version} + + software.amazon.awssdk + profiles + ${awsjavasdk.version} + software.amazon.awssdk apache-client From a9e1a087d5153298f5cd171aa57d6151a7a95830 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 12:00:49 -0700 Subject: [PATCH 26/53] Remove dependency on profiles (use option get in generated code instead) --- .../poet/builder/BaseClientBuilderClass.java | 29 +++++++++---------- ...test-bearer-auth-client-builder-class.java | 8 ++--- .../sra/test-client-builder-class.java | 8 ++--- ...-client-builder-endpoints-auth-params.java | 8 ++--- ...lient-builder-internal-defaults-class.java | 8 ++--- ...-composed-sync-default-client-builder.java | 8 ++--- ...ulti-auth-sigv4a-client-builder-class.java | 8 ++--- ...test-no-auth-ops-client-builder-class.java | 8 ++--- ...-no-auth-service-client-builder-class.java | 8 ++--- .../sra/test-query-client-builder-class.java | 8 ++--- .../auth/AuthSchemePreferenceProvider.java | 22 ++++++++++---- services/pom.xml | 5 ---- test/protocol-tests/pom.xml | 5 ---- 13 files changed, 66 insertions(+), 67 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index afb0d7cd8ca7..ff7caa9c53c0 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -443,7 +443,7 @@ private MethodSpec finalizeServiceConfigurationMethod() { // serviceConfigBuilder; the service configuration classes (e.g. S3Configuration) return primitive booleans that // have a default when not present. builder.addStatement("builder.option($T.DUALSTACK_ENDPOINT_ENABLED, serviceConfigBuilder.dualstackEnabled())", - AwsClientOption.class); + AwsClientOption.class); } if (model.getCustomizationConfig().getServiceConfig().hasFipsProperty()) { @@ -453,14 +453,14 @@ private MethodSpec finalizeServiceConfigurationMethod() { if (model.getEndpointOperation().isPresent()) { builder.addStatement("builder.option($T.ENDPOINT_DISCOVERY_ENABLED, endpointDiscoveryEnabled)\n", - SdkClientOption.class); + SdkClientOption.class); } if (StringUtils.isNotBlank(model.getCustomizationConfig().getCustomRetryStrategy())) { builder.addStatement("builder.option($1T.RETRY_STRATEGY, $2T.resolveRetryStrategy(config))", - SdkClientOption.class, - PoetUtils.classNameFromFqcn(model.getCustomizationConfig().getCustomRetryStrategy())); + SdkClientOption.class, + PoetUtils.classNameFromFqcn(model.getCustomizationConfig().getCustomRetryStrategy())); } if (StringUtils.isNotBlank(model.getCustomizationConfig().getCustomRetryPolicy())) { @@ -486,7 +486,7 @@ private MethodSpec finalizeServiceConfigurationMethod() { if (endpointParamsKnowledgeIndex.hasAccountIdEndpointModeBuiltIn()) { builder.addStatement("builder.option($T.$L, resolveAccountIdEndpointMode(config))", - AwsClientOption.class, model.getNamingStrategy().getEnumValueName("accountIdEndpointMode")); + AwsClientOption.class, model.getNamingStrategy().getEnumValueName("accountIdEndpointMode")); } String serviceNameForEnvVar = model.getNamingStrategy().getServiceNameForEnvironmentVariables(); @@ -832,14 +832,13 @@ private MethodSpec defaultAuthSchemeProviderMethod() { .addModifiers(PRIVATE) .addParameter(SdkClientConfiguration.class, "config") .returns(authSchemeSpecUtils.providerInterfaceName()) - .addStatement("$T builder = " - + "$T.builder()", - AuthSchemePreferenceProvider.Builder.class, AuthSchemePreferenceProvider.class) - .addStatement("config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder" - + ".profileFile(() -> profileFile))") - .addStatement("config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder" - + ".profileName(profileName))") - .addStatement("List preferences = builder.build().resolveAuthSchemePreference()") + .addCode("$T authSchemePreferenceProvider = " + + "$T.builder()", + AuthSchemePreferenceProvider.class, AuthSchemePreferenceProvider.class) + .addCode(".profileFile(config.option($T.PROFILE_FILE_SUPPLIER))", SdkClientOption.class) + .addCode(".profileName(config.option($T.PROFILE_NAME))", SdkClientOption.class) + .addStatement(".build()") + .addStatement("List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference()") .beginControlFlow("if(preferences != null && !preferences.isEmpty())") .addStatement("return $T.builder().withPreferredAuthSchemes(preferences).build()", authSchemeSpecUtils.providerInterfaceName()) @@ -979,10 +978,10 @@ private MethodSpec internalPluginsMethod() { List internalPlugins = model.getCustomizationConfig().getInternalPlugins(); if (internalPlugins.isEmpty()) { return builder.addStatement("return $T.emptyList()", Collections.class) - .build(); + .build(); } - builder.addStatement("$T internalPlugins = new $T<>()", parameterizedTypeName, ArrayList.class); + builder.addStatement("$T internalPlugins = new $T<>()", parameterizedTypeName, ArrayList.class); for (String internalPlugin : internalPlugins) { String arguments = internalPluginNewArguments(internalPlugin); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index e96012812a4f..987b1f30ea9a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -128,10 +128,10 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index 13fa4cf20907..540071d01a7d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -227,10 +227,10 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index 48577e0c6290..276718ae1f92 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -145,10 +145,10 @@ public B authSchemeProvider(QueryAuthSchemeProvider authSchemeProvider) { } private QueryAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return QueryAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index b439ee3df905..5d2e21ff4184 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -128,10 +128,10 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index 723fb7e51258..439d818c8922 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -150,10 +150,10 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java index ba9c6fc26357..961f1ca7ffd0 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java @@ -123,10 +123,10 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index 8fca8dc07caf..034878e97c61 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -122,10 +122,10 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 653403fedc4c..0fed20118bf7 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -115,10 +115,10 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index e881e5b08c93..4b8d38d972ee 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -143,10 +143,10 @@ public B authSchemeProvider(QueryAuthSchemeProvider authSchemeProvider) { } private QueryAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider.Builder builder = AuthSchemePreferenceProvider.builder(); - config.asOverrideConfiguration().defaultProfileFile().ifPresent(profileFile -> builder.profileFile(() -> profileFile)); - config.asOverrideConfiguration().defaultProfileName().ifPresent(profileName -> builder.profileName(profileName)); - List preferences = builder.build().resolveAuthSchemePreference(); + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (preferences != null && !preferences.isEmpty()) { return QueryAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java index 7a9e00a09bdd..b48a3e0920da 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java @@ -20,21 +20,31 @@ import java.util.List; import java.util.Optional; import java.util.function.Supplier; -import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.profiles.Profile; import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; -import software.amazon.awssdk.utils.Validate; +import software.amazon.awssdk.utils.Lazy; -@SdkProtectedApi +@SdkInternalApi public class AuthSchemePreferenceProvider { private final Supplier profileFile; private final String profileName; private AuthSchemePreferenceProvider(Builder builder) { - this.profileFile = Validate.paramNotNull(builder.profileFile, "profileFile"); - this.profileName = builder.profileName; + if (builder.profileFile != null) { + this.profileFile = builder.profileFile; + } else { + this.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; + } + + if (builder.profileName != null) { + this.profileName = builder.profileName; + } else { + this.profileName = ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow(); + } } public static Builder builder() { @@ -79,7 +89,7 @@ private List fromProfileFile() { } public static final class Builder { - private Supplier profileFile = ProfileFile::defaultProfileFile; + private Supplier profileFile; private String profileName; public AuthSchemePreferenceProvider.Builder profileFile(Supplier profileFile) { diff --git a/services/pom.xml b/services/pom.xml index bf79123843bb..9ec42eaeb927 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -509,11 +509,6 @@ retries-spi ${awsjavasdk.version} - - software.amazon.awssdk - profiles - ${awsjavasdk.version} - apache-client software.amazon.awssdk diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index a416f50f0119..f6419b41bef4 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -87,11 +87,6 @@ aws-core ${awsjavasdk.version} - - software.amazon.awssdk - profiles - ${awsjavasdk.version} - software.amazon.awssdk apache-client From 73e0564a778d8a5f446d6c73ce555fe967b94b99 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 12:27:29 -0700 Subject: [PATCH 27/53] Fix checkstyle --- .../awscore/internal/auth/AuthSchemePreferenceProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java index b48a3e0920da..b61f3d934aeb 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java @@ -37,7 +37,7 @@ private AuthSchemePreferenceProvider(Builder builder) { if (builder.profileFile != null) { this.profileFile = builder.profileFile; } else { - this.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; + this.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; } if (builder.profileName != null) { From e20c0414f7aa3f492f4a939c348c85dc85c65554 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 13:17:49 -0700 Subject: [PATCH 28/53] Move AuthSchemePreferenceProvider out of internal module --- .../awssdk/codegen/poet/builder/BaseClientBuilderClass.java | 2 +- .../builder/sra/test-bearer-auth-client-builder-class.java | 2 +- .../codegen/poet/builder/sra/test-client-builder-class.java | 2 +- .../sra/test-client-builder-endpoints-auth-params.java | 2 +- .../sra/test-client-builder-internal-defaults-class.java | 2 +- .../sra/test-composed-sync-default-client-builder.java | 2 +- .../sra/test-multi-auth-sigv4a-client-builder-class.java | 2 +- .../builder/sra/test-no-auth-ops-client-builder-class.java | 2 +- .../sra/test-no-auth-service-client-builder-class.java | 2 +- .../poet/builder/sra/test-query-client-builder-class.java | 2 +- .../{internal => }/auth/AuthSchemePreferenceProvider.java | 6 +++--- .../multiauth/AuthSchemePreferenceProviderTest.java | 2 +- .../services/multiauth/MultiAuthSigningPropertiesTest.java | 2 -- 13 files changed, 14 insertions(+), 16 deletions(-) rename core/aws-core/src/main/java/software/amazon/awssdk/awscore/{internal => }/auth/AuthSchemePreferenceProvider.java (96%) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index ff7caa9c53c0..e8da76165a92 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -46,7 +46,7 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.codegen.internal.Utils; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index 987b1f30ea9a..d09f14ced763 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -10,10 +10,10 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index 540071d01a7d..a2f2668cd4de 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -12,10 +12,10 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin1; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin2; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index 276718ae1f92..11333a836f9e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -10,12 +10,12 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index 5d2e21ff4184..981c3ac3c19f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -8,10 +8,10 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index 439d818c8922..bd3ca4d6af4e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -10,10 +10,10 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java index 961f1ca7ffd0..e5f70c733bb2 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java @@ -8,10 +8,10 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index 034878e97c61..40e2d957a64a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -8,10 +8,10 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 0fed20118bf7..73078fd11aad 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -8,10 +8,10 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index 4b8d38d972ee..f726752861f5 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -10,12 +10,12 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceProvider.java similarity index 96% rename from core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java rename to core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceProvider.java index b61f3d934aeb..4debf6407150 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceProvider.java @@ -13,14 +13,14 @@ * permissions and limitations under the License. */ -package software.amazon.awssdk.awscore.internal.auth; +package software.amazon.awssdk.awscore.auth; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Supplier; -import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.profiles.Profile; import software.amazon.awssdk.profiles.ProfileFile; @@ -28,7 +28,7 @@ import software.amazon.awssdk.profiles.ProfileProperty; import software.amazon.awssdk.utils.Lazy; -@SdkInternalApi +@SdkProtectedApi public class AuthSchemePreferenceProvider { private final Supplier profileFile; private final String profileName; diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java index d52f3418341f..b4abb4fe4f3f 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.interceptor.Context; diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java index ebe63f18562f..639f5097146b 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/MultiAuthSigningPropertiesTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.when; import java.util.Arrays; -import java.util.List; import java.util.StringJoiner; import java.util.concurrent.CompletableFuture; import org.assertj.core.api.Assertions; @@ -35,7 +34,6 @@ import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner; From cb2d5a0d939a2783434fb94d45f86e7fbfd95217 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 23 May 2025 13:51:10 -0700 Subject: [PATCH 29/53] More checkstyle fixes --- .../awssdk/codegen/poet/builder/BaseClientBuilderClass.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index e8da76165a92..25dddc17aa2d 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -43,10 +43,10 @@ import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.codegen.internal.Utils; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; From ca2faacfce4e78115c801a7c8c13941ed4cb576f Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 27 May 2025 10:09:41 -0700 Subject: [PATCH 30/53] Refactor and cleanup - move anon classes to full codegen classes. --- .../tasks/CommonInternalGeneratorTasks.java | 23 +++- .../customization/CustomizationConfig.java | 3 +- .../awssdk/codegen/poet/PoetExtension.java | 8 ++ .../poet/builder/BaseClientBuilderClass.java | 111 ++++-------------- ...vironmentTokenMetricsInterceptorClass.java | 94 +++++++++++++++ .../EnvironmentTokenSystemSettingsClass.java | 76 ++++++++++++ .../auth/spi/scheme/AuthSchemeProvider.java | 1 - .../EnvironmentTokenProviderTest.java | 22 +++- 8 files changed, 247 insertions(+), 91 deletions(-) create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java create mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClass.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java index 7d407f582f7d..8e4242c80e7d 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java @@ -15,11 +15,13 @@ package software.amazon.awssdk.codegen.emitters.tasks; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import software.amazon.awssdk.codegen.emitters.GeneratorTask; import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams; import software.amazon.awssdk.codegen.emitters.PoetGeneratorTask; +import software.amazon.awssdk.codegen.poet.client.EnvironmentTokenMetricsInterceptorClass; +import software.amazon.awssdk.codegen.poet.client.EnvironmentTokenSystemSettingsClass; import software.amazon.awssdk.codegen.poet.client.SdkClientOptions; import software.amazon.awssdk.codegen.poet.common.UserAgentUtilsSpec; @@ -33,7 +35,14 @@ public CommonInternalGeneratorTasks(GeneratorTaskParams params) { @Override protected List createTasks() throws Exception { - return Arrays.asList(createClientOptionTask(), createUserAgentTask()); + List tasks = new ArrayList<>(); + tasks.add(createClientOptionTask()); + tasks.add(createUserAgentTask()); + if (params.getModel().getCustomizationConfig().isEnableEnvironmentBearerToken()) { + tasks.add(createEnvironmentTokenSystemSettingTask()); + tasks.add(createEnvironmentTokenMetricInterceptorTask()); + } + return tasks; } private PoetGeneratorTask createClientOptionTask() { @@ -46,6 +55,16 @@ private PoetGeneratorTask createUserAgentTask() { new UserAgentUtilsSpec(params.getModel())); } + private GeneratorTask createEnvironmentTokenSystemSettingTask() { + return new PoetGeneratorTask(clientOptionsDir(), params.getModel().getFileHeader(), + new EnvironmentTokenSystemSettingsClass(params.getModel())); + } + + private GeneratorTask createEnvironmentTokenMetricInterceptorTask() { + return new PoetGeneratorTask(clientOptionsDir(), params.getModel().getFileHeader(), + new EnvironmentTokenMetricsInterceptorClass(params.getModel())); + } + private String clientOptionsDir() { return params.getPathProvider().getClientInternalDirectory(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java index 88435b2650c7..069c6ca6d5a2 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java @@ -352,7 +352,8 @@ public class CustomizationConfig { /** * A boolean flag to indicate if support for configuring a bearer token sourced from the environment should be added to the - * generated service. + * generated service. When enabled, the generated client will use bearer auth with the token sourced from the + * `AWS_BEARER_TOKEN_[SigningName]` environment variable. */ private boolean enableEnvironmentBearerToken = false; diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java index b126fd2f201e..c450111b4fe7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java @@ -79,6 +79,14 @@ public ClassName getUserAgentClass() { return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "UserAgentUtils"); } + public ClassName getEnvironmentTokenMetricsInterceptorClass() { + return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "EnvironmentTokenMetricsInterceptor"); + } + + public ClassName getEnvironmentTokenSystemSettingsClass() { + return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "EnvironmentTokenSystemSettings"); + } + /** * @param operationName Name of the operation * @return A Poet {@link ClassName} for the response type of a paginated operation in the base service package. diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 59c11c2a5794..16419b431db2 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -53,8 +53,8 @@ import software.amazon.awssdk.codegen.model.intermediate.OperationModel; import software.amazon.awssdk.codegen.model.service.AuthType; import software.amazon.awssdk.codegen.model.service.ClientContextParam; -import software.amazon.awssdk.codegen.naming.NamingStrategy; import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.PoetExtension; import software.amazon.awssdk.codegen.poet.PoetUtils; import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils; import software.amazon.awssdk.codegen.poet.auth.scheme.ModelAuthSchemeClassesKnowledgeIndex; @@ -64,7 +64,6 @@ import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils; import software.amazon.awssdk.codegen.utils.AuthUtils; import software.amazon.awssdk.core.SdkPlugin; -import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; import software.amazon.awssdk.core.checksums.RequestChecksumCalculationResolver; import software.amazon.awssdk.core.checksums.ResponseChecksumValidation; @@ -74,18 +73,13 @@ import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.endpointdiscovery.providers.DefaultEndpointDiscoveryProviderChain; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; -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.SdkInternalExecutionAttribute; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.core.signer.Signer; -import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.ProtocolNegotiation; import software.amazon.awssdk.http.SdkHttpConfigurationOption; import software.amazon.awssdk.http.auth.aws.signer.RegionSet; -import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; @@ -95,7 +89,6 @@ import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.StringUtils; -import software.amazon.awssdk.utils.SystemSetting; import software.amazon.awssdk.utils.Validate; import software.amazon.awssdk.utils.internal.CodegenNamingUtils; @@ -111,6 +104,8 @@ public class BaseClientBuilderClass implements ClassSpec { private final AuthSchemeSpecUtils authSchemeSpecUtils; private final ServiceClientConfigurationUtils configurationUtils; private final EndpointParamsKnowledgeIndex endpointParamsKnowledgeIndex; + private final PoetExtension poetExtensions; + public BaseClientBuilderClass(IntermediateModel model) { this.model = model; @@ -121,6 +116,7 @@ public BaseClientBuilderClass(IntermediateModel model) { this.authSchemeSpecUtils = new AuthSchemeSpecUtils(model); this.configurationUtils = new ServiceClientConfigurationUtils(model); this.endpointParamsKnowledgeIndex = EndpointParamsKnowledgeIndex.of(model); + this.poetExtensions = new PoetExtension(model); } @Override @@ -281,21 +277,18 @@ private MethodSpec mergeServiceDefaultsMethod() { .returns(SdkClientConfiguration.class) .addParameter(SdkClientConfiguration.class, "config"); - if (model.getCustomizationConfig().isEnableEnvironmentBearerToken()) { - configureEnvironmentBearerToken(builder); - } boolean crc32FromCompressedDataEnabled = model.getCustomizationConfig().isCalculateCrc32FromCompressedData(); - builder.addCode("return config.merge(c -> c"); - builder.addCode(".option($T.ENDPOINT_PROVIDER, defaultEndpointProvider())", SdkClientOption.class); + builder.beginControlFlow("return config.merge(c -> "); + builder.addCode("c.option($T.ENDPOINT_PROVIDER, defaultEndpointProvider())", SdkClientOption.class); if (authSchemeSpecUtils.useSraAuth()) { - builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config))", SdkClientOption.class); - builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); - } else { - if (defaultAwsAuthSignerMethod().isPresent()) { - builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); + if (!model.getCustomizationConfig().isEnableEnvironmentBearerToken()) { + builder.addCode(".option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config))", SdkClientOption.class); } + builder.addCode(".option($T.AUTH_SCHEMES, authSchemes())", SdkClientOption.class); + } else if (defaultAwsAuthSignerMethod().isPresent()) { + builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class); } builder.addCode(".option($T.CRC32_FROM_COMPRESSED_DATA_ENABLED, $L)\n", SdkClientOption.class, crc32FromCompressedDataEnabled); @@ -314,8 +307,12 @@ private MethodSpec mergeServiceDefaultsMethod() { builder.addCode(".option($T.TOKEN_SIGNER, defaultTokenSigner())", SdkAdvancedClientOption.class); } } + builder.addStatement(""); - builder.addCode(");"); + if (model.getCustomizationConfig().isEnableEnvironmentBearerToken()) { + configureEnvironmentBearerToken(builder); + } + builder.endControlFlow(")"); return builder.build(); } @@ -328,90 +325,32 @@ private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { + "support smithy.api#httpBearerAuth."); } - builder.addStatement("$T tokenSystemSetting = $L", SystemSetting.class, bearerTokenSystemSetting()); - builder.addStatement("$T tokenFromEnv = tokenSystemSetting.getStringValue()", - ParameterizedTypeName.get(Optional.class, String.class)); + builder.addStatement("$T tokenFromEnv = new $T().getStringValue()", + ParameterizedTypeName.get(Optional.class, String.class), + poetExtensions.getEnvironmentTokenSystemSettingsClass()); builder .beginControlFlow("if (tokenFromEnv.isPresent() && config.option($T.AUTH_SCHEME_PROVIDER) == null && config.option($T" + ".TOKEN_IDENTITY_PROVIDER) == null)", SdkClientOption.class, AwsClientOption.class) - .beginControlFlow("config = config.merge(c -> ") .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, $T.builder()" + ".withPreferredAuthSchemes($T.singletonList($S)).build())", SdkClientOption.class, authSchemeSpecUtils.providerInterfaceName(), Collections.class, - "smithy.api#httpBearerAuth") + "httpBearerAuth") .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", AwsClientOption.class, StaticTokenProvider.class) .addStatement("$T interceptors = c.option($T.EXECUTION_INTERCEPTORS)", ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), SdkClientOption.class) - .addStatement("$T envTokenMetricInterceptors = $T.singletonList($L)", + .addStatement("$T envTokenMetricInterceptors = $T.singletonList(new $T(tokenFromEnv.get()))", ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), Collections.class, - envTokenMetricInterceptor()) + poetExtensions.getEnvironmentTokenMetricsInterceptorClass()) .addStatement("c.option($T.EXECUTION_INTERCEPTORS, $T.mergeLists(interceptors, envTokenMetricInterceptors))", SdkClientOption.class, CollectionUtils.class) - .endControlFlow(")") + .endControlFlow() + .beginControlFlow("else") + .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config))", SdkClientOption.class) .endControlFlow(); - } - - private TypeSpec bearerTokenSystemSetting() { - NamingStrategy namingStrategy = model.getNamingStrategy(); - - String systemPropertyName = "aws.bearerToken" + namingStrategy.getSigningNameForSystemProperties(); - String envName = "AWS_BEARER_TOKEN_" + namingStrategy.getSigningNameForEnvironmentVariables(); - - return TypeSpec.anonymousClassBuilder("") - .addSuperinterface(SystemSetting.class) - .addMethod(MethodSpec.methodBuilder("property") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return $S", systemPropertyName) - .build()) - .addMethod(MethodSpec.methodBuilder("environmentVariable") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return $S", envName) - .build()) - .addMethod(MethodSpec.methodBuilder("defaultValue") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(String.class) - .addStatement("return null") - .build()) - .build(); - - } - private TypeSpec envTokenMetricInterceptor() { - MethodSpec beforeExeuction = - MethodSpec - .methodBuilder("beforeExecution") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .addParameter(Context.BeforeExecution.class, "context") - .addParameter(ExecutionAttributes.class, "executionAttributes") - .addStatement("$T selectedAuthScheme = executionAttributes.getAttribute($T.SELECTED_AUTH_SCHEME)", - SelectedAuthScheme.class, SdkInternalExecutionAttribute.class) - .beginControlFlow("if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals($T" - + ".SCHEME_ID) && selectedAuthScheme.identity().isDone())", BearerAuthScheme.class) - .beginControlFlow("if (selectedAuthScheme.identity().getNow(null) instanceof $T)", TokenIdentity.class) - - .addStatement("$T configuredToken = ($T) selectedAuthScheme.identity().getNow(null)", - TokenIdentity.class, TokenIdentity.class) - .beginControlFlow("if (configuredToken.token().equals(tokenFromEnv.get()))") - .addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS)" - + ".addMetric($T.BEARER_SERVICE_ENV_VARS.value())", - SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class) - .endControlFlow() - .endControlFlow() - .endControlFlow() - .build(); - return TypeSpec.anonymousClassBuilder("") - .addSuperinterface(ExecutionInterceptor.class) - .addMethod(beforeExeuction) - .build(); } private Optional mergeInternalDefaultsMethod() { diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java new file mode 100644 index 000000000000..6646649ca502 --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java @@ -0,0 +1,94 @@ +/* + * 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.codegen.poet.client; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeSpec; +import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.PoetExtension; +import software.amazon.awssdk.codegen.poet.PoetUtils; +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.SdkInternalExecutionAttribute; +import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; +import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; +import software.amazon.awssdk.identity.spi.TokenIdentity; + +public class EnvironmentTokenMetricsInterceptorClass implements ClassSpec { + protected final PoetExtension poetExtensions; + + public EnvironmentTokenMetricsInterceptorClass(IntermediateModel model) { + this.poetExtensions = new PoetExtension(model); + } + + + @Override + public TypeSpec poetSpec() { + return TypeSpec.classBuilder(className()) + .addModifiers(Modifier.PUBLIC) + .addAnnotation(PoetUtils.generatedAnnotation()) + .addAnnotation(SdkInternalApi.class) + .addSuperinterface(ExecutionInterceptor.class) + .addField(String.class, "tokenFromEnv", Modifier.PRIVATE, Modifier.FINAL) + .addMethod(constructor()) + .addMethod(beforeExecutionMethod()) + .build(); + } + + private MethodSpec constructor() { + return MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(String.class, "tokenFromEnv") + .addStatement("this.tokenFromEnv = tokenFromEnv") + .build(); + } + + @Override + public ClassName className() { + return poetExtensions.getEnvironmentTokenMetricsInterceptorClass(); + } + + private MethodSpec beforeExecutionMethod() { + return MethodSpec + .methodBuilder("beforeExecution") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .addParameter(Context.BeforeExecution.class, "context") + .addParameter(ExecutionAttributes.class, "executionAttributes") + .addStatement("$T selectedAuthScheme = executionAttributes.getAttribute($T.SELECTED_AUTH_SCHEME)", + SelectedAuthScheme.class, SdkInternalExecutionAttribute.class) + .beginControlFlow("if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals($T" + + ".SCHEME_ID) && selectedAuthScheme.identity().isDone())", BearerAuthScheme.class) + .beginControlFlow("if (selectedAuthScheme.identity().getNow(null) instanceof $T)", TokenIdentity.class) + + .addStatement("$T configuredToken = ($T) selectedAuthScheme.identity().getNow(null)", + TokenIdentity.class, TokenIdentity.class) + .beginControlFlow("if (configuredToken.token().equals(tokenFromEnv))") + .addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS)" + + ".addMetric($T.BEARER_SERVICE_ENV_VARS.value())", + SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class) + .endControlFlow() + .endControlFlow() + .endControlFlow() + .build(); + } +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClass.java new file mode 100644 index 000000000000..3ca3fb56ab41 --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClass.java @@ -0,0 +1,76 @@ +/* + * 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.codegen.poet.client; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeSpec; +import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.naming.NamingStrategy; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.PoetExtension; +import software.amazon.awssdk.codegen.poet.PoetUtils; +import software.amazon.awssdk.utils.SystemSetting; + +public class EnvironmentTokenSystemSettingsClass implements ClassSpec { + protected final IntermediateModel model; + protected final PoetExtension poetExtensions; + + public EnvironmentTokenSystemSettingsClass(IntermediateModel model) { + this.model = model; + this.poetExtensions = new PoetExtension(model); + } + + @Override + public TypeSpec poetSpec() { + NamingStrategy namingStrategy = model.getNamingStrategy(); + + String systemPropertyName = "aws.bearerToken" + namingStrategy.getSigningNameForSystemProperties(); + String envName = "AWS_BEARER_TOKEN_" + namingStrategy.getSigningNameForEnvironmentVariables(); + + return TypeSpec.classBuilder(className()) + .addModifiers(Modifier.PUBLIC) + .addAnnotation(PoetUtils.generatedAnnotation()) + .addAnnotation(SdkInternalApi.class) + .addSuperinterface(SystemSetting.class) + .addMethod(MethodSpec.methodBuilder("property") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", systemPropertyName) + .build()) + .addMethod(MethodSpec.methodBuilder("environmentVariable") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return $S", envName) + .build()) + .addMethod(MethodSpec.methodBuilder("defaultValue") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .returns(String.class) + .addStatement("return null") + .build()) + .build(); + } + + @Override + public ClassName className() { + return poetExtensions.getEnvironmentTokenSystemSettingsClass(); + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java index bb194ba42645..d08bdbe520c1 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/scheme/AuthSchemeProvider.java @@ -23,5 +23,4 @@ */ @SdkPublicApi public interface AuthSchemeProvider { - } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java index aa7422d77dd5..b72e089128c5 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java @@ -23,6 +23,7 @@ import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.auth.token.credentials.StaticTokenProvider; +import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpFullRequest; @@ -117,7 +118,26 @@ public void usesBearerAuthWithTokenPreferredFromSystemProperties() { .isEqualTo(String.format("Bearer %s", SYSTEM_TEST_TOKEN)); } - // TODO: Additional priority tests when auth scheme preference is complete + @Test + public void usesBearerAuthWithTokenFromEnvironmentOverAuthSchemePreference() { + environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); + environmentVariableHelper.set( + SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.environmentVariable(), "sigv4"); + mockHttpClient.stubNextResponse(mockResponse()); + + EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + .builder() + .httpClient(mockHttpClient) + .build(); + + client.oneOperation(b -> { + }); + + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo(String.format("Bearer %s", ENV_TOKEN)); + assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) + .matches(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); + } @Test public void usesSigv4WhenAuthSchemeProviderIsManuallyConfigured() { From f3992dc27bfd2bd1a07839f092d27b1e4186b7c4 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 27 May 2025 10:17:30 -0700 Subject: [PATCH 31/53] Update docs --- .../software/amazon/awssdk/codegen/naming/NamingStrategy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java index dd434a0546e5..637920be14de 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java @@ -206,12 +206,12 @@ public interface NamingStrategy { String getSigningName(); /** - * Retrieve the service name that should be used for environment variables. + * Retrieve the service's signing name that should be used for environment variables. */ String getSigningNameForEnvironmentVariables(); /** - * Retrieve the service name that should be used for system properties. + * Retrieve the service's signing name that should be used for system properties. */ String getSigningNameForSystemProperties(); From 7a8bfa092d4f2b453634f90d4da65bd3aed8a386 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 28 May 2025 08:41:30 -0700 Subject: [PATCH 32/53] Additional codegen tests --- ...nmentTokenMetricsInterceptorClassTest.java | 32 ++++++++++++++++ ...vironmentTokenSystemSettingsClassTest.java | 31 +++++++++++++++ ...nment-token-metrics-interceptor-class.java | 38 +++++++++++++++++++ ...vironment-token-system-settings-class.java | 24 ++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java create mode 100644 codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClassTest.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-system-settings-class.java diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java new file mode 100644 index 000000000000..dfa1aa6624f8 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java @@ -0,0 +1,32 @@ +/* + * 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.codegen.poet.client; + +import static org.hamcrest.MatcherAssert.assertThat; +import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; + +import org.junit.Test; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.ClientTestModels; + +public class EnvironmentTokenMetricsInterceptorClassTest { + + @Test + public void testEnvironmentTokenMetricsInterceptorClass() { + ClassSpec classSpec = new EnvironmentTokenMetricsInterceptorClass(ClientTestModels.restJsonServiceModels()); + assertThat(classSpec, generatesTo("test-environment-token-metrics-interceptor-class.java")); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClassTest.java new file mode 100644 index 000000000000..3946483248a6 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenSystemSettingsClassTest.java @@ -0,0 +1,31 @@ +/* + * 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.codegen.poet.client; + +import static org.hamcrest.MatcherAssert.assertThat; +import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; + +import org.junit.Test; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.ClientTestModels; + +public class EnvironmentTokenSystemSettingsClassTest { + @Test + public void testEnvironmentTokenSystemSettingsClass() { + ClassSpec classSpec = new EnvironmentTokenSystemSettingsClass(ClientTestModels.restJsonServiceModels()); + assertThat(classSpec, generatesTo("test-environment-token-system-settings-class.java")); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java new file mode 100644 index 000000000000..2eb290be7369 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java @@ -0,0 +1,38 @@ +package software.amazon.awssdk.services.json.internal; + +import software.amazon.awssdk.annotations.Generated; +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.core.interceptor.SdkInternalExecutionAttribute; +import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; +import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; +import software.amazon.awssdk.identity.spi.TokenIdentity; + +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class EnvironmentTokenMetricsInterceptor implements ExecutionInterceptor { + private final String tokenFromEnv; + + public EnvironmentTokenMetricsInterceptor(String tokenFromEnv) { + this.tokenFromEnv = tokenFromEnv; + } + + @Override + public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { + SelectedAuthScheme selectedAuthScheme = executionAttributes + .getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME); + if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals(BearerAuthScheme.SCHEME_ID) + && selectedAuthScheme.identity().isDone()) { + if (selectedAuthScheme.identity().getNow(null) instanceof TokenIdentity) { + TokenIdentity configuredToken = (TokenIdentity) selectedAuthScheme.identity().getNow(null); + if (configuredToken.token().equals(tokenFromEnv)) { + executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS.value()); + } + } + } + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-system-settings-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-system-settings-class.java new file mode 100644 index 000000000000..bb604b75807b --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-system-settings-class.java @@ -0,0 +1,24 @@ +package software.amazon.awssdk.services.json.internal; + +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.utils.SystemSetting; + +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public class EnvironmentTokenSystemSettings implements SystemSetting { + @Override + public String property() { + return "aws.bearerTokenJsonService"; + } + + @Override + public String environmentVariable() { + return "AWS_BEARER_TOKEN_JSON_SERVICE"; + } + + @Override + public String defaultValue() { + return null; + } +} From 10c5e4fab322616dbbcab8b810474f28ff225803 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 28 May 2025 15:16:47 -0700 Subject: [PATCH 33/53] Update core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java Co-authored-by: David Ho <70000000+davidh44@users.noreply.github.com> --- .../awssdk/awscore/internal/AwsExecutionContextBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 c6bc03a1d47f..060b7ef0adb4 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 @@ -278,8 +278,8 @@ private static MetricCollector resolveMetricCollector(ClientExecutionParams Date: Wed, 28 May 2025 15:33:14 -0700 Subject: [PATCH 34/53] Add codegen tset for base client builder w/ env bearer token --- .../awssdk/codegen/poet/ClientTestModels.java | 16 ++ .../builder/BaseClientBuilderClassTest.java | 8 + ...env-bearer-token-client-builder-class.java | 228 ++++++++++++++++++ .../customization-env-bearer-token.config | 3 + 4 files changed, 255 insertions(+) create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json-bearer-auth/customization-env-bearer-token.config diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java index 308aa69ea487..978e837fc87f 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/ClientTestModels.java @@ -86,6 +86,22 @@ public static IntermediateModel bearerAuthServiceModels() { return new IntermediateModelBuilder(models).build(); } + public static IntermediateModel envBearerTokenServiceModels() { + File serviceModel = new File(ClientTestModels.class.getResource( + "client/c2j/json-bearer-auth/service-2.json").getFile()); + File customizationModel = new File(ClientTestModels.class.getResource( + "client/c2j/json-bearer-auth/customization-env-bearer-token.config").getFile()); + File paginatorsModel = new File(ClientTestModels.class.getResource( + "client/c2j/json-bearer-auth/paginators.json").getFile()); + C2jModels models = C2jModels.builder() + .serviceModel(getServiceModel(serviceModel)) + .customizationConfig(getCustomizationConfig(customizationModel)) + .paginatorsModel(getPaginatorsModel(paginatorsModel)) + .build(); + + return new IntermediateModelBuilder(models).build(); + } + public static IntermediateModel restJsonServiceModels() { File serviceModel = new File(ClientTestModels.class.getResource("client/c2j/rest-json/service-2.json").getFile()); File customizationModel = new File(ClientTestModels.class.getResource("client/c2j/rest-json/customization.config").getFile()); diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClassTest.java index a09271f4001a..423ae5aba59a 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClassTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClassTest.java @@ -17,6 +17,7 @@ import static software.amazon.awssdk.codegen.poet.ClientTestModels.bearerAuthServiceModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.composedClientJsonServiceModels; +import static software.amazon.awssdk.codegen.poet.ClientTestModels.envBearerTokenServiceModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.internalConfigModels; import static software.amazon.awssdk.codegen.poet.ClientTestModels.operationWithNoAuth; import static software.amazon.awssdk.codegen.poet.ClientTestModels.opsWithSigv4a; @@ -87,6 +88,13 @@ void baseClientBuilderClassWithBearerAuth_sra() { validateBaseClientBuilderClassGeneration(bearerAuthServiceModels(), "test-bearer-auth-client-builder-class.java", true); } + @Test + void baseClientBuilderClassWithEnvBearerToken_sra() { + validateBaseClientBuilderClassGeneration(envBearerTokenServiceModels(), + "test-env-bearer-token-client-builder-class.java", + true); + } + @Test void baseClientBuilderClassWithNoAuthOperation_sra() { validateBaseClientBuilderClassGeneration(operationWithNoAuth(), "test-no-auth-ops-client-builder-class.java", true); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java new file mode 100644 index 000000000000..5faeec296701 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java @@ -0,0 +1,228 @@ +package software.amazon.awssdk.services.json; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.credentials.TokenUtils; +import software.amazon.awssdk.auth.token.credentials.StaticTokenProvider; +import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; +import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.SdkPlugin; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; +import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; +import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; +import software.amazon.awssdk.identity.spi.IdentityProvider; +import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; +import software.amazon.awssdk.retries.api.RetryStrategy; +import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; +import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; +import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; +import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; +import software.amazon.awssdk.services.json.internal.EnvironmentTokenMetricsInterceptor; +import software.amazon.awssdk.services.json.internal.EnvironmentTokenSystemSettings; +import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; +import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.Validate; + +/** + * Internal base class for {@link DefaultJsonClientBuilder} and {@link DefaultJsonAsyncClientBuilder}. + */ +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +abstract class DefaultJsonBaseClientBuilder, C> extends AwsDefaultClientBuilder { + private final Map> additionalAuthSchemes = new HashMap<>(); + + @Override + protected final String serviceEndpointPrefix() { + return "json-service-endpoint"; + } + + @Override + protected final String serviceName() { + return "Json"; + } + + @Override + protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + Optional tokenFromEnv = new EnvironmentTokenSystemSettings().getStringValue(); + if (tokenFromEnv.isPresent() && config.option(SdkClientOption.AUTH_SCHEME_PROVIDER) == null + && config.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER) == null) { + c.option(SdkClientOption.AUTH_SCHEME_PROVIDER, + JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(Collections.singletonList("httpBearerAuth")) + .build()); + c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, StaticTokenProvider.create(tokenFromEnv::get)); + List interceptors = c.option(SdkClientOption.EXECUTION_INTERCEPTORS); + List envTokenMetricInterceptors = Collections + .singletonList(new EnvironmentTokenMetricsInterceptor(tokenFromEnv.get())); + c.option(SdkClientOption.EXECUTION_INTERCEPTORS, + CollectionUtils.mergeLists(interceptors, envTokenMetricInterceptors)); + } else { + c.option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)); + } + }); + } + + @Override + protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + List endpointInterceptors = new ArrayList<>(); + endpointInterceptors.add(new JsonAuthSchemeInterceptor()); + endpointInterceptors.add(new JsonResolveEndpointInterceptor()); + endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); + ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); + List interceptors = interceptorFactory + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + List additionalInterceptors = new ArrayList<>(); + interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); + interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); + interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); + SdkClientConfiguration.Builder builder = config.toBuilder(); + builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { + IdentityProviders.Builder result = IdentityProviders.builder(); + IdentityProvider tokenIdentityProvider = c.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER); + if (tokenIdentityProvider != null) { + result.putIdentityProvider(tokenIdentityProvider); + } + return result.build(); + }); + builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); + builder.lazyOptionIfAbsent( + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); + return builder.build(); + } + + @Override + protected final String signingName() { + return "json-service"; + } + + private JsonEndpointProvider defaultEndpointProvider() { + return JsonEndpointProvider.defaultProvider(); + } + + public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { + clientConfiguration.option(SdkClientOption.AUTH_SCHEME_PROVIDER, authSchemeProvider); + return thisBuilder(); + } + + private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { + AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); + List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); + if (preferences != null && !preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + } + return JsonAuthSchemeProvider.defaultProvider(); + } + + @Override + public B putAuthScheme(AuthScheme authScheme) { + additionalAuthSchemes.put(authScheme.schemeId(), authScheme); + return thisBuilder(); + } + + private Map> authSchemes() { + Map> schemes = new HashMap<>(2 + this.additionalAuthSchemes.size()); + BearerAuthScheme bearerAuthScheme = BearerAuthScheme.create(); + schemes.put(bearerAuthScheme.schemeId(), bearerAuthScheme); + NoAuthAuthScheme noAuthAuthScheme = NoAuthAuthScheme.create(); + schemes.put(noAuthAuthScheme.schemeId(), noAuthAuthScheme); + schemes.putAll(this.additionalAuthSchemes); + return schemes; + } + + private IdentityProvider defaultTokenProvider() { + return DefaultAwsTokenProvider.create(); + } + + @Override + protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { + List internalPlugins = internalPlugins(config); + List externalPlugins = plugins(); + if (internalPlugins.isEmpty() && externalPlugins.isEmpty()) { + return config; + } + List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); + SdkClientConfiguration.Builder configuration = config.toBuilder(); + JsonServiceClientConfigurationBuilder serviceConfigBuilder = new JsonServiceClientConfigurationBuilder(configuration); + for (SdkPlugin plugin : plugins) { + plugin.configureClient(serviceConfigBuilder); + } + updateRetryStrategyClientConfiguration(configuration); + return configuration.build(); + } + + private void updateRetryStrategyClientConfiguration(SdkClientConfiguration.Builder configuration) { + ClientOverrideConfiguration.Builder builder = configuration.asOverrideConfigurationBuilder(); + RetryMode retryMode = builder.retryMode(); + if (retryMode != null) { + configuration.option(SdkClientOption.RETRY_STRATEGY, AwsRetryStrategy.forRetryMode(retryMode)); + } else { + Consumer> configurator = builder.retryStrategyConfigurator(); + if (configurator != null) { + RetryStrategy.Builder defaultBuilder = AwsRetryStrategy.defaultRetryStrategy().toBuilder(); + configurator.accept(defaultBuilder); + configuration.option(SdkClientOption.RETRY_STRATEGY, defaultBuilder.build()); + } else { + RetryStrategy retryStrategy = builder.retryStrategy(); + if (retryStrategy != null) { + configuration.option(SdkClientOption.RETRY_STRATEGY, retryStrategy); + } + } + } + configuration.option(SdkClientOption.CONFIGURED_RETRY_MODE, null); + configuration.option(SdkClientOption.CONFIGURED_RETRY_STRATEGY, null); + configuration.option(SdkClientOption.CONFIGURED_RETRY_CONFIGURATOR, null); + } + + private List internalPlugins(SdkClientConfiguration config) { + return Collections.emptyList(); + } + + protected static void validateClientOptions(SdkClientConfiguration c) { + Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), + "The 'tokenProvider' must be configured in the client builder."); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json-bearer-auth/customization-env-bearer-token.config b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json-bearer-auth/customization-env-bearer-token.config new file mode 100644 index 000000000000..2edb12c857bc --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/c2j/json-bearer-auth/customization-env-bearer-token.config @@ -0,0 +1,3 @@ +{ + "enableEnvironmentBearerToken": true +} From fa17dcfcc0695403152ba940e2b5e0a6fb76856b Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Thu, 29 May 2025 02:44:03 -0700 Subject: [PATCH 35/53] Fixing comments, adding fixture file, renaming provider to resolver, adding coverage --- .../auth/scheme/AuthSchemeProviderSpec.java | 9 +- .../poet/builder/BaseClientBuilderClass.java | 8 +- .../poet/auth/scheme/AuthSchemeSpecTest.java | 6 + .../query-auth-scheme-preferred-provider.java | 51 +++++++++ .../scheme/query-auth-scheme-provider.java | 11 +- ...oint-auth-params-auth-scheme-provider.java | 11 +- ...test-bearer-auth-client-builder-class.java | 8 +- .../sra/test-client-builder-class.java | 8 +- ...-client-builder-endpoints-auth-params.java | 8 +- ...lient-builder-internal-defaults-class.java | 8 +- ...-composed-sync-default-client-builder.java | 8 +- ...ulti-auth-sigv4a-client-builder-class.java | 8 +- ...test-no-auth-ops-client-builder-class.java | 8 +- ...-no-auth-service-client-builder-class.java | 8 +- .../sra/test-query-client-builder-class.java | 8 +- ...java => AuthSchemePreferenceResolver.java} | 32 ++---- .../PreferredAuthSchemeProviderTest.java | 2 +- ...hemePreferenceResolverFunctionalTest.java} | 45 +++----- .../AuthSchemePreferenceResolverTest.java | 107 ++++++++++++++++++ 19 files changed, 250 insertions(+), 104 deletions(-) create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-preferred-provider.java rename core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/{AuthSchemePreferenceProvider.java => AuthSchemePreferenceResolver.java} (75%) rename test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/{AuthSchemePreferenceProviderTest.java => AuthSchemePreferenceResolverFunctionalTest.java} (86%) create mode 100644 test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index 944223765a69..05172675b161 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.function.Consumer; import javax.lang.model.element.Modifier; -import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.ClassSpec; @@ -128,6 +128,8 @@ private MethodSpec staticBuilderMethodSpec() { private TypeSpec builderInterfaceSpec() { return TypeSpec.interfaceBuilder("Builder") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addAnnotation(NotThreadSafe.class) + .addJavadoc("A builder for creating {@link $T} instances.\n", className()) .addMethod(MethodSpec.methodBuilder("build") .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addJavadoc("Returns a {@link $T} object that is created from the " @@ -136,7 +138,7 @@ private TypeSpec builderInterfaceSpec() { .returns(className()) .build()) - .addMethod(MethodSpec.methodBuilder("withPreferredAuthSchemes") + .addMethod(MethodSpec.methodBuilder("preferredAuthSchemes") .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addJavadoc("Set the preferred auth schemes in order of preference.") .returns(className().nestedClass("Builder")) @@ -150,7 +152,6 @@ private TypeSpec builderInterfaceSpec() { private TypeSpec builderClassSpec() { return TypeSpec.classBuilder(authSchemeSpecUtils.authSchemeProviderBuilderName()) - .addAnnotation(SdkInternalApi.class) .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC) .addSuperinterface(className().nestedClass("Builder")) .addField( @@ -160,7 +161,7 @@ private TypeSpec builderClassSpec() { .build()) .addMethod( MethodSpec - .methodBuilder("withPreferredAuthSchemes").addAnnotation(Override.class) + .methodBuilder("preferredAuthSchemes").addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter( ParameterizedTypeName.get(List.class, String.class), diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 25dddc17aa2d..8fef2668ab60 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -43,7 +43,7 @@ import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -834,13 +834,13 @@ private MethodSpec defaultAuthSchemeProviderMethod() { .returns(authSchemeSpecUtils.providerInterfaceName()) .addCode("$T authSchemePreferenceProvider = " + "$T.builder()", - AuthSchemePreferenceProvider.class, AuthSchemePreferenceProvider.class) + AuthSchemePreferenceResolver.class, AuthSchemePreferenceResolver.class) .addCode(".profileFile(config.option($T.PROFILE_FILE_SUPPLIER))", SdkClientOption.class) .addCode(".profileName(config.option($T.PROFILE_NAME))", SdkClientOption.class) .addStatement(".build()") .addStatement("List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference()") - .beginControlFlow("if(preferences != null && !preferences.isEmpty())") - .addStatement("return $T.builder().withPreferredAuthSchemes(preferences).build()", + .beginControlFlow("if(!preferences.isEmpty())") + .addStatement("return $T.builder().preferredAuthSchemes(preferences).build()", authSchemeSpecUtils.providerInterfaceName()) .endControlFlow() .addStatement("return $T.defaultProvider()", authSchemeSpecUtils.providerInterfaceName()) diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java index dba6bca98c74..533dbe8a46ad 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java @@ -66,6 +66,12 @@ static List parameters() { .caseName("query") .outputFileSuffix("default-params") .build(), + TestCase.builder() + .modelProvider(ClientTestModels::queryServiceModels) + .classSpecProvider(PreferredAuthSchemeProviderSpec::new) + .caseName("query") + .outputFileSuffix("preferred-provider") + .build(), // query-endpoint-auth-params TestCase.builder() .modelProvider(ClientTestModels::queryServiceModelsEndpointAuthParamsWithAllowList) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-preferred-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-preferred-provider.java new file mode 100644 index 000000000000..279142374e6b --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-preferred-provider.java @@ -0,0 +1,51 @@ +package software.amazon.awssdk.services.query.auth.scheme.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; +import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeParams; +import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; +import software.amazon.awssdk.utils.CollectionUtils; + +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public final class PreferredQueryAuthSchemeProvider implements QueryAuthSchemeProvider { + private final QueryAuthSchemeProvider delegate; + + private final List authSchemePreference; + + public PreferredQueryAuthSchemeProvider(QueryAuthSchemeProvider delegate, List authSchemePreference) { + this.delegate = delegate; + this.authSchemePreference = authSchemePreference != null ? authSchemePreference : Collections.emptyList(); + } + + /** + * Resolve the auth schemes based on the given set of parameters. + */ + @Override + public List resolveAuthScheme(QueryAuthSchemeParams params) { + List candidateAuthSchemes = delegate.resolveAuthScheme(params); + if (CollectionUtils.isNullOrEmpty(authSchemePreference)) { + return candidateAuthSchemes; + } + List authSchemes = new ArrayList<>(); + authSchemePreference.forEach(preferredSchemeId -> { + candidateAuthSchemes + .stream() + .filter(candidate -> { + String candidateSchemeName = candidate.schemeId().contains("#") ? candidate.schemeId().split("#")[1] + : candidate.schemeId(); + return candidateSchemeName.equals(preferredSchemeId); + }).findFirst().ifPresent(authSchemes::add); + }); + candidateAuthSchemes.forEach(candidate -> { + if (!authSchemes.contains(candidate)) { + authSchemes.add(candidate); + } + }); + return authSchemes; + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java index ba478a5c69d6..ac83deda474b 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java @@ -4,7 +4,7 @@ import java.util.List; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; -import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; @@ -46,6 +46,10 @@ static Builder builder() { return new QueryAuthSchemeProviderBuilder(); } + /** + * A builder for creating {@link QueryAuthSchemeProvider} instances. + */ + @NotThreadSafe interface Builder { /** * Returns a {@link QueryAuthSchemeProvider} object that is created from the properties that have been set on @@ -56,15 +60,14 @@ interface Builder { /** * Set the preferred auth schemes in order of preference. */ - Builder withPreferredAuthSchemes(List authSchemePreference); + Builder preferredAuthSchemes(List authSchemePreference); } - @SdkInternalApi final class QueryAuthSchemeProviderBuilder implements Builder { private List authSchemePreference; @Override - public Builder withPreferredAuthSchemes(List authSchemePreference) { + public Builder preferredAuthSchemes(List authSchemePreference) { this.authSchemePreference = new ArrayList<>(authSchemePreference); return this; } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java index ba478a5c69d6..ac83deda474b 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java @@ -4,7 +4,7 @@ import java.util.List; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; -import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; @@ -46,6 +46,10 @@ static Builder builder() { return new QueryAuthSchemeProviderBuilder(); } + /** + * A builder for creating {@link QueryAuthSchemeProvider} instances. + */ + @NotThreadSafe interface Builder { /** * Returns a {@link QueryAuthSchemeProvider} object that is created from the properties that have been set on @@ -56,15 +60,14 @@ interface Builder { /** * Set the preferred auth schemes in order of preference. */ - Builder withPreferredAuthSchemes(List authSchemePreference); + Builder preferredAuthSchemes(List authSchemePreference); } - @SdkInternalApi final class QueryAuthSchemeProviderBuilder implements Builder { private List authSchemePreference; @Override - public Builder withPreferredAuthSchemes(List authSchemePreference) { + public Builder preferredAuthSchemes(List authSchemePreference) { this.authSchemePreference = new ArrayList<>(authSchemePreference); return this; } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index d09f14ced763..8fe981670552 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -10,7 +10,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -128,12 +128,12 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index a2f2668cd4de..6aaa86ea5ec3 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -12,7 +12,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -227,12 +227,12 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index 11333a836f9e..f082434b99ba 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -10,7 +10,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -145,12 +145,12 @@ public B authSchemeProvider(QueryAuthSchemeProvider authSchemeProvider) { } private QueryAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return QueryAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return QueryAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return QueryAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index 981c3ac3c19f..fd620065b6e8 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -8,7 +8,7 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -128,12 +128,12 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index bd3ca4d6af4e..54afc26816f8 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -10,7 +10,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -150,12 +150,12 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java index e5f70c733bb2..0f847c107f6b 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java @@ -8,7 +8,7 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -123,12 +123,12 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return DatabaseAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index 40e2d957a64a..eb93eaf23bbc 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -8,7 +8,7 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -122,12 +122,12 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return DatabaseAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 73078fd11aad..8418796fa1fa 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -8,7 +8,7 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -115,12 +115,12 @@ public B authSchemeProvider(DatabaseAuthSchemeProvider authSchemeProvider) { } private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return DatabaseAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return DatabaseAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index f726752861f5..2e6e68d9e0f6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -10,7 +10,7 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; @@ -143,12 +143,12 @@ public B authSchemeProvider(QueryAuthSchemeProvider authSchemeProvider) { } private QueryAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return QueryAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return QueryAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); } return QueryAuthSchemeProvider.defaultProvider(); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java similarity index 75% rename from core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceProvider.java rename to core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index 4debf6407150..fef99c8a2470 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -27,24 +27,17 @@ import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; import software.amazon.awssdk.utils.Lazy; +import software.amazon.awssdk.utils.Validate; @SdkProtectedApi -public class AuthSchemePreferenceProvider { +public final class AuthSchemePreferenceResolver { private final Supplier profileFile; private final String profileName; - private AuthSchemePreferenceProvider(Builder builder) { - if (builder.profileFile != null) { - this.profileFile = builder.profileFile; - } else { - this.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; - } - - if (builder.profileName != null) { - this.profileName = builder.profileName; - } else { - this.profileName = ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow(); - } + private AuthSchemePreferenceResolver(Builder builder) { + this.profileFile = Validate.getOrDefault(builder.profileFile, () -> ProfileFile::defaultProfileFile); + this.profileName = Validate.getOrDefault(builder.profileName, + ProfileFileSystemSetting.AWS_PROFILE::getStringValueOrThrow); } public static Builder builder() { @@ -92,18 +85,18 @@ public static final class Builder { private Supplier profileFile; private String profileName; - public AuthSchemePreferenceProvider.Builder profileFile(Supplier profileFile) { + public AuthSchemePreferenceResolver.Builder profileFile(Supplier profileFile) { this.profileFile = profileFile; return this; } - public AuthSchemePreferenceProvider.Builder profileName(String profileName) { + public AuthSchemePreferenceResolver.Builder profileName(String profileName) { this.profileName = profileName; return this; } - public AuthSchemePreferenceProvider build() { - return new AuthSchemePreferenceProvider(this); + public AuthSchemePreferenceResolver build() { + return new AuthSchemePreferenceResolver(this); } } @@ -112,9 +105,6 @@ private static List parseAuthSchemeList(String unformattedList) { return Collections.emptyList(); } - unformattedList = unformattedList.replaceAll("\\s+", ""); - String[] splitByTabs = unformattedList.split("\t"); - String finalFormat = String.join("", splitByTabs); - return Arrays.asList(finalFormat.split(",")); + return Arrays.asList(unformattedList.replaceAll("\\s+", "").split(",")); } } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java index ad53ba5041a2..a6e4dac2797d 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java @@ -47,7 +47,7 @@ public class PreferredAuthSchemeProviderTest { void testAuthSchemePreference(List preferredAuthSchemes, String operation, String expectedFirstScheme, String testName) { MultiauthAuthSchemeProvider provider = MultiauthAuthSchemeProvider .builder() - .withPreferredAuthSchemes(preferredAuthSchemes) + .preferredAuthSchemes(preferredAuthSchemes) .build(); MultiauthAuthSchemeParams params = MultiauthAuthSchemeParams diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java similarity index 86% rename from test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java rename to test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java index b4abb4fe4f3f..1e69af2d05bb 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java @@ -16,9 +16,9 @@ package software.amazon.awssdk.services.multiauth; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -28,7 +28,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; -import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.interceptor.Context; @@ -52,7 +51,7 @@ import software.amazon.awssdk.testutils.EnvironmentVariableHelper; import software.amazon.awssdk.utils.StringInputStream; -public class AuthSchemePreferenceProviderTest { +public class AuthSchemePreferenceResolverFunctionalTest { private final EnvironmentVariableHelper helper = new EnvironmentVariableHelper(); @AfterEach @@ -61,25 +60,6 @@ void tearDown() { helper.reset(); } - @ParameterizedTest - @MethodSource("schemeParsingCases") - void parsesAuthSchemeCorrectly(String authSchemePreference, List actual) { - System.setProperty(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.property(), authSchemePreference); - AuthSchemePreferenceProvider provider = AuthSchemePreferenceProvider.builder().build(); - List pref = provider.resolveAuthSchemePreference(); - assertThat(pref).isEqualTo(actual); - } - - static Stream schemeParsingCases() { - return Stream.of( - Arguments.of("scheme1, scheme2 , \tscheme3 \t", Arrays.asList("scheme1", "scheme2", "scheme3")), - Arguments.of("scheme1, scheme2 \t scheme3 scheme4", Arrays.asList("scheme1", "scheme2scheme3scheme4")), - Arguments.of("sigv4, sig v 4 a, bearer", Arrays.asList("sigv4", "sigv4a", "bearer")), - Arguments.of("", Collections.singletonList("")) - - ); - } - @ParameterizedTest @MethodSource("testCases") void resolvesAuthSchemePreference(TestCase testCase) { @@ -92,7 +72,7 @@ void resolvesAuthSchemePreference(TestCase testCase) { builder.putAuthScheme(authScheme("aws.auth#sigv4a", new SkipCrtNoOpSigner())); if (testCase.clientSetting != null) { - builder.authSchemeProvider(MultiauthAuthSchemeProvider.builder().withPreferredAuthSchemes(testCase.clientSetting).build()); + builder.authSchemeProvider(MultiauthAuthSchemeProvider.builder().preferredAuthSchemes(testCase.clientSetting).build()); } if (testCase.systemPropSetting != null) { @@ -120,11 +100,9 @@ void resolvesAuthSchemePreference(TestCase testCase) { MultiauthClient client = builder.build(); - try { - client.multiAuthWithOnlySigv4aAndSigv4(MultiAuthWithOnlySigv4AAndSigv4Request.builder().build()); - } catch (AutSchemeCapturingInterceptor.CaptureException e) { - // expected - } + assertThatThrownBy(() -> + client.multiAuthWithOnlySigv4aAndSigv4(MultiAuthWithOnlySigv4AAndSigv4Request.builder().build()) + ).isInstanceOf(AutSchemeCapturingInterceptor.CaptureException.class); assertThat(interceptor.authScheme()).isEqualTo(testCase.resolvedAuthScheme); } finally { @@ -185,6 +163,15 @@ static Stream testCases() { "sigv4", "Profile setting is used when others are null")), + Arguments.of(new TestCase( + "", + null, + null, + null, + "sigv4a", + "Profile setting is used when explicit empty string is supplied")), + + Arguments.of(new TestCase( "bearer,sigv4,sigv4a", "sigv4a,sigv4,bearer", @@ -269,5 +256,3 @@ public CompletableFuture signAsync( } } } - - diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java new file mode 100644 index 000000000000..5c30087cc6df --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java @@ -0,0 +1,107 @@ +/* + * 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.services.multiauth; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; +import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.profiles.ProfileProperty; +import software.amazon.awssdk.utils.StringInputStream; + +class AuthSchemePreferenceResolverTest { + + @AfterEach + void tearDown() { + System.clearProperty(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.property()); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("profileTestCases") + void profileParsingTests(String testName, String profileContent, String profileName, List expected) { + ProfileFile profileFile = ProfileFile.builder() + .type(ProfileFile.Type.CONFIGURATION) + .content(new StringInputStream(profileContent)) + .build(); + + AuthSchemePreferenceResolver.Builder resolverBuilder = AuthSchemePreferenceResolver.builder() + .profileFile(() -> profileFile); + if (profileName != null) { + resolverBuilder.profileName(profileName); + } + + assertThat(resolverBuilder.build().resolveAuthSchemePreference()).isEqualTo(expected); + } + + static Stream profileTestCases() { + return Stream.of( + Arguments.of( + "Default profile parsing", + "[default]\n" + ProfileProperty.AUTH_SCHEME_PREFERENCE + "=sigv4,bearer", + null, + Arrays.asList("sigv4", "bearer") + ), + Arguments.of( + "Custom profile parsing", + "[profile custom]\n" + ProfileProperty.AUTH_SCHEME_PREFERENCE + "=sigv4,bearer", + "custom", + Arrays.asList("sigv4", "bearer") + ), + Arguments.of( + "Profile with whitespace", + "[default]\n" + ProfileProperty.AUTH_SCHEME_PREFERENCE + "=sigv4, \tbearer \t", + null, + Arrays.asList("sigv4", "bearer") + ) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("systemSettingTestCases") + void systemSettingParsingTests(String testName, String systemSetting, List expected) { + if (systemSetting != null) { + System.setProperty(SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.property(), systemSetting); + } + + AuthSchemePreferenceResolver resolver = AuthSchemePreferenceResolver.builder().build(); + assertThat(resolver.resolveAuthSchemePreference()).isEqualTo(expected); + } + + static Stream systemSettingTestCases() { + return Stream.of( + Arguments.of("Basic system setting", "sigv4,bearer", Arrays.asList("sigv4", "bearer")), + Arguments.of("Empty system setting", "", Collections.singletonList("")), + Arguments.of("No system setting", null, Collections.emptyList()), + + // Whitespace/formatting cases (from schemeParsingCases) + Arguments.of("Whitespace with tabs", "scheme1, scheme2 , \tscheme3 \t", + Arrays.asList("scheme1", "scheme2", "scheme3")), + Arguments.of("Whitespace with joined schemes", "scheme1, scheme2 \t scheme3 scheme4", + Arrays.asList("scheme1", "scheme2scheme3scheme4")), + Arguments.of("Whitespace in scheme names", "sigv4, sig v 4 a, bearer", + Arrays.asList("sigv4", "sigv4a", "bearer")) + ); + } +} \ No newline at end of file From da1a81b8af0ec99f4e92a7e294d025e06dade0b1 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 08:24:39 -0700 Subject: [PATCH 36/53] Add async client test --- .../EnvironmentTokenProviderTest.java | 303 ++++++++++++------ 1 file changed, 210 insertions(+), 93 deletions(-) diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java index b72e089128c5..c16069a30dd5 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/environmenttokenprovider/EnvironmentTokenProviderTest.java @@ -17,11 +17,13 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; 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.StaticCredentialsProvider; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import software.amazon.awssdk.auth.token.credentials.StaticTokenProvider; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; @@ -31,6 +33,7 @@ import software.amazon.awssdk.services.environmenttokenprovider.auth.scheme.EnvironmentTokenProviderAuthSchemeProvider; import software.amazon.awssdk.services.environmenttokenprovider.model.OneOperationRequest; import software.amazon.awssdk.testutils.EnvironmentVariableHelper; +import software.amazon.awssdk.testutils.service.http.MockAsyncHttpClient; import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient; public class EnvironmentTokenProviderTest { @@ -40,6 +43,7 @@ public class EnvironmentTokenProviderTest { public static final String SYSTEM_TEST_TOKEN = "system-test-token"; private MockSyncHttpClient mockHttpClient; + private MockAsyncHttpClient mockAsyncHttpClient; private String systemPropertyBeforeTest; private final EnvironmentVariableHelper environmentVariableHelper = new EnvironmentVariableHelper(); @@ -47,12 +51,14 @@ public class EnvironmentTokenProviderTest { @BeforeEach void setUp() { mockHttpClient = new MockSyncHttpClient(); + mockAsyncHttpClient = new MockAsyncHttpClient(); systemPropertyBeforeTest = System.getProperty(SYSTEM_PROPERTY_NAME); } @AfterEach void tearDown() { mockHttpClient.reset(); + mockAsyncHttpClient.reset(); environmentVariableHelper.reset(); if (systemPropertyBeforeTest != null) { System.setProperty(SYSTEM_PROPERTY_NAME, systemPropertyBeforeTest); @@ -61,122 +67,147 @@ void tearDown() { } } - @Test - public void usesSigv4WhenTokenUnset() { - mockHttpClient.stubNextResponse(mockResponse()); + @ParameterizedTest + @MethodSource("testCases") + void testAsyncClient(TestCase testCase) { + setupSystemAndEnv(testCase); - EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient - .builder() - .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid"))) - .httpClient(mockHttpClient) - .build(); + mockAsyncHttpClient.stubNextResponse(mockResponse()); - client.oneOperation(b -> { - }); + EnvironmentTokenProviderAsyncClientBuilder clientBuilder = EnvironmentTokenProviderAsyncClient + .builder() + .httpClient(mockAsyncHttpClient); - SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); - assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).startsWith("AWS4-HMAC-SHA256 Credential=akid/"); - } + if (testCase.authSchemeProvider != null) { + clientBuilder.authSchemeProvider(testCase.authSchemeProvider); + } - @Test - public void usesBearerAuthWithTokenFromEnvironmentWhenSet() { - environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); - mockHttpClient.stubNextResponse(mockResponse()); + EnvironmentTokenProviderAsyncClient client = clientBuilder.build(); - EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient - .builder() - .httpClient(mockHttpClient) - .build(); + if (testCase.operationToken == null) { + client.oneOperation(b -> {} ).join(); + } else { + client.oneOperation(requestWithOperationToken(testCase)).join(); + } - client.oneOperation(b -> { - }); + SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockAsyncHttpClient.getLastRequest(); - SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); - assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo(String.format("Bearer %s", ENV_TOKEN)); - assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) - .matches(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); + verifyRequest(testCase, loggedRequest); } - @Test - public void usesBearerAuthWithTokenPreferredFromSystemProperties() { - environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); - System.setProperty(SYSTEM_PROPERTY_NAME, SYSTEM_TEST_TOKEN); - + @ParameterizedTest + @MethodSource("testCases") + void testSyncClient(TestCase testCase) { + setupSystemAndEnv(testCase); mockHttpClient.stubNextResponse(mockResponse()); - EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient + EnvironmentTokenProviderClientBuilder clientBuilder = EnvironmentTokenProviderClient .builder() - .httpClient(mockHttpClient) - .build(); + .httpClient(mockHttpClient); - client.oneOperation(b -> { - }); - - SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); - assertThat(loggedRequest.firstMatchingHeader("Authorization").get()) - .isEqualTo(String.format("Bearer %s", SYSTEM_TEST_TOKEN)); - } + if (testCase.authSchemeProvider != null) { + clientBuilder.authSchemeProvider(testCase.authSchemeProvider); + } - @Test - public void usesBearerAuthWithTokenFromEnvironmentOverAuthSchemePreference() { - environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); - environmentVariableHelper.set( - SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.environmentVariable(), "sigv4"); - mockHttpClient.stubNextResponse(mockResponse()); + EnvironmentTokenProviderClient client = clientBuilder.build(); - EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient - .builder() - .httpClient(mockHttpClient) - .build(); + if (testCase.operationToken == null) { + client.oneOperation(b -> {} ); + } else { + client.oneOperation(requestWithOperationToken(testCase)); + } - client.oneOperation(b -> { - }); SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); - assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo(String.format("Bearer %s", ENV_TOKEN)); - assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) - .matches(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); - } - @Test - public void usesSigv4WhenAuthSchemeProviderIsManuallyConfigured() { - mockHttpClient.stubNextResponse(mockResponse()); - environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); - - EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient - .builder() - .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid"))) - .authSchemeProvider(EnvironmentTokenProviderAuthSchemeProvider.defaultProvider()) - .httpClient(mockHttpClient) - .build(); + verifyRequest(testCase, loggedRequest); + } - client.oneOperation(b -> { - }); + private static void verifyRequest(TestCase testCase, SdkHttpFullRequest loggedRequest) { + if (testCase.expectBearerAuth) { + assertThat(loggedRequest.firstMatchingHeader("Authorization").get()) + .startsWith("Bearer"); + } else { + assertThat(loggedRequest.firstMatchingHeader("Authorization") + .get()).startsWith("AWS4-HMAC-SHA256"); + } - SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); - assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).startsWith("AWS4-HMAC-SHA256 Credential=akid/"); + if (testCase.expectBusinessMetricSet) { + assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) + .matches(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); + } else { + assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) + .doesNotMatch(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); + } } - @Test - public void metricNotSetWhenTokenOverriddenOnOperation() { - environmentVariableHelper.set(ENV_NAME, ENV_TOKEN); - mockHttpClient.stubNextResponse(mockResponse()); - - EnvironmentTokenProviderClient client = EnvironmentTokenProviderClient - .builder() - .httpClient(mockHttpClient) - .build(); + static Stream testCases() { + return Stream.of( + TestCase.builder() + .description("Does not use bearer auth when ENV token is unset") + .expectBearerAuth(false) + .build(), + + TestCase.builder() + .description("Uses bearer auth when ENV token is set") + .envVar(ENV_NAME, ENV_TOKEN) + .expectBearerAuth(true) + .expectedBearerToken(ENV_TOKEN) + .expectBusinessMetricSet(true) + .build(), + + TestCase.builder() + .description("Uses bearer auth when system property token is set") + .envVar(ENV_NAME, "some-other-token") + .systemProperty(SYSTEM_TEST_TOKEN) + .expectBearerAuth(true) + .expectedBearerToken(SYSTEM_TEST_TOKEN) + .expectBusinessMetricSet(true) + .build(), + + TestCase.builder() + .description("Uses bearer auth from environment over auth scheme preference") + .envVar(ENV_NAME, ENV_TOKEN) + .envVar( + SdkSystemSetting.AWS_AUTH_SCHEME_PREFERENCE.environmentVariable(), + "sigv4") + .expectBearerAuth(true) + .expectedBearerToken(ENV_TOKEN) + .expectBusinessMetricSet(true) + .build(), + + TestCase.builder() + .description("Doesn't use bearer when AuthSchemeProvider is manually configured on the client") + .envVar(ENV_NAME, ENV_TOKEN) + .authSchemeProvider(EnvironmentTokenProviderAuthSchemeProvider.defaultProvider()) + .expectBearerAuth(false) + .expectBusinessMetricSet(false) + .build(), + + TestCase.builder() + .description("Business metric is not set when the token is overridden on the operation") + .envVar(ENV_NAME, ENV_TOKEN) + .operationToken("operation-token") + .expectBearerAuth(true) + .expectedBearerToken("operation-token") + .expectBusinessMetricSet(false) + .build() + ); + } - client.oneOperation(OneOperationRequest.builder() - .overrideConfiguration(c -> c.tokenIdentityProvider( - StaticTokenProvider.create(() -> "operation-token"))) - .build()); + private static OneOperationRequest requestWithOperationToken(TestCase testCase) { + return OneOperationRequest.builder() + .overrideConfiguration(c -> c.tokenIdentityProvider( + StaticTokenProvider.create(() -> testCase.operationToken))) + .build(); + } - SdkHttpFullRequest loggedRequest = (SdkHttpFullRequest) mockHttpClient.getLastRequest(); - assertThat(loggedRequest.firstMatchingHeader("Authorization").get()).isEqualTo("Bearer operation-token"); - assertThat(loggedRequest.firstMatchingHeader("User-Agent").get()) - .doesNotMatch(".*m\\/[A-Za-z0-9,]+" + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS); + private void setupSystemAndEnv(TestCase testCase) { + testCase.envVars.forEach(environmentVariableHelper::set); + if (testCase.systemProperty != null) { + System.setProperty(SYSTEM_PROPERTY_NAME, testCase.systemProperty); + } } private HttpExecuteResponse mockResponse() { @@ -184,4 +215,90 @@ private HttpExecuteResponse mockResponse() { .response(SdkHttpResponse.builder().statusCode(200).build()) .build(); } + + static final class TestCase { + final String description; + final Map envVars; + final String systemProperty; + final EnvironmentTokenProviderAuthSchemeProvider authSchemeProvider; + final String operationToken; + final boolean expectBearerAuth; + final String expectedBearerToken; + final boolean expectBusinessMetricSet; + + private TestCase(Builder builder) { + this.description = builder.description; + this.envVars = builder.envVars; + this.systemProperty = builder.systemProperty; + this.authSchemeProvider = builder.authSchemeProvider; + this.operationToken = builder.operationToken; + this.expectBearerAuth = builder.expectBearerAuth; + this.expectedBearerToken = builder.expectedBearerToken; + this.expectBusinessMetricSet = builder.expectBusinessMetricSet; + } + + @Override + public String toString() { + return description; + } + + static Builder builder() { + return new Builder(); + } + + static class Builder { + private String description; + private Map envVars = new HashMap<>(); + private String systemProperty; + private EnvironmentTokenProviderAuthSchemeProvider authSchemeProvider; + private String operationToken; + private boolean expectBearerAuth; + private String expectedBearerToken; + private boolean expectBusinessMetricSet; + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder envVar(String key, String value) { + this.envVars.put(key, value); + return this; + } + + public Builder systemProperty(String systemProperty) { + this.systemProperty = systemProperty; + return this; + } + + public Builder authSchemeProvider(EnvironmentTokenProviderAuthSchemeProvider authSchemeProvider) { + this.authSchemeProvider = authSchemeProvider; + return this; + } + + public Builder operationToken(String operationToken) { + this.operationToken = operationToken; + return this; + } + + public Builder expectBearerAuth(boolean expectBearerAuth) { + this.expectBearerAuth = expectBearerAuth; + return this; + } + + public Builder expectedBearerToken(String expectedBearerToken) { + this.expectedBearerToken = expectedBearerToken; + return this; + } + + public Builder expectBusinessMetricSet(boolean expectBusinessMetricSet) { + this.expectBusinessMetricSet = expectBusinessMetricSet; + return this; + } + + public TestCase build() { + return new TestCase(this); + } + } + } } From 39882e877c567a466cbbb55f62781f86497ea6a0 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 09:08:34 -0700 Subject: [PATCH 37/53] Move metric interceptor logic from beforeExecute to beforeMarshall --- .../poet/client/EnvironmentTokenMetricsInterceptorClass.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java index 6646649ca502..f34187704799 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java @@ -69,10 +69,10 @@ public ClassName className() { private MethodSpec beforeExecutionMethod() { return MethodSpec - .methodBuilder("beforeExecution") + .methodBuilder("beforeMarshalling") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) - .addParameter(Context.BeforeExecution.class, "context") + .addParameter(Context.BeforeMarshalling.class, "context") .addParameter(ExecutionAttributes.class, "executionAttributes") .addStatement("$T selectedAuthScheme = executionAttributes.getAttribute($T.SELECTED_AUTH_SCHEME)", SelectedAuthScheme.class, SdkInternalExecutionAttribute.class) From cb799bb679e4fe40b59fb2739232498bc0af671f Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 11:27:02 -0700 Subject: [PATCH 38/53] Move metrics logic into auth scheme interceptor --- .../tasks/CommonInternalGeneratorTasks.java | 7 -- .../scheme/AuthSchemeInterceptorSpec.java | 42 +++++++++ .../poet/builder/BaseClientBuilderClass.java | 12 +-- ...vironmentTokenMetricsInterceptorClass.java | 94 ------------------- ...nmentTokenMetricsInterceptorClassTest.java | 32 ------- ...nment-token-metrics-interceptor-class.java | 38 -------- .../SdkInternalExecutionAttribute.java | 6 ++ 7 files changed, 53 insertions(+), 178 deletions(-) delete mode 100644 codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java delete mode 100644 codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java delete mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java index 8e4242c80e7d..1bafba5eed5d 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/CommonInternalGeneratorTasks.java @@ -20,7 +20,6 @@ import software.amazon.awssdk.codegen.emitters.GeneratorTask; import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams; import software.amazon.awssdk.codegen.emitters.PoetGeneratorTask; -import software.amazon.awssdk.codegen.poet.client.EnvironmentTokenMetricsInterceptorClass; import software.amazon.awssdk.codegen.poet.client.EnvironmentTokenSystemSettingsClass; import software.amazon.awssdk.codegen.poet.client.SdkClientOptions; import software.amazon.awssdk.codegen.poet.common.UserAgentUtilsSpec; @@ -40,7 +39,6 @@ protected List createTasks() throws Exception { tasks.add(createUserAgentTask()); if (params.getModel().getCustomizationConfig().isEnableEnvironmentBearerToken()) { tasks.add(createEnvironmentTokenSystemSettingTask()); - tasks.add(createEnvironmentTokenMetricInterceptorTask()); } return tasks; } @@ -60,11 +58,6 @@ private GeneratorTask createEnvironmentTokenSystemSettingTask() { new EnvironmentTokenSystemSettingsClass(params.getModel())); } - private GeneratorTask createEnvironmentTokenMetricInterceptorTask() { - return new PoetGeneratorTask(clientOptionsDir(), params.getModel().getFileHeader(), - new EnvironmentTokenMetricsInterceptorClass(params.getModel())); - } - private String clientOptionsDir() { return params.getPathProvider().getClientInternalDirectory(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeInterceptorSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeInterceptorSpec.java index 7686ef132271..043bf74ba9d9 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeInterceptorSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeInterceptorSpec.java @@ -49,8 +49,10 @@ import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.core.internal.util.MetricUtils; import software.amazon.awssdk.core.metrics.CoreMetric; +import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; import software.amazon.awssdk.endpoints.EndpointProvider; import software.amazon.awssdk.http.auth.aws.signer.RegionSet; +import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.signer.HttpSigner; @@ -70,8 +72,10 @@ public final class AuthSchemeInterceptorSpec implements ClassSpec { private final AuthSchemeSpecUtils authSchemeSpecUtils; private final EndpointRulesSpecUtils endpointRulesSpecUtils; + private final IntermediateModel intermediateModel; public AuthSchemeInterceptorSpec(IntermediateModel intermediateModel) { + this.intermediateModel = intermediateModel; this.authSchemeSpecUtils = new AuthSchemeSpecUtils(intermediateModel); this.endpointRulesSpecUtils = new EndpointRulesSpecUtils(intermediateModel); } @@ -99,9 +103,42 @@ public TypeSpec poetSpec() { .addMethod(generateTrySelectAuthScheme()) .addMethod(generateGetIdentityMetric()) .addMethod(putSelectedAuthSchemeMethodSpec()); + if (intermediateModel.getCustomizationConfig().isEnableEnvironmentBearerToken()) { + builder.addMethod(generateEnvironmentTokenMetric()); + } return builder.build(); } + private MethodSpec generateEnvironmentTokenMetric() { + return MethodSpec + .methodBuilder("recordEnvironmentTokenBusinessMetric") + .addModifiers(Modifier.PRIVATE) + .addTypeVariable(TypeVariableName.get("T", Identity.class)) + .addParameter(ParameterSpec.builder( + ParameterizedTypeName.get(ClassName.get(SelectedAuthScheme.class), + TypeVariableName.get("T")), + "selectedAuthScheme").build()) + .addParameter(ExecutionAttributes.class, "executionAttributes") + .addStatement("$T tokenFromEnv = executionAttributes.getAttribute($T.TOKEN_CONFIGURED_FROM_ENV)", + String.class, SdkInternalExecutionAttribute.class) + .beginControlFlow("if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals($T" + + ".SCHEME_ID) && selectedAuthScheme.identity().isDone())", BearerAuthScheme.class) + .beginControlFlow("if (selectedAuthScheme.identity().getNow(null) instanceof $T)", TokenIdentity.class) + + .addStatement("$T configuredToken = ($T) selectedAuthScheme.identity().getNow(null)", + TokenIdentity.class, TokenIdentity.class) + .beginControlFlow("if (configuredToken.token().equals(tokenFromEnv))") + .addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS)" + + ".addMetric($T.BEARER_SERVICE_ENV_VARS.value())", + SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class) + .endControlFlow() + .endControlFlow() + .endControlFlow() + .build(); + + + } + private MethodSpec generateBeforeExecution() { MethodSpec.Builder builder = MethodSpec.methodBuilder("beforeExecution") .addAnnotation(Override.class) @@ -116,6 +153,11 @@ private MethodSpec generateBeforeExecution() { .addStatement("$T selectedAuthScheme = selectAuthScheme(authOptions, executionAttributes)", wildcardSelectedAuthScheme()) .addStatement("putSelectedAuthScheme(executionAttributes, selectedAuthScheme)"); + + if (intermediateModel.getCustomizationConfig().isEnableEnvironmentBearerToken()) { + builder.addStatement("recordEnvironmentTokenBusinessMetric(selectedAuthScheme, " + + "executionAttributes)"); + } return builder.build(); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 16419b431db2..aeec20e2f46b 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -73,7 +73,9 @@ import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.endpointdiscovery.providers.DefaultEndpointDiscoveryProviderChain; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.http.Protocol; @@ -339,13 +341,9 @@ private void configureEnvironmentBearerToken(MethodSpec.Builder builder) { "httpBearerAuth") .addStatement("c.option($T.TOKEN_IDENTITY_PROVIDER, $T.create(tokenFromEnv::get))", AwsClientOption.class, StaticTokenProvider.class) - .addStatement("$T interceptors = c.option($T.EXECUTION_INTERCEPTORS)", - ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), SdkClientOption.class) - .addStatement("$T envTokenMetricInterceptors = $T.singletonList(new $T(tokenFromEnv.get()))", - ParameterizedTypeName.get(List.class, ExecutionInterceptor.class), Collections.class, - poetExtensions.getEnvironmentTokenMetricsInterceptorClass()) - .addStatement("c.option($T.EXECUTION_INTERCEPTORS, $T.mergeLists(interceptors, envTokenMetricInterceptors))", - SdkClientOption.class, CollectionUtils.class) + .addStatement("c.option($T.EXECUTION_ATTRIBUTES, " + + "$T.builder().put($T.TOKEN_CONFIGURED_FROM_ENV, tokenFromEnv.get()).build())", + SdkClientOption.class, ExecutionAttributes.class, SdkInternalExecutionAttribute.class) .endControlFlow() .beginControlFlow("else") .addStatement("c.option($T.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config))", SdkClientOption.class) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java deleted file mode 100644 index f34187704799..000000000000 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClass.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.codegen.poet.client; - -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.TypeSpec; -import javax.lang.model.element.Modifier; -import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; -import software.amazon.awssdk.codegen.poet.ClassSpec; -import software.amazon.awssdk.codegen.poet.PoetExtension; -import software.amazon.awssdk.codegen.poet.PoetUtils; -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.SdkInternalExecutionAttribute; -import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; -import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; -import software.amazon.awssdk.identity.spi.TokenIdentity; - -public class EnvironmentTokenMetricsInterceptorClass implements ClassSpec { - protected final PoetExtension poetExtensions; - - public EnvironmentTokenMetricsInterceptorClass(IntermediateModel model) { - this.poetExtensions = new PoetExtension(model); - } - - - @Override - public TypeSpec poetSpec() { - return TypeSpec.classBuilder(className()) - .addModifiers(Modifier.PUBLIC) - .addAnnotation(PoetUtils.generatedAnnotation()) - .addAnnotation(SdkInternalApi.class) - .addSuperinterface(ExecutionInterceptor.class) - .addField(String.class, "tokenFromEnv", Modifier.PRIVATE, Modifier.FINAL) - .addMethod(constructor()) - .addMethod(beforeExecutionMethod()) - .build(); - } - - private MethodSpec constructor() { - return MethodSpec.constructorBuilder() - .addModifiers(Modifier.PUBLIC) - .addParameter(String.class, "tokenFromEnv") - .addStatement("this.tokenFromEnv = tokenFromEnv") - .build(); - } - - @Override - public ClassName className() { - return poetExtensions.getEnvironmentTokenMetricsInterceptorClass(); - } - - private MethodSpec beforeExecutionMethod() { - return MethodSpec - .methodBuilder("beforeMarshalling") - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .addParameter(Context.BeforeMarshalling.class, "context") - .addParameter(ExecutionAttributes.class, "executionAttributes") - .addStatement("$T selectedAuthScheme = executionAttributes.getAttribute($T.SELECTED_AUTH_SCHEME)", - SelectedAuthScheme.class, SdkInternalExecutionAttribute.class) - .beginControlFlow("if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals($T" - + ".SCHEME_ID) && selectedAuthScheme.identity().isDone())", BearerAuthScheme.class) - .beginControlFlow("if (selectedAuthScheme.identity().getNow(null) instanceof $T)", TokenIdentity.class) - - .addStatement("$T configuredToken = ($T) selectedAuthScheme.identity().getNow(null)", - TokenIdentity.class, TokenIdentity.class) - .beginControlFlow("if (configuredToken.token().equals(tokenFromEnv))") - .addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS)" - + ".addMetric($T.BEARER_SERVICE_ENV_VARS.value())", - SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class) - .endControlFlow() - .endControlFlow() - .endControlFlow() - .build(); - } -} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java deleted file mode 100644 index dfa1aa6624f8..000000000000 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/client/EnvironmentTokenMetricsInterceptorClassTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.codegen.poet.client; - -import static org.hamcrest.MatcherAssert.assertThat; -import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; - -import org.junit.Test; -import software.amazon.awssdk.codegen.poet.ClassSpec; -import software.amazon.awssdk.codegen.poet.ClientTestModels; - -public class EnvironmentTokenMetricsInterceptorClassTest { - - @Test - public void testEnvironmentTokenMetricsInterceptorClass() { - ClassSpec classSpec = new EnvironmentTokenMetricsInterceptorClass(ClientTestModels.restJsonServiceModels()); - assertThat(classSpec, generatesTo("test-environment-token-metrics-interceptor-class.java")); - } -} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java deleted file mode 100644 index 2eb290be7369..000000000000 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-environment-token-metrics-interceptor-class.java +++ /dev/null @@ -1,38 +0,0 @@ -package software.amazon.awssdk.services.json.internal; - -import software.amazon.awssdk.annotations.Generated; -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.core.interceptor.SdkInternalExecutionAttribute; -import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; -import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; -import software.amazon.awssdk.identity.spi.TokenIdentity; - -@Generated("software.amazon.awssdk:codegen") -@SdkInternalApi -public class EnvironmentTokenMetricsInterceptor implements ExecutionInterceptor { - private final String tokenFromEnv; - - public EnvironmentTokenMetricsInterceptor(String tokenFromEnv) { - this.tokenFromEnv = tokenFromEnv; - } - - @Override - public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { - SelectedAuthScheme selectedAuthScheme = executionAttributes - .getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME); - if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals(BearerAuthScheme.SCHEME_ID) - && selectedAuthScheme.identity().isDone()) { - if (selectedAuthScheme.identity().getNow(null) instanceof TokenIdentity) { - TokenIdentity configuredToken = (TokenIdentity) selectedAuthScheme.identity().getNow(null); - if (configuredToken.token().equals(tokenFromEnv)) { - executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( - BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS.value()); - } - } - } - } -} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java index 08f890bd8333..08276be11d16 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java @@ -197,6 +197,12 @@ public final class SdkInternalExecutionAttribute extends SdkExecutionAttribute { static final ExecutionAttribute INTERNAL_RESOLVED_CHECKSUM_SPECS = new ExecutionAttribute<>("InternalResolvedChecksumSpecs"); + /** + * The response checksum validation setting. + */ + public static final ExecutionAttribute TOKEN_CONFIGURED_FROM_ENV = new ExecutionAttribute<>( + "TokenConfiguredFromEnv"); + private SdkInternalExecutionAttribute() { } } From 9c0980ba16d4c1d9357910f233de3621d322b626 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 11:55:01 -0700 Subject: [PATCH 39/53] Remove unused import --- .../amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index fef99c8a2470..c6c631e1c1d3 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -26,7 +26,6 @@ import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; -import software.amazon.awssdk.utils.Lazy; import software.amazon.awssdk.utils.Validate; @SdkProtectedApi From 141b9d6b984fb305d14f680a545c7f182c4f10d1 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 12:51:32 -0700 Subject: [PATCH 40/53] Add codegen test for preferred auth scheme provider --- .../PreferredAuthSchemeProviderSpecTest.java | 32 ++++++++++++ .../test-preferred-auth-scheme-provider.java | 51 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java new file mode 100644 index 000000000000..c2856343ba51 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java @@ -0,0 +1,32 @@ +/* + * 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.codegen.poet.auth.scheme; + +import static org.hamcrest.MatcherAssert.assertThat; +import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.codegen.poet.ClassSpec; +import software.amazon.awssdk.codegen.poet.ClientTestModels; + +public class PreferredAuthSchemeProviderSpecTest { + + @Test + void testGeneratedClass() { + ClassSpec classSpec = new PreferredAuthSchemeProviderSpec(ClientTestModels.restJsonServiceModels()); + assertThat(classSpec, generatesTo("test-preferred-auth-scheme-provider.java")); + } +} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java new file mode 100644 index 000000000000..66e2babc8751 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java @@ -0,0 +1,51 @@ +package software.amazon.awssdk.services.json.auth.scheme.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; +import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeParams; +import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; +import software.amazon.awssdk.utils.CollectionUtils; + +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public final class PreferredJsonAuthSchemeProvider implements JsonAuthSchemeProvider { + private final JsonAuthSchemeProvider delegate; + + private final List authSchemePreference; + + public PreferredJsonAuthSchemeProvider(JsonAuthSchemeProvider delegate, List authSchemePreference) { + this.delegate = delegate; + this.authSchemePreference = authSchemePreference != null ? authSchemePreference : Collections.emptyList(); + } + + /** + * Resolve the auth schemes based on the given set of parameters. + */ + @Override + public List resolveAuthScheme(JsonAuthSchemeParams params) { + List candidateAuthSchemes = delegate.resolveAuthScheme(params); + if (CollectionUtils.isNullOrEmpty(authSchemePreference)) { + return candidateAuthSchemes; + } + List authSchemes = new ArrayList<>(); + authSchemePreference.forEach(preferredSchemeId -> { + candidateAuthSchemes + .stream() + .filter(candidate -> { + String candidateSchemeName = candidate.schemeId().contains("#") ? candidate.schemeId().split("#")[1] + : candidate.schemeId(); + return candidateSchemeName.equals(preferredSchemeId); + }).findFirst().ifPresent(authSchemes::add); + }); + candidateAuthSchemes.forEach(candidate -> { + if (!authSchemes.contains(candidate)) { + authSchemes.add(candidate); + } + }); + return authSchemes; + } +} From 491e3cfb11b0cebed08f544980a4a143c428fdc4 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 13:06:31 -0700 Subject: [PATCH 41/53] Check for empty string --- .../awssdk/awscore/auth/AuthSchemePreferenceResolver.java | 3 ++- .../services/multiauth/AuthSchemePreferenceResolverTest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index c6c631e1c1d3..14f71ce75c1c 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -26,6 +26,7 @@ import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; +import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.Validate; @SdkProtectedApi @@ -100,7 +101,7 @@ public AuthSchemePreferenceResolver build() { } private static List parseAuthSchemeList(String unformattedList) { - if (unformattedList == null) { + if (StringUtils.isEmpty(unformattedList)) { return Collections.emptyList(); } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java index 5c30087cc6df..3373b9fbb229 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java @@ -92,7 +92,7 @@ void systemSettingParsingTests(String testName, String systemSetting, List systemSettingTestCases() { return Stream.of( Arguments.of("Basic system setting", "sigv4,bearer", Arrays.asList("sigv4", "bearer")), - Arguments.of("Empty system setting", "", Collections.singletonList("")), + Arguments.of("Empty system setting", "", Collections.emptyList()), Arguments.of("No system setting", null, Collections.emptyList()), // Whitespace/formatting cases (from schemeParsingCases) From e915d3edfae6cae10566087a3c1c156ed9e5e45f Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 13:18:42 -0700 Subject: [PATCH 42/53] Add more documentation --- .../awscore/auth/AuthSchemePreferenceResolver.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index 14f71ce75c1c..c562821842c3 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -29,6 +29,11 @@ import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.Validate; +/** + * A resolver for the default value of auth scheme preference. This checks environment variables, + * system properties and the profile file for the relevant configuration options when + * {@link #resolveAuthSchemePreference()} is invoked. + */ @SdkProtectedApi public final class AuthSchemePreferenceResolver { private final Supplier profileFile; @@ -44,6 +49,13 @@ public static Builder builder() { return new Builder(); } + /** + * Resolve the auth scheme preference based on the following order of precedence: + * 1. System settings (jvm and then environment). + * 2. Profile file + * + * @return The resolved, ordered list of auth scheme preferences or an empty list if no values are found. + */ public List resolveAuthSchemePreference() { List systemSettingList = fromSystemSetting(); if (systemSettingList != null && !systemSettingList.isEmpty()) { From 729abbb95aba10a8dc54644841b5f396c4873b97 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 29 May 2025 13:38:24 -0700 Subject: [PATCH 43/53] Revert "Add codegen test for preferred auth scheme provider" This reverts commit 141b9d6b984fb305d14f680a545c7f182c4f10d1. --- .../PreferredAuthSchemeProviderSpecTest.java | 32 ------------ .../test-preferred-auth-scheme-provider.java | 51 ------------------- 2 files changed, 83 deletions(-) delete mode 100644 codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java delete mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java deleted file mode 100644 index c2856343ba51..000000000000 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/PreferredAuthSchemeProviderSpecTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.codegen.poet.auth.scheme; - -import static org.hamcrest.MatcherAssert.assertThat; -import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo; - -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.codegen.poet.ClassSpec; -import software.amazon.awssdk.codegen.poet.ClientTestModels; - -public class PreferredAuthSchemeProviderSpecTest { - - @Test - void testGeneratedClass() { - ClassSpec classSpec = new PreferredAuthSchemeProviderSpec(ClientTestModels.restJsonServiceModels()); - assertThat(classSpec, generatesTo("test-preferred-auth-scheme-provider.java")); - } -} diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java deleted file mode 100644 index 66e2babc8751..000000000000 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/test-preferred-auth-scheme-provider.java +++ /dev/null @@ -1,51 +0,0 @@ -package software.amazon.awssdk.services.json.auth.scheme.internal; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import software.amazon.awssdk.annotations.Generated; -import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; -import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeParams; -import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; -import software.amazon.awssdk.utils.CollectionUtils; - -@Generated("software.amazon.awssdk:codegen") -@SdkInternalApi -public final class PreferredJsonAuthSchemeProvider implements JsonAuthSchemeProvider { - private final JsonAuthSchemeProvider delegate; - - private final List authSchemePreference; - - public PreferredJsonAuthSchemeProvider(JsonAuthSchemeProvider delegate, List authSchemePreference) { - this.delegate = delegate; - this.authSchemePreference = authSchemePreference != null ? authSchemePreference : Collections.emptyList(); - } - - /** - * Resolve the auth schemes based on the given set of parameters. - */ - @Override - public List resolveAuthScheme(JsonAuthSchemeParams params) { - List candidateAuthSchemes = delegate.resolveAuthScheme(params); - if (CollectionUtils.isNullOrEmpty(authSchemePreference)) { - return candidateAuthSchemes; - } - List authSchemes = new ArrayList<>(); - authSchemePreference.forEach(preferredSchemeId -> { - candidateAuthSchemes - .stream() - .filter(candidate -> { - String candidateSchemeName = candidate.schemeId().contains("#") ? candidate.schemeId().split("#")[1] - : candidate.schemeId(); - return candidateSchemeName.equals(preferredSchemeId); - }).findFirst().ifPresent(authSchemes::add); - }); - candidateAuthSchemes.forEach(candidate -> { - if (!authSchemes.contains(candidate)) { - authSchemes.add(candidate); - } - }); - return authSchemes; - } -} From 9abd847d958e4f7cb61e4e512c61544a9ae92ee3 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Mon, 2 Jun 2025 10:21:24 -0700 Subject: [PATCH 44/53] Replace authprovider builder with overridden defaultProvider method --- .../auth/scheme/AuthSchemeProviderSpec.java | 88 +++---------------- .../poet/builder/BaseClientBuilderClass.java | 2 +- .../scheme/query-auth-scheme-provider.java | 40 +-------- ...oint-auth-params-auth-scheme-provider.java | 40 +-------- ...test-bearer-auth-client-builder-class.java | 2 +- .../sra/test-client-builder-class.java | 2 +- ...-client-builder-endpoints-auth-params.java | 2 +- ...lient-builder-internal-defaults-class.java | 2 +- ...-composed-sync-default-client-builder.java | 2 +- ...ulti-auth-sigv4a-client-builder-class.java | 2 +- ...test-no-auth-ops-client-builder-class.java | 2 +- ...-no-auth-service-client-builder-class.java | 2 +- .../sra/test-query-client-builder-class.java | 2 +- .../PreferredAuthSchemeProviderTest.java | 5 +- ...chemePreferenceResolverFunctionalTest.java | 2 +- 15 files changed, 30 insertions(+), 165 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java index 05172675b161..b43c577e9931 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeProviderSpec.java @@ -17,16 +17,13 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; -import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import javax.lang.model.element.Modifier; -import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.poet.ClassSpec; @@ -58,9 +55,7 @@ public TypeSpec poetSpec() { .addMethod(resolveAuthSchemeMethod()) .addMethod(resolveAuthSchemeConsumerBuilderMethod()) .addMethod(defaultProviderMethod()) - .addMethod(staticBuilderMethodSpec()) - .addType(builderInterfaceSpec()) - .addType(builderClassSpec()) + .addMethod(defaultPreferredProviderMethod()) .build(); } @@ -100,6 +95,17 @@ private MethodSpec defaultProviderMethod() { .build(); } + private MethodSpec defaultPreferredProviderMethod() { + return MethodSpec.methodBuilder("defaultProvider") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addParameter(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") + .returns(className()) + .addJavadoc("Get the default auth scheme provider the preferred auth schemes in order of preference.") + .addStatement("return new $T(defaultProvider(), authSchemePreference)", + authSchemeSpecUtils.preferredAuthSchemeProviderName()) + .build(); + } + private CodeBlock interfaceJavadoc() { CodeBlock.Builder b = CodeBlock.builder(); @@ -111,75 +117,5 @@ private CodeBlock interfaceJavadoc() { return b.build(); } - - private MethodSpec staticBuilderMethodSpec() { - return MethodSpec.methodBuilder("builder") - .addJavadoc("Create a builder for the auth scheme provider.") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(className().nestedClass("Builder")) - .addStatement("return new $T()", ClassName.get(className().packageName(), - className().simpleName(), - className().simpleName() + "Builder") - ) - .build(); - } - - - private TypeSpec builderInterfaceSpec() { - return TypeSpec.interfaceBuilder("Builder") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .addAnnotation(NotThreadSafe.class) - .addJavadoc("A builder for creating {@link $T} instances.\n", className()) - .addMethod(MethodSpec.methodBuilder("build") - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .addJavadoc("Returns a {@link $T} object that is created from the " - + "properties that have been set on the builder.", - className()) - .returns(className()) - .build()) - - .addMethod(MethodSpec.methodBuilder("preferredAuthSchemes") - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .addJavadoc("Set the preferred auth schemes in order of preference.") - .returns(className().nestedClass("Builder")) - .addParameter( - ParameterizedTypeName.get(List.class, String.class), - "authSchemePreference" - ) - .build()) - .build(); - } - - private TypeSpec builderClassSpec() { - return TypeSpec.classBuilder(authSchemeSpecUtils.authSchemeProviderBuilderName()) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC) - .addSuperinterface(className().nestedClass("Builder")) - .addField( - FieldSpec - .builder(ParameterizedTypeName.get(List.class, String.class), "authSchemePreference") - .addModifiers(Modifier.PRIVATE) - .build()) - .addMethod( - MethodSpec - .methodBuilder("preferredAuthSchemes").addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .addParameter( - ParameterizedTypeName.get(List.class, String.class), - "authSchemePreference" - ) - .returns(className().nestedClass("Builder")) - .addStatement("this.authSchemePreference = new $T<>(authSchemePreference)", ArrayList.class) - .addStatement("return this") - .build()) - .addMethod( - MethodSpec - .methodBuilder("build").addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .returns(className()) - .addStatement("return new $T(defaultProvider(), authSchemePreference)", - authSchemeSpecUtils.preferredAuthSchemeProviderName()) - .build()) - .build(); - } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 8fef2668ab60..b7d20cf5603e 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -840,7 +840,7 @@ private MethodSpec defaultAuthSchemeProviderMethod() { .addStatement(".build()") .addStatement("List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference()") .beginControlFlow("if(!preferences.isEmpty())") - .addStatement("return $T.builder().preferredAuthSchemes(preferences).build()", + .addStatement("return $T.defaultProvider(preferences)", authSchemeSpecUtils.providerInterfaceName()) .endControlFlow() .addStatement("return $T.defaultProvider()", authSchemeSpecUtils.providerInterfaceName()) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java index ac83deda474b..cdbc7c4c24d0 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-provider.java @@ -1,10 +1,8 @@ package software.amazon.awssdk.services.query.auth.scheme; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; -import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; @@ -40,41 +38,9 @@ static QueryAuthSchemeProvider defaultProvider() { } /** - * Create a builder for the auth scheme provider. + * Get the default auth scheme provider the preferred auth schemes in order of preference. */ - static Builder builder() { - return new QueryAuthSchemeProviderBuilder(); - } - - /** - * A builder for creating {@link QueryAuthSchemeProvider} instances. - */ - @NotThreadSafe - interface Builder { - /** - * Returns a {@link QueryAuthSchemeProvider} object that is created from the properties that have been set on - * the builder. - */ - QueryAuthSchemeProvider build(); - - /** - * Set the preferred auth schemes in order of preference. - */ - Builder preferredAuthSchemes(List authSchemePreference); - } - - final class QueryAuthSchemeProviderBuilder implements Builder { - private List authSchemePreference; - - @Override - public Builder preferredAuthSchemes(List authSchemePreference) { - this.authSchemePreference = new ArrayList<>(authSchemePreference); - return this; - } - - @Override - public QueryAuthSchemeProvider build() { - return new PreferredQueryAuthSchemeProvider(defaultProvider(), authSchemePreference); - } + static QueryAuthSchemeProvider defaultProvider(List authSchemePreference) { + return new PreferredQueryAuthSchemeProvider(defaultProvider(), authSchemePreference); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java index ac83deda474b..cdbc7c4c24d0 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-auth-scheme-provider.java @@ -1,10 +1,8 @@ package software.amazon.awssdk.services.query.auth.scheme; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; -import software.amazon.awssdk.annotations.NotThreadSafe; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; @@ -40,41 +38,9 @@ static QueryAuthSchemeProvider defaultProvider() { } /** - * Create a builder for the auth scheme provider. + * Get the default auth scheme provider the preferred auth schemes in order of preference. */ - static Builder builder() { - return new QueryAuthSchemeProviderBuilder(); - } - - /** - * A builder for creating {@link QueryAuthSchemeProvider} instances. - */ - @NotThreadSafe - interface Builder { - /** - * Returns a {@link QueryAuthSchemeProvider} object that is created from the properties that have been set on - * the builder. - */ - QueryAuthSchemeProvider build(); - - /** - * Set the preferred auth schemes in order of preference. - */ - Builder preferredAuthSchemes(List authSchemePreference); - } - - final class QueryAuthSchemeProviderBuilder implements Builder { - private List authSchemePreference; - - @Override - public Builder preferredAuthSchemes(List authSchemePreference) { - this.authSchemePreference = new ArrayList<>(authSchemePreference); - return this; - } - - @Override - public QueryAuthSchemeProvider build() { - return new PreferredQueryAuthSchemeProvider(defaultProvider(), authSchemePreference); - } + static QueryAuthSchemeProvider defaultProvider(List authSchemePreference) { + return new PreferredQueryAuthSchemeProvider(defaultProvider(), authSchemePreference); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index 8fe981670552..d07aa8df2aa6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -133,7 +133,7 @@ private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return JsonAuthSchemeProvider.defaultProvider(preferences); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index 6aaa86ea5ec3..6fc7c8605c76 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -232,7 +232,7 @@ private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return JsonAuthSchemeProvider.defaultProvider(preferences); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index f082434b99ba..9c5e9647fa06 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -150,7 +150,7 @@ private QueryAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return QueryAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return QueryAuthSchemeProvider.defaultProvider(preferences); } return QueryAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index fd620065b6e8..15fa5602d745 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -133,7 +133,7 @@ private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return JsonAuthSchemeProvider.defaultProvider(preferences); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index 54afc26816f8..a765c15c4c34 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -155,7 +155,7 @@ private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return JsonAuthSchemeProvider.defaultProvider(preferences); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java index 0f847c107f6b..38d843d80fb0 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java @@ -128,7 +128,7 @@ private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfigurat .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return DatabaseAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return DatabaseAuthSchemeProvider.defaultProvider(preferences); } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index eb93eaf23bbc..aab7db9ccff5 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -127,7 +127,7 @@ private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfigurat .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return DatabaseAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return DatabaseAuthSchemeProvider.defaultProvider(preferences); } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 8418796fa1fa..30958f0e2876 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -120,7 +120,7 @@ private DatabaseAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfigurat .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return DatabaseAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return DatabaseAuthSchemeProvider.defaultProvider(preferences); } return DatabaseAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index 2e6e68d9e0f6..89a0c285bf60 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -148,7 +148,7 @@ private QueryAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); if (!preferences.isEmpty()) { - return QueryAuthSchemeProvider.builder().preferredAuthSchemes(preferences).build(); + return QueryAuthSchemeProvider.defaultProvider(preferences); } return QueryAuthSchemeProvider.defaultProvider(); } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java index a6e4dac2797d..1868848bdf3c 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/PreferredAuthSchemeProviderTest.java @@ -45,10 +45,7 @@ public class PreferredAuthSchemeProviderTest { @ParameterizedTest(name = "{3}") @MethodSource("authSchemeTestCases") void testAuthSchemePreference(List preferredAuthSchemes, String operation, String expectedFirstScheme, String testName) { - MultiauthAuthSchemeProvider provider = MultiauthAuthSchemeProvider - .builder() - .preferredAuthSchemes(preferredAuthSchemes) - .build(); + MultiauthAuthSchemeProvider provider = MultiauthAuthSchemeProvider.defaultProvider(preferredAuthSchemes); MultiauthAuthSchemeParams params = MultiauthAuthSchemeParams .builder() diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java index 1e69af2d05bb..502f5aa20be9 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverFunctionalTest.java @@ -72,7 +72,7 @@ void resolvesAuthSchemePreference(TestCase testCase) { builder.putAuthScheme(authScheme("aws.auth#sigv4a", new SkipCrtNoOpSigner())); if (testCase.clientSetting != null) { - builder.authSchemeProvider(MultiauthAuthSchemeProvider.builder().preferredAuthSchemes(testCase.clientSetting).build()); + builder.authSchemeProvider(MultiauthAuthSchemeProvider.defaultProvider(testCase.clientSetting)); } if (testCase.systemPropSetting != null) { From 1dc5f585b73cee268b4dc0dedcae28c887c80b17 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 3 Jun 2025 08:34:56 -0700 Subject: [PATCH 45/53] Update core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java Co-authored-by: Olivier L Applin --- .../awssdk/awscore/auth/AuthSchemePreferenceResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index c562821842c3..e61325524f25 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -63,7 +63,7 @@ public List resolveAuthSchemePreference() { } List profileFilePrefList = fromProfileFile(); - if (profileFilePrefList != null && !profileFilePrefList.isEmpty()) { + if (!CollectionUtils.isNullOrEmpty(profileFilePrefList)) { return profileFilePrefList; } From 22dbae732949dac220ceb45708f0dc443e9e62fc Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 3 Jun 2025 08:35:06 -0700 Subject: [PATCH 46/53] Update core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java Co-authored-by: Olivier L Applin --- .../awssdk/awscore/auth/AuthSchemePreferenceResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index e61325524f25..27f384291b03 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -58,7 +58,7 @@ public static Builder builder() { */ public List resolveAuthSchemePreference() { List systemSettingList = fromSystemSetting(); - if (systemSettingList != null && !systemSettingList.isEmpty()) { + if (!CollectionUtils.isNullOrEmpty(systemSettingList)) { return systemSettingList; } From 584c77c5f49a772d8ae04907d452a92675919b39 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 3 Jun 2025 09:04:50 -0700 Subject: [PATCH 47/53] Fix import from suggested changes --- .../amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java index 27f384291b03..5e7fb58f0d96 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/auth/AuthSchemePreferenceResolver.java @@ -26,6 +26,7 @@ import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; +import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.Validate; From 1e85d4fc6efc5d1f1b07f5ede5956fe7573f8ce3 Mon Sep 17 00:00:00 2001 From: RanVaknin <50976344+RanVaknin@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:02:47 -0700 Subject: [PATCH 48/53] move test to aws-core module --- .../internal/auth}/AuthSchemePreferenceResolverTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth => core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/auth}/AuthSchemePreferenceResolverTest.java (98%) diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceResolverTest.java similarity index 98% rename from test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java rename to core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceResolverTest.java index 3373b9fbb229..1f8526009cf8 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/multiauth/AuthSchemePreferenceResolverTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/auth/AuthSchemePreferenceResolverTest.java @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -package software.amazon.awssdk.services.multiauth; +package software.amazon.awssdk.awscore.internal.auth; import static org.assertj.core.api.Assertions.assertThat; From 04596cf63ae29085995b605db4f86465918ffe5d Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 5 Jun 2025 09:15:13 -0700 Subject: [PATCH 49/53] Update codegen tests --- ...test-bearer-auth-client-builder-class.java | 17 +-- .../sra/test-client-builder-class.java | 19 +-- ...-client-builder-endpoints-auth-params.java | 17 +-- ...lient-builder-internal-defaults-class.java | 10 +- ...-composed-sync-default-client-builder.java | 19 +-- ...env-bearer-token-client-builder-class.java | 23 ++-- ...ulti-auth-sigv4a-client-builder-class.java | 10 +- ...test-no-auth-ops-client-builder-class.java | 27 +++- ...-no-auth-service-client-builder-class.java | 10 +- .../sra/test-query-client-builder-class.java | 17 +-- ...test-bearer-auth-client-builder-class.java | 51 ++++---- .../builder/test-client-builder-class.java | 119 +++++++++--------- ...-client-builder-endpoints-auth-params.java | 17 +-- ...lient-builder-internal-defaults-class.java | 42 ++++--- ...-composed-sync-default-client-builder.java | 75 +++++------ .../test-h2-service-client-builder-class.java | 44 +++---- ...dgeForH2-service-client-builder-class.java | 42 ++++--- ...test-no-auth-ops-client-builder-class.java | 51 ++++---- ...-no-auth-service-client-builder-class.java | 42 ++++--- .../test-query-client-builder-class.java | 17 +-- 20 files changed, 356 insertions(+), 313 deletions(-) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java index d07aa8df2aa6..ee8f9a73d3e5 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-bearer-auth-client-builder-class.java @@ -60,14 +60,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java index 6fc7c8605c76..a0bdac67d04d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-class.java @@ -71,15 +71,16 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java index 9c5e9647fa06..360d3664eaad 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-endpoints-auth-params.java @@ -69,14 +69,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java index 15fa5602d745..9b143b9ccd69 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-client-builder-internal-defaults-class.java @@ -56,10 +56,12 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java index a765c15c4c34..117e19038881 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-composed-sync-default-client-builder.java @@ -66,15 +66,16 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java index 5faeec296701..48ecf08535fa 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-env-bearer-token-client-builder-class.java @@ -12,17 +12,19 @@ import software.amazon.awssdk.auth.credentials.TokenUtils; import software.amazon.awssdk.auth.token.credentials.StaticTokenProvider; import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; +import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; -import software.amazon.awssdk.awscore.internal.auth.AuthSchemePreferenceProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; @@ -38,7 +40,6 @@ import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; -import software.amazon.awssdk.services.json.internal.EnvironmentTokenMetricsInterceptor; import software.amazon.awssdk.services.json.internal.EnvironmentTokenSystemSettings; import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; @@ -75,14 +76,12 @@ protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfigurati if (tokenFromEnv.isPresent() && config.option(SdkClientOption.AUTH_SCHEME_PROVIDER) == null && config.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER) == null) { c.option(SdkClientOption.AUTH_SCHEME_PROVIDER, - JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(Collections.singletonList("httpBearerAuth")) - .build()); + JsonAuthSchemeProvider.defaultProvider(Collections.singletonList("httpBearerAuth"))); c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, StaticTokenProvider.create(tokenFromEnv::get)); - List interceptors = c.option(SdkClientOption.EXECUTION_INTERCEPTORS); - List envTokenMetricInterceptors = Collections - .singletonList(new EnvironmentTokenMetricsInterceptor(tokenFromEnv.get())); - c.option(SdkClientOption.EXECUTION_INTERCEPTORS, - CollectionUtils.mergeLists(interceptors, envTokenMetricInterceptors)); + c.option( + SdkClientOption.EXECUTION_ATTRIBUTES, + ExecutionAttributes.builder() + .put(SdkInternalExecutionAttribute.TOKEN_CONFIGURED_FROM_ENV, tokenFromEnv.get()).build()); } else { c.option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)); } @@ -147,12 +146,12 @@ public B authSchemeProvider(JsonAuthSchemeProvider authSchemeProvider) { } private JsonAuthSchemeProvider defaultAuthSchemeProvider(SdkClientConfiguration config) { - AuthSchemePreferenceProvider authSchemePreferenceProvider = AuthSchemePreferenceProvider.builder() + AuthSchemePreferenceResolver authSchemePreferenceProvider = AuthSchemePreferenceResolver.builder() .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.option(SdkClientOption.PROFILE_NAME)).build(); List preferences = authSchemePreferenceProvider.resolveAuthSchemePreference(); - if (preferences != null && !preferences.isEmpty()) { - return JsonAuthSchemeProvider.builder().withPreferredAuthSchemes(preferences).build(); + if (!preferences.isEmpty()) { + return JsonAuthSchemeProvider.defaultProvider(preferences); } return JsonAuthSchemeProvider.defaultProvider(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java index 38d843d80fb0..75faf2cad7a8 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-multi-auth-sigv4a-client-builder-class.java @@ -59,10 +59,12 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java index aab7db9ccff5..72d4f526bfb3 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-ops-client-builder-class.java @@ -8,6 +8,8 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.credentials.TokenUtils; +import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider; import software.amazon.awssdk.awscore.auth.AuthSchemePreferenceResolver; import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; @@ -26,6 +28,7 @@ import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; @@ -36,6 +39,7 @@ import software.amazon.awssdk.services.database.endpoints.internal.DatabaseResolveEndpointInterceptor; import software.amazon.awssdk.services.database.internal.DatabaseServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.Validate; /** * Internal base class for {@link DefaultDatabaseClientBuilder} and {@link DefaultDatabaseAsyncClientBuilder}. @@ -58,10 +62,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + }); } @Override @@ -80,6 +89,10 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { IdentityProviders.Builder result = IdentityProviders.builder(); + IdentityProvider tokenIdentityProvider = c.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER); + if (tokenIdentityProvider != null) { + result.putIdentityProvider(tokenIdentityProvider); + } IdentityProvider credentialsIdentityProvider = c.get(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); if (credentialsIdentityProvider != null) { result.putIdentityProvider(credentialsIdentityProvider); @@ -150,6 +163,10 @@ private Map> authSchemes() { return schemes; } + private IdentityProvider defaultTokenProvider() { + return DefaultAwsTokenProvider.create(); + } + @Override protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List internalPlugins = internalPlugins(config); @@ -196,5 +213,7 @@ private List internalPlugins(SdkClientConfiguration config) { } protected static void validateClientOptions(SdkClientConfiguration c) { + Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java index 30958f0e2876..0be9c031d828 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-no-auth-service-client-builder-class.java @@ -55,10 +55,12 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java index 89a0c285bf60..19b8d5abbae1 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/sra/test-query-client-builder-class.java @@ -67,14 +67,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) - .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.AUTH_SCHEME_PROVIDER, defaultAuthSchemeProvider(config)) + .option(SdkClientOption.AUTH_SCHEMES, authSchemes()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java index 9895ae765031..c7932ab9f7c6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java @@ -53,13 +53,14 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner()); + }); } @Override @@ -69,7 +70,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -85,21 +86,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } @@ -167,8 +168,8 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java index 6013da8b2ea5..2eca7dfdcf2c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java @@ -64,15 +64,16 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner()); + }); } @Override @@ -82,82 +83,82 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); ServiceConfiguration.Builder serviceConfigBuilder = ((ServiceConfiguration) config - .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder - .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config - .option(SdkClientOption.PROFILE_NAME)); + .option(SdkClientOption.PROFILE_NAME)); if (serviceConfigBuilder.dualstackEnabled() != null) { Validate.validState( - config.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED) == null, - "Dualstack has been configured on both ServiceConfiguration and the client/global level. Please limit dualstack configuration to one location."); + config.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED) == null, + "Dualstack has been configured on both ServiceConfiguration and the client/global level. Please limit dualstack configuration to one location."); } else { serviceConfigBuilder.dualstackEnabled(config.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)); } if (serviceConfigBuilder.fipsModeEnabled() != null) { Validate.validState( - config.option(AwsClientOption.FIPS_ENDPOINT_ENABLED) == null, - "Fips has been configured on both ServiceConfiguration and the client/global level. Please limit fips configuration to one location."); + config.option(AwsClientOption.FIPS_ENDPOINT_ENABLED) == null, + "Fips has been configured on both ServiceConfiguration and the client/global level. Please limit fips configuration to one location."); } else { serviceConfigBuilder.fipsModeEnabled(config.option(AwsClientOption.FIPS_ENDPOINT_ENABLED)); } if (serviceConfigBuilder.useArnRegionEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.USE_ARN_REGION) == null, - "UseArnRegion has been configured on both ServiceConfiguration and the client/global level. Please limit UseArnRegion configuration to one location."); + clientContextParams.get(JsonClientContextParams.USE_ARN_REGION) == null, + "UseArnRegion has been configured on both ServiceConfiguration and the client/global level. Please limit UseArnRegion configuration to one location."); } else { serviceConfigBuilder.useArnRegionEnabled(clientContextParams.get(JsonClientContextParams.USE_ARN_REGION)); } if (serviceConfigBuilder.multiRegionEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS) == null, - "DisableMultiRegionAccessPoints has been configured on both ServiceConfiguration and the client/global level. Please limit DisableMultiRegionAccessPoints configuration to one location."); + clientContextParams.get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS) == null, + "DisableMultiRegionAccessPoints has been configured on both ServiceConfiguration and the client/global level. Please limit DisableMultiRegionAccessPoints configuration to one location."); } else if (clientContextParams.get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS) != null) { serviceConfigBuilder.multiRegionEnabled(!clientContextParams - .get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS)); + .get(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS)); } if (serviceConfigBuilder.pathStyleAccessEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.FORCE_PATH_STYLE) == null, - "ForcePathStyle has been configured on both ServiceConfiguration and the client/global level. Please limit ForcePathStyle configuration to one location."); + clientContextParams.get(JsonClientContextParams.FORCE_PATH_STYLE) == null, + "ForcePathStyle has been configured on both ServiceConfiguration and the client/global level. Please limit ForcePathStyle configuration to one location."); } else { serviceConfigBuilder.pathStyleAccessEnabled(clientContextParams.get(JsonClientContextParams.FORCE_PATH_STYLE)); } if (serviceConfigBuilder.accelerateModeEnabled() != null) { Validate.validState( - clientContextParams.get(JsonClientContextParams.ACCELERATE) == null, - "Accelerate has been configured on both ServiceConfiguration and the client/global level. Please limit Accelerate configuration to one location."); + clientContextParams.get(JsonClientContextParams.ACCELERATE) == null, + "Accelerate has been configured on both ServiceConfiguration and the client/global level. Please limit Accelerate configuration to one location."); } else { serviceConfigBuilder.accelerateModeEnabled(clientContextParams.get(JsonClientContextParams.ACCELERATE)); } Boolean checksumValidationEnabled = serviceConfigBuilder.checksumValidationEnabled(); if (checksumValidationEnabled != null) { Validate.validState( - config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION) == null, - "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); + config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION) == null, + "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); Validate.validState( - config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION) == null, - "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); + config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION) == null, + "Checksum behavior has been configured on both ServiceConfiguration and the client/global level. Please limit checksum behavior configuration to one location."); if (checksumValidationEnabled) { config = config.toBuilder() - .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_SUPPORTED) - .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_SUPPORTED).build(); + .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_SUPPORTED) + .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_SUPPORTED).build(); } else { config = config.toBuilder() - .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_REQUIRED) - .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_REQUIRED).build(); + .option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation.WHEN_REQUIRED) + .option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation.WHEN_REQUIRED).build(); } } ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); clientContextParams.put(JsonClientContextParams.USE_ARN_REGION, finalServiceConfig.useArnRegionEnabled()); clientContextParams.put(JsonClientContextParams.DISABLE_MULTI_REGION_ACCESS_POINTS, - !finalServiceConfig.multiRegionEnabled()); + !finalServiceConfig.multiRegionEnabled()); clientContextParams.put(JsonClientContextParams.FORCE_PATH_STYLE, finalServiceConfig.pathStyleAccessEnabled()); clientContextParams.put(JsonClientContextParams.ACCELERATE, finalServiceConfig.accelerateModeEnabled()); SdkClientConfiguration.Builder builder = config.toBuilder(); @@ -182,21 +183,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon } builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); @@ -301,9 +302,9 @@ private RequestChecksumCalculation resolveRequestChecksumCalculation(SdkClientCo RequestChecksumCalculation configuredChecksumCalculation = config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION); if (configuredChecksumCalculation == null) { configuredChecksumCalculation = RequestChecksumCalculationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); } return configuredChecksumCalculation; } @@ -312,19 +313,19 @@ private ResponseChecksumValidation resolveResponseChecksumValidation(SdkClientCo ResponseChecksumValidation configuredChecksumValidation = config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION); if (configuredChecksumValidation == null) { configuredChecksumValidation = ResponseChecksumValidationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); } return configuredChecksumValidation; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java index 52c27dfcc8ac..4a8a346f1c76 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java @@ -61,14 +61,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner()); + }); } @Override diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java index 12dec5b9986d..4f1e5bbd8e0d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java @@ -50,9 +50,11 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override @@ -70,7 +72,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -86,21 +88,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } @@ -164,6 +166,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java index 52f9d10e821f..778b676c4975 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java @@ -59,15 +59,16 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .option(SdkClientOption.SERVICE_CONFIGURATION, ServiceConfiguration.builder().build()) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner()); + }); } @Override @@ -77,17 +78,17 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new JsonRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/json/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); interceptors = CollectionUtils.mergeLists(interceptors, config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); ServiceConfiguration.Builder serviceConfigBuilder = ((ServiceConfiguration) config - .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + .option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); serviceConfigBuilder.profileFile(serviceConfigBuilder.profileFileSupplier() != null ? serviceConfigBuilder - .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); + .profileFileSupplier() : config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)); serviceConfigBuilder.profileName(serviceConfigBuilder.profileName() != null ? serviceConfigBuilder.profileName() : config - .option(SdkClientOption.PROFILE_NAME)); + .option(SdkClientOption.PROFILE_NAME)); ServiceConfiguration finalServiceConfig = serviceConfigBuilder.build(); SdkClientConfiguration.Builder builder = config.toBuilder(); builder.lazyOption(SdkClientOption.IDENTITY_PROVIDERS, c -> { @@ -105,21 +106,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") + .serviceProfileProperty("json_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); @@ -220,9 +221,9 @@ private RequestChecksumCalculation resolveRequestChecksumCalculation(SdkClientCo RequestChecksumCalculation configuredChecksumCalculation = config.option(SdkClientOption.REQUEST_CHECKSUM_CALCULATION); if (configuredChecksumCalculation == null) { configuredChecksumCalculation = RequestChecksumCalculationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumCalculation(RequestChecksumCalculation.WHEN_SUPPORTED).resolve(); } return configuredChecksumCalculation; } @@ -231,19 +232,19 @@ private ResponseChecksumValidation resolveResponseChecksumValidation(SdkClientCo ResponseChecksumValidation configuredChecksumValidation = config.option(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION); if (configuredChecksumValidation == null) { configuredChecksumValidation = ResponseChecksumValidationResolver.create() - .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.option(SdkClientOption.PROFILE_NAME)) - .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); + .profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(config.option(SdkClientOption.PROFILE_NAME)) + .defaultChecksumValidation(ResponseChecksumValidation.WHEN_SUPPORTED).resolve(); } return configuredChecksumValidation; } protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(SdkAdvancedClientOption.TOKEN_SIGNER), - "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[TOKEN_SIGNER]' must be configured in the client builder."); Validate.notNull(c.option(AwsClientOption.TOKEN_IDENTITY_PROVIDER), - "The 'tokenProvider' must be configured in the client builder."); + "The 'tokenProvider' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java index ddd2b3427e71..eb724ba82245 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java @@ -54,9 +54,11 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override @@ -66,7 +68,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new H2RequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/h2/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/h2/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -82,21 +84,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2") - .serviceProfileProperty("h2_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2") + .serviceProfileProperty("h2_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } @@ -118,7 +120,7 @@ private H2EndpointProvider defaultEndpointProvider() { protected final AttributeMap serviceHttpConfig() { AttributeMap result = AttributeMap.empty(); return result.merge(AttributeMap.builder().put(SdkHttpConfigurationOption.PROTOCOL, Protocol.HTTP2) - .put(SdkHttpConfigurationOption.PROTOCOL_NEGOTIATION, ProtocolNegotiation.ALPN).build()); + .put(SdkHttpConfigurationOption.PROTOCOL_NEGOTIATION, ProtocolNegotiation.ALPN).build()); } @Override @@ -167,6 +169,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java index a296652d9b41..a9dcec96847e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java @@ -53,9 +53,11 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override @@ -65,7 +67,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new H2RequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/h2/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/h2/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -81,21 +83,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2") - .serviceProfileProperty("h2_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2") + .serviceProfileProperty("h2_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } @@ -165,6 +167,6 @@ private List internalPlugins(SdkClientConfiguration config) { protected static void validateClientOptions(SdkClientConfiguration c) { Validate.notNull(c.option(SdkAdvancedClientOption.SIGNER), - "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); + "The 'overrideConfiguration.advancedOption[SIGNER]' must be configured in the client builder."); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java index 4671c2e583e7..5ec8c0facf9a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java @@ -42,7 +42,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { @Override protected final String serviceEndpointPrefix() { return "database-service-endpoint"; @@ -55,14 +55,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner()); + }); } @Override @@ -92,21 +93,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } @@ -142,7 +143,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java index a5aedee94c63..6a8e2290d918 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java @@ -33,7 +33,7 @@ @Generated("software.amazon.awssdk:codegen") @SdkInternalApi abstract class DefaultDatabaseBaseClientBuilder, C> extends - AwsDefaultClientBuilder { + AwsDefaultClientBuilder { @Override protected final String serviceEndpointPrefix() { return "database-service-endpoint"; @@ -46,8 +46,10 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()).option( - SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false)); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()).option( + SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false); + }); } @Override @@ -57,7 +59,7 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon endpointInterceptors.add(new DatabaseRequestSetEndpointInterceptor()); ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); List interceptors = interceptorFactory - .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); + .getInterceptors("software/amazon/awssdk/services/database/execution.interceptors"); List additionalInterceptors = new ArrayList<>(); interceptors = CollectionUtils.mergeLists(endpointInterceptors, interceptors); interceptors = CollectionUtils.mergeLists(interceptors, additionalInterceptors); @@ -69,21 +71,21 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon }); builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( - SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + SdkClientOption.CLIENT_ENDPOINT_PROVIDER, + c -> AwsClientEndpointProvider + .builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service") + .serviceEndpointPrefix(serviceEndpointPrefix()) + .defaultProtocol("https") + .region(c.get(AwsClientOption.AWS_REGION)) + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)) + .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, + c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) + .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } @@ -107,7 +109,7 @@ protected SdkClientConfiguration invokePlugins(SdkClientConfiguration config) { List plugins = CollectionUtils.mergeLists(internalPlugins, externalPlugins); SdkClientConfiguration.Builder configuration = config.toBuilder(); DatabaseServiceClientConfigurationBuilder serviceConfigBuilder = new DatabaseServiceClientConfigurationBuilder( - configuration); + configuration); for (SdkPlugin plugin : plugins) { plugin.configureClient(serviceConfigBuilder); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java index df04abcb8bef..2ef919b3671f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java @@ -60,14 +60,15 @@ protected final String serviceName() { @Override protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) { - return config.merge(c -> c - .option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) - .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) - .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) - .lazyOption(AwsClientOption.TOKEN_PROVIDER, - p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) - .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) - .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner())); + return config.merge(c -> { + c.option(SdkClientOption.ENDPOINT_PROVIDER, defaultEndpointProvider()) + .option(SdkAdvancedClientOption.SIGNER, defaultSigner()) + .option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false) + .lazyOption(AwsClientOption.TOKEN_PROVIDER, + p -> TokenUtils.toSdkTokenProvider(p.get(AwsClientOption.TOKEN_IDENTITY_PROVIDER))) + .option(AwsClientOption.TOKEN_IDENTITY_PROVIDER, defaultTokenProvider()) + .option(SdkAdvancedClientOption.TOKEN_SIGNER, defaultTokenSigner()); + }); } @Override From 8ecc9dced3e42e0e8a41f421a0c1f95e8b2a6032 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 5 Jun 2025 09:36:45 -0700 Subject: [PATCH 50/53] Fix checkstyle --- .../awssdk/awscore/internal/AwsExecutionContextBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 060b7ef0adb4..b4a2b17bc048 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 @@ -68,7 +68,7 @@ private AwsExecutionContextBuilder() { * Used by both sync and async clients to create the execution context, and run initial interceptors. */ public static ExecutionContext - invokeInterceptorsAndCreateExecutionContext(ClientExecutionParams executionParams, + invokeInterceptorsAndCreateExecutionContext(ClientExecutionParams executionParams, SdkClientConfiguration clientConfig) { // Note: This is currently copied to DefaultS3Presigner and other presigners. // Don't edit this without considering those From 23c5b58a2e90c62df2f0093f1c8dbbae78f1e368 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 5 Jun 2025 10:01:19 -0700 Subject: [PATCH 51/53] Fix checkstyle --- .../interceptor/SdkInternalExecutionAttribute.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java index 08276be11d16..37ecf5ce3576 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java @@ -189,6 +189,12 @@ public final class SdkInternalExecutionAttribute extends SdkExecutionAttribute { public static final ExecutionAttribute RESPONSE_CHECKSUM_VALIDATION = new ExecutionAttribute<>( "ResponseChecksumValidation"); + /** + * The response checksum validation setting. + */ + public static final ExecutionAttribute TOKEN_CONFIGURED_FROM_ENV = new ExecutionAttribute<>( + "TokenConfiguredFromEnv"); + /** * The backing attribute for RESOLVED_CHECKSUM_SPECS. * This holds the real ChecksumSpecs value, and is used to map to the ChecksumAlgorithm signer property @@ -197,12 +203,6 @@ public final class SdkInternalExecutionAttribute extends SdkExecutionAttribute { static final ExecutionAttribute INTERNAL_RESOLVED_CHECKSUM_SPECS = new ExecutionAttribute<>("InternalResolvedChecksumSpecs"); - /** - * The response checksum validation setting. - */ - public static final ExecutionAttribute TOKEN_CONFIGURED_FROM_ENV = new ExecutionAttribute<>( - "TokenConfiguredFromEnv"); - private SdkInternalExecutionAttribute() { } } From fec46b0d5362918f657714c8380e97cb07de5580 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 5 Jun 2025 10:11:01 -0700 Subject: [PATCH 52/53] Improve test coverage --- .../awssdk/codegen/poet/PoetExtension.java | 4 - .../poet/auth/scheme/AuthSchemeSpecTest.java | 7 + ...-bearer-token-auth-scheme-interceptor.java | 164 ++++++++++++++++++ 3 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/env-bearer-token-auth-scheme-interceptor.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java index c450111b4fe7..4112188c6451 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/PoetExtension.java @@ -79,10 +79,6 @@ public ClassName getUserAgentClass() { return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "UserAgentUtils"); } - public ClassName getEnvironmentTokenMetricsInterceptorClass() { - return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "EnvironmentTokenMetricsInterceptor"); - } - public ClassName getEnvironmentTokenSystemSettingsClass() { return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "EnvironmentTokenSystemSettings"); } diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java index 533dbe8a46ad..3e2807600928 100644 --- a/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeSpecTest.java @@ -220,6 +220,13 @@ static List parameters() { .classSpecProvider(AuthSchemeInterceptorSpec::new) .caseName("ops-auth-sigv4a-value") .outputFileSuffix("interceptor") + .build(), + // service with environment bearer token enabled + TestCase.builder() + .modelProvider(ClientTestModels::envBearerTokenServiceModels) + .classSpecProvider(AuthSchemeInterceptorSpec::new) + .caseName("env-bearer-token") + .outputFileSuffix("interceptor") .build() ); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/env-bearer-token-auth-scheme-interceptor.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/env-bearer-token-auth-scheme-interceptor.java new file mode 100644 index 000000000000..a7f8a8e8d336 --- /dev/null +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/env-bearer-token-auth-scheme-interceptor.java @@ -0,0 +1,164 @@ +package software.amazon.awssdk.services.json.auth.scheme.internal; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.SelectedAuthScheme; +import software.amazon.awssdk.core.exception.SdkException; +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.core.internal.util.MetricUtils; +import software.amazon.awssdk.core.metrics.CoreMetric; +import software.amazon.awssdk.core.useragent.BusinessMetricFeatureId; +import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; +import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; +import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption; +import software.amazon.awssdk.http.auth.spi.signer.HttpSigner; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.Identity; +import software.amazon.awssdk.identity.spi.IdentityProvider; +import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.identity.spi.ResolveIdentityRequest; +import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.SdkMetric; +import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeParams; +import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; +import software.amazon.awssdk.utils.Logger; +import software.amazon.awssdk.utils.Validate; + +@Generated("software.amazon.awssdk:codegen") +@SdkInternalApi +public final class JsonAuthSchemeInterceptor implements ExecutionInterceptor { + private static Logger LOG = Logger.loggerFor(JsonAuthSchemeInterceptor.class); + + @Override + public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { + List authOptions = resolveAuthOptions(context, executionAttributes); + SelectedAuthScheme selectedAuthScheme = selectAuthScheme(authOptions, executionAttributes); + putSelectedAuthScheme(executionAttributes, selectedAuthScheme); + recordEnvironmentTokenBusinessMetric(selectedAuthScheme, executionAttributes); + } + + private List resolveAuthOptions(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { + JsonAuthSchemeProvider authSchemeProvider = Validate.isInstanceOf(JsonAuthSchemeProvider.class, + executionAttributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEME_RESOLVER), + "Expected an instance of JsonAuthSchemeProvider"); + JsonAuthSchemeParams params = authSchemeParams(context.request(), executionAttributes); + return authSchemeProvider.resolveAuthScheme(params); + } + + private SelectedAuthScheme selectAuthScheme(List authOptions, + ExecutionAttributes executionAttributes) { + MetricCollector metricCollector = executionAttributes.getAttribute(SdkExecutionAttribute.API_CALL_METRIC_COLLECTOR); + Map> authSchemes = executionAttributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES); + IdentityProviders identityProviders = executionAttributes.getAttribute(SdkInternalExecutionAttribute.IDENTITY_PROVIDERS); + List> discardedReasons = new ArrayList<>(); + for (AuthSchemeOption authOption : authOptions) { + AuthScheme authScheme = authSchemes.get(authOption.schemeId()); + SelectedAuthScheme selectedAuthScheme = trySelectAuthScheme(authOption, authScheme, + identityProviders, discardedReasons, metricCollector, executionAttributes); + if (selectedAuthScheme != null) { + if (!discardedReasons.isEmpty()) { + LOG.debug(() -> String.format("%s auth will be used, discarded: '%s'", authOption.schemeId(), + discardedReasons.stream().map(Supplier::get).collect(Collectors.joining(", ")))); + } + return selectedAuthScheme; + } + } + throw SdkException + .builder() + .message( + "Failed to determine how to authenticate the user: " + + discardedReasons.stream().map(Supplier::get).collect(Collectors.joining(", "))).build(); + } + + private JsonAuthSchemeParams authSchemeParams(SdkRequest request, ExecutionAttributes executionAttributes) { + String operation = executionAttributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME); + JsonAuthSchemeParams.Builder builder = JsonAuthSchemeParams.builder().operation(operation); + return builder.build(); + } + + private SelectedAuthScheme trySelectAuthScheme(AuthSchemeOption authOption, AuthScheme authScheme, + IdentityProviders identityProviders, List> discardedReasons, MetricCollector metricCollector, + ExecutionAttributes executionAttributes) { + if (authScheme == null) { + discardedReasons.add(() -> String.format("'%s' is not enabled for this request.", authOption.schemeId())); + return null; + } + IdentityProvider identityProvider = authScheme.identityProvider(identityProviders); + if (identityProvider == null) { + discardedReasons + .add(() -> String.format("'%s' does not have an identity provider configured.", authOption.schemeId())); + return null; + } + HttpSigner signer; + try { + signer = authScheme.signer(); + } catch (RuntimeException e) { + discardedReasons.add(() -> String.format("'%s' signer could not be retrieved: %s", authOption.schemeId(), + e.getMessage())); + return null; + } + ResolveIdentityRequest.Builder identityRequestBuilder = ResolveIdentityRequest.builder(); + authOption.forEachIdentityProperty(identityRequestBuilder::putProperty); + CompletableFuture identity; + SdkMetric metric = getIdentityMetric(identityProvider); + if (metric == null) { + identity = identityProvider.resolveIdentity(identityRequestBuilder.build()); + } else { + identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()), + metricCollector, metric); + } + return new SelectedAuthScheme<>(identity, signer, authOption); + } + + private SdkMetric getIdentityMetric(IdentityProvider identityProvider) { + Class identityType = identityProvider.identityType(); + if (identityType == AwsCredentialsIdentity.class) { + return CoreMetric.CREDENTIALS_FETCH_DURATION; + } + if (identityType == TokenIdentity.class) { + return CoreMetric.TOKEN_FETCH_DURATION; + } + return null; + } + + private void putSelectedAuthScheme(ExecutionAttributes attributes, + SelectedAuthScheme selectedAuthScheme) { + SelectedAuthScheme existingAuthScheme = attributes.getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME); + if (existingAuthScheme != null) { + AuthSchemeOption.Builder selectedOption = selectedAuthScheme.authSchemeOption().toBuilder(); + existingAuthScheme.authSchemeOption().forEachIdentityProperty(selectedOption::putIdentityPropertyIfAbsent); + existingAuthScheme.authSchemeOption().forEachSignerProperty(selectedOption::putSignerPropertyIfAbsent); + selectedAuthScheme = new SelectedAuthScheme<>(selectedAuthScheme.identity(), selectedAuthScheme.signer(), + selectedOption.build()); + } + attributes.putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedAuthScheme); + } + + private void recordEnvironmentTokenBusinessMetric(SelectedAuthScheme selectedAuthScheme, + ExecutionAttributes executionAttributes) { + String tokenFromEnv = executionAttributes.getAttribute(SdkInternalExecutionAttribute.TOKEN_CONFIGURED_FROM_ENV); + if (selectedAuthScheme != null && selectedAuthScheme.authSchemeOption().schemeId().equals(BearerAuthScheme.SCHEME_ID) + && selectedAuthScheme.identity().isDone()) { + if (selectedAuthScheme.identity().getNow(null) instanceof TokenIdentity) { + TokenIdentity configuredToken = (TokenIdentity) selectedAuthScheme.identity().getNow(null); + if (configuredToken.token().equals(tokenFromEnv)) { + executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( + BusinessMetricFeatureId.BEARER_SERVICE_ENV_VARS.value()); + } + } + } + } +} From a1a3c20433b304c06575d6ebb8cb4aeb3cd6c476 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 6 Jun 2025 10:51:32 -0700 Subject: [PATCH 53/53] Fix docs --- .../awssdk/core/interceptor/SdkInternalExecutionAttribute.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java index 37ecf5ce3576..f875836a1422 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkInternalExecutionAttribute.java @@ -190,7 +190,8 @@ public final class SdkInternalExecutionAttribute extends SdkExecutionAttribute { "ResponseChecksumValidation"); /** - * The response checksum validation setting. + * The token configured from the environment or system properties, used to determine if the BEARER_SERVICE_ENV_VARS + * business metric should be set. */ public static final ExecutionAttribute TOKEN_CONFIGURED_FROM_ENV = new ExecutionAttribute<>( "TokenConfiguredFromEnv");