diff --git a/.brazil.json b/.brazil.json index 9d9a3f897c06..e554078b10e0 100644 --- a/.brazil.json +++ b/.brazil.json @@ -101,7 +101,8 @@ "test-utils": { "skipImport": true }, "tests-coverage-reporting": { "skipImport": true }, "third-party": { "skipImport": true }, - "third-party-slf4j-api": { "skipImport": true } + "third-party-slf4j-api": { "skipImport": true }, + "crt-unavailable-tests": { "skipImport": true } }, "dependencies": { diff --git a/buildspecs/release-javadoc.yml b/buildspecs/release-javadoc.yml index a5dc4b3157d4..62132efd1cca 100644 --- a/buildspecs/release-javadoc.yml +++ b/buildspecs/release-javadoc.yml @@ -18,7 +18,7 @@ phases: commands: - python ./scripts/doc_crosslinks/generate_cross_link_data.py --apiDefinitionsBasePath ./services/ --apiDefinitionsRelativeFilePath src/main/resources/codegen-resources/service-2.json --templateFilePath ./scripts/doc_crosslinks/crosslink_redirect.html --outputFilePath ./scripts/crosslink_redirect.html - mvn install -P quick -T1C - - mvn clean install javadoc:aggregate -B -Ppublic-javadoc -Dcheckstyle.skip -Dspotbugs.skip -DskipTests -Ddoclint=none -pl '!:protocol-tests,!:protocol-tests-core,!:codegen-generated-classes-test,!:sdk-benchmarks,!:s3-benchmarks,!:module-path-tests,!:test-utils,!:http-client-tests,!:tests-coverage-reporting,!:sdk-native-image-test,!:ruleset-testing-core,!:old-client-version-compatibility-test' + - mvn clean install javadoc:aggregate -B -Ppublic-javadoc -Dcheckstyle.skip -Dspotbugs.skip -DskipTests -Ddoclint=none -pl '!:protocol-tests,!:protocol-tests-core,!:codegen-generated-classes-test,!:sdk-benchmarks,!:s3-benchmarks,!:module-path-tests,!:test-utils,!:http-client-tests,!:tests-coverage-reporting,!:sdk-native-image-test,!:ruleset-testing-core,!:old-client-version-compatibility-test,!:crt-unavailable-tests' - RELEASE_VERSION=`mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec` - - aws s3 sync target/site/apidocs/ $DOC_PATH/$RELEASE_VERSION/ --acl="public-read" diff --git a/buildspecs/release-to-maven.yml b/buildspecs/release-to-maven.yml index 66a9fcde6525..061b1737de35 100644 --- a/buildspecs/release-to-maven.yml +++ b/buildspecs/release-to-maven.yml @@ -34,7 +34,7 @@ phases: awk 'BEGIN { var=ENVIRON["SDK_SIGNING_GPG_KEYNAME"] } { gsub("\\$SDK_SIGNING_GPG_KEYNAME", var, $0); print }' > \ $SETTINGS_XML - mvn clean deploy -B -s $SETTINGS_XML -Ppublishing -DperformRelease -Dspotbugs.skip -DskipTests -Dcheckstyle.skip -Djapicmp.skip -Ddoclint=none -pl !:protocol-tests,!:protocol-tests-core,!:codegen-generated-classes-test,!:sdk-benchmarks,!:module-path-tests,!:tests-coverage-reporting,!:stability-tests,!:sdk-native-image-test,!:auth-tests,!:s3-benchmarks,!:region-testing,!:old-client-version-compatibility-test -DautoReleaseAfterClose=true -DstagingProgressTimeoutMinutes=30 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true + mvn clean deploy -B -s $SETTINGS_XML -Ppublishing -DperformRelease -Dspotbugs.skip -DskipTests -Dcheckstyle.skip -Djapicmp.skip -Ddoclint=none -pl !:protocol-tests,!:protocol-tests-core,!:codegen-generated-classes-test,!:sdk-benchmarks,!:module-path-tests,!:tests-coverage-reporting,!:stability-tests,!:sdk-native-image-test,!:auth-tests,!:s3-benchmarks,!:region-testing,!:old-client-version-compatibility-test,!:crt-unavailable-tests -DautoReleaseAfterClose=true -DstagingProgressTimeoutMinutes=30 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true else echo "This version was already released." fi 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 026e91a36742..6ab69cb24a92 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 @@ -52,6 +52,7 @@ import software.amazon.awssdk.endpoints.EndpointProvider; 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; @@ -274,6 +275,19 @@ private MethodSpec generateTrySelectAuthScheme() { .endControlFlow(); } + builder.addStatement("$T signer", + ParameterizedTypeName.get(ClassName.get(HttpSigner.class), TypeVariableName.get("T"))); + builder.beginControlFlow("try"); + { + builder.addStatement("signer = authScheme.signer()"); + builder.nextControlFlow("catch (RuntimeException e)"); + builder.addStatement("discardedReasons.add(() -> String.format($S, authOption.schemeId(), e.getMessage()))", + "'%s' signer could not be retrieved: %s") + .addStatement("return null") + .endControlFlow(); + } + + builder.addStatement("$T.Builder identityRequestBuilder = $T.builder()", ResolveIdentityRequest.class, ResolveIdentityRequest.class); @@ -294,7 +308,7 @@ private MethodSpec generateTrySelectAuthScheme() { MetricUtils.class) .endControlFlow(); - builder.addStatement("return new $T<>(identity, authScheme.signer(), authOption)", SelectedAuthScheme.class); + builder.addStatement("return new $T<>(identity, signer, authOption)", SelectedAuthScheme.class); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-interceptor.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-interceptor.java index be41e3e83869..48edb00b1855 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-interceptor.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-interceptor.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.core.metrics.CoreMetric; 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; @@ -100,6 +101,14 @@ private SelectedAuthScheme trySelectAuthScheme(AuthSchem .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; @@ -110,7 +119,7 @@ private SelectedAuthScheme trySelectAuthScheme(AuthSchem identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()), metricCollector, metric); } - return new SelectedAuthScheme<>(identity, authScheme.signer(), authOption); + return new SelectedAuthScheme<>(identity, signer, authOption); } private SdkMetric getIdentityMetric(IdentityProvider identityProvider) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-with-allowlist-auth-scheme-interceptor.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-with-allowlist-auth-scheme-interceptor.java index aee41328cd1f..942aa43d9aee 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-with-allowlist-auth-scheme-interceptor.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-with-allowlist-auth-scheme-interceptor.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.endpoints.EndpointProvider; 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; @@ -117,6 +118,14 @@ private SelectedAuthScheme trySelectAuthScheme(AuthSchem .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; @@ -127,7 +136,7 @@ private SelectedAuthScheme trySelectAuthScheme(AuthSchem identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()), metricCollector, metric); } - return new SelectedAuthScheme<>(identity, authScheme.signer(), authOption); + return new SelectedAuthScheme<>(identity, signer, authOption); } private SdkMetric getIdentityMetric(IdentityProvider identityProvider) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-without-allowlist-auth-scheme-interceptor.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-without-allowlist-auth-scheme-interceptor.java index f95cc1366cd3..3c48c7bd907d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-without-allowlist-auth-scheme-interceptor.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-without-allowlist-auth-scheme-interceptor.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.endpoints.EndpointProvider; 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; @@ -120,6 +121,14 @@ private SelectedAuthScheme trySelectAuthScheme(AuthSchem .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; @@ -130,7 +139,7 @@ private SelectedAuthScheme trySelectAuthScheme(AuthSchem identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()), metricCollector, metric); } - return new SelectedAuthScheme<>(identity, authScheme.signer(), authOption); + return new SelectedAuthScheme<>(identity, signer, authOption); } private SdkMetric getIdentityMetric(IdentityProvider identityProvider) { diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/scheme/DefaultAwsV4aAuthScheme.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/scheme/DefaultAwsV4aAuthScheme.java index 8be2e8c43e80..b00574dac8ae 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/scheme/DefaultAwsV4aAuthScheme.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/scheme/DefaultAwsV4aAuthScheme.java @@ -52,10 +52,27 @@ public IdentityProvider identityProvider(IdentityProvide */ @Override public AwsV4aHttpSigner signer() { + if (SignerSingletonHolder.ERROR != null) { + throw SignerSingletonHolder.ERROR; + } return SignerSingletonHolder.INSTANCE; } private static class SignerSingletonHolder { - private static final AwsV4aHttpSigner INSTANCE = AwsV4aHttpSigner.create(); + private static final AwsV4aHttpSigner INSTANCE; + private static final RuntimeException ERROR; + + // Attempt to load the Sigv4a signer and cache the error if CRT is not available on the classpath. + static { + AwsV4aHttpSigner instance = null; + RuntimeException error = null; + try { + instance = AwsV4aHttpSigner.create(); + } catch (RuntimeException e) { + error = e; + } + INSTANCE = instance; + ERROR = error; + } } } diff --git a/pom.xml b/pom.xml index 43c40388727a..7d6fb5c04211 100644 --- a/pom.xml +++ b/pom.xml @@ -88,6 +88,7 @@ test/ruleset-testing-core test/old-client-version-compatibility-test test/bundle-logging-bridge-binding-test + test/crt-unavailable-tests ${scm.github.url} diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/AuthSchemeInterceptorTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/AuthSchemeInterceptorTest.java new file mode 100644 index 000000000000..e187ab4435d5 --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/AuthSchemeInterceptorTest.java @@ -0,0 +1,108 @@ +/* + * 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 static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +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.SdkExecutionAttribute; +import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; +import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; +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.IdentityProvider; +import software.amazon.awssdk.identity.spi.IdentityProviders; +import software.amazon.awssdk.services.protocolrestjson.auth.scheme.ProtocolRestJsonAuthSchemeParams; +import software.amazon.awssdk.services.protocolrestjson.auth.scheme.ProtocolRestJsonAuthSchemeProvider; +import software.amazon.awssdk.services.protocolrestjson.auth.scheme.internal.ProtocolRestJsonAuthSchemeInterceptor; + +public class AuthSchemeInterceptorTest { + private static final ProtocolRestJsonAuthSchemeInterceptor INTERCEPTOR = new ProtocolRestJsonAuthSchemeInterceptor(); + + private Context.BeforeExecution mockContext; + + @BeforeEach + public void setup() { + mockContext = mock(Context.BeforeExecution.class); + } + + @Test + public void resolveAuthScheme_authSchemeSignerThrows_continuesToNextAuthScheme() { + ProtocolRestJsonAuthSchemeProvider mockAuthSchemeProvider = mock(ProtocolRestJsonAuthSchemeProvider.class); + List authSchemeOptions = Arrays.asList( + AuthSchemeOption.builder().schemeId(TestAuthScheme.SCHEME_ID).build(), + AuthSchemeOption.builder().schemeId(AwsV4AuthScheme.SCHEME_ID).build() + ); + when(mockAuthSchemeProvider.resolveAuthScheme(any(ProtocolRestJsonAuthSchemeParams.class))).thenReturn(authSchemeOptions); + + IdentityProviders mockIdentityProviders = mock(IdentityProviders.class); + when(mockIdentityProviders.identityProvider(any(Class.class))).thenReturn(AnonymousCredentialsProvider.create()); + + Map> authSchemes = new HashMap<>(); + authSchemes.put(AwsV4AuthScheme.SCHEME_ID, AwsV4AuthScheme.create()); + + TestAuthScheme notProvidedAuthScheme = spy(new TestAuthScheme()); + authSchemes.put(TestAuthScheme.SCHEME_ID, notProvidedAuthScheme); + + ExecutionAttributes attributes = new ExecutionAttributes(); + attributes.putAttribute(SdkExecutionAttribute.OPERATION_NAME, "GetFoo"); + attributes.putAttribute(SdkInternalExecutionAttribute.AUTH_SCHEME_RESOLVER, mockAuthSchemeProvider); + attributes.putAttribute(SdkInternalExecutionAttribute.IDENTITY_PROVIDERS, mockIdentityProviders); + attributes.putAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES, authSchemes); + + INTERCEPTOR.beforeExecution(mockContext, attributes); + + SelectedAuthScheme selectedAuthScheme = attributes.getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME); + + verify(notProvidedAuthScheme).signer(); + assertThat(selectedAuthScheme.authSchemeOption().schemeId()).isEqualTo(AwsV4AuthScheme.SCHEME_ID); + } + + private static class TestAuthScheme implements AuthScheme { + public static final String SCHEME_ID = "codegen-test-scheme"; + + @Override + public String schemeId() { + return SCHEME_ID; + } + + @Override + public IdentityProvider identityProvider(IdentityProviders providers) { + return providers.identityProvider(AwsCredentialsIdentity.class); + } + + @Override + public HttpSigner signer() { + throw new RuntimeException("Not on classpath"); + } + } +} diff --git a/test/crt-unavailable-tests/pom.xml b/test/crt-unavailable-tests/pom.xml new file mode 100644 index 000000000000..3d9df73be489 --- /dev/null +++ b/test/crt-unavailable-tests/pom.xml @@ -0,0 +1,92 @@ + + + + + + aws-sdk-java-pom + software.amazon.awssdk + 2.24.8-SNAPSHOT + ../../pom.xml + + 4.0.0 + + crt-unavailable-tests + AWS Java SDK :: Test :: Crt Unavailable Tests + Test package for testing components that use CRT when CRT is not on the classpath. + + + + software.amazon.awssdk + bom-internal + ${project.version} + pom + import + + + + + + + software.amazon.awssdk + http-auth-aws + ${awsjavasdk.version} + test + + + org.assertj + assertj-core + test + + + org.hamcrest + hamcrest-all + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.vintage + junit-vintage-engine + test + + + com.github.tomakehurst + wiremock-jre8 + test + + + org.apache.logging.log4j + log4j-api + test + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + + diff --git a/test/crt-unavailable-tests/src/test/java/software/amazon/awssdk/auth/aws/AwsV4aAuthSchemeTest.java b/test/crt-unavailable-tests/src/test/java/software/amazon/awssdk/auth/aws/AwsV4aAuthSchemeTest.java new file mode 100644 index 000000000000..ba407ce64bc4 --- /dev/null +++ b/test/crt-unavailable-tests/src/test/java/software/amazon/awssdk/auth/aws/AwsV4aAuthSchemeTest.java @@ -0,0 +1,28 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.auth.aws; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.http.auth.aws.scheme.AwsV4aAuthScheme; + +public class AwsV4aAuthSchemeTest { + @Test + public void signer_throwsRuntimeException() { + assertThatThrownBy(AwsV4aAuthScheme.create()::signer).hasMessageContaining("Could not load class"); + } +}