Skip to content

Commit 2bac2f4

Browse files
committed
Choose next potential scheme if signer not found
This commit fixes the generated auth scheme selection mechanism by ensuring that auth scheme is able to provide a signer implementation (i.e. does not throw an exception) before selecting the auth scheme. This is useful in situations where the signer implementation relies on components thay may not be available at runtime, such as the AwsV4aAuthScheme, which relies on CRT which is an optional dependency. Additional changes: - introduce crt-unavailable-tests which is a good candidate for testing behavior of components that use CRT when CRT is not present. - modify DefaultAwsV4aAuthScheme so that errors thrown during static initialization of the singleton holder for the Sigv4a signer are caught and thrown directly instead of resulting in ExceptionInInitializerError
1 parent 7936d57 commit 2bac2f4

File tree

13 files changed

+323
-8
lines changed

13 files changed

+323
-8
lines changed

.brazil.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@
101101
"test-utils": { "skipImport": true },
102102
"tests-coverage-reporting": { "skipImport": true },
103103
"third-party": { "skipImport": true },
104-
"third-party-slf4j-api": { "skipImport": true }
104+
"third-party-slf4j-api": { "skipImport": true },
105+
"crt-unavailable-tests": { "skipImport": true }
105106
},
106107

107108
"dependencies": {

buildspecs/release-javadoc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ phases:
1818
commands:
1919
- 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
2020
- mvn install -P quick -T1C
21-
- 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'
21+
- 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'
2222
- RELEASE_VERSION=`mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec`
2323
-
2424
- aws s3 sync target/site/apidocs/ $DOC_PATH/$RELEASE_VERSION/ --acl="public-read"

buildspecs/release-to-maven.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ phases:
3434
awk 'BEGIN { var=ENVIRON["SDK_SIGNING_GPG_KEYNAME"] } { gsub("\\$SDK_SIGNING_GPG_KEYNAME", var, $0); print }' > \
3535
$SETTINGS_XML
3636
37-
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
37+
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
3838
else
3939
echo "This version was already released."
4040
fi

codegen/src/main/java/software/amazon/awssdk/codegen/poet/auth/scheme/AuthSchemeInterceptorSpec.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import software.amazon.awssdk.endpoints.EndpointProvider;
5353
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
5454
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
55+
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
5556
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
5657
import software.amazon.awssdk.identity.spi.Identity;
5758
import software.amazon.awssdk.identity.spi.IdentityProvider;
@@ -274,6 +275,22 @@ private MethodSpec generateTrySelectAuthScheme() {
274275
.endControlFlow();
275276
}
276277

278+
builder.addStatement("$T signer",
279+
ParameterizedTypeName.get(ClassName.get(HttpSigner.class), TypeVariableName.get("T")));
280+
builder.beginControlFlow("try");
281+
{
282+
builder.addStatement("signer = authScheme.signer()");
283+
builder.endControlFlow();
284+
}
285+
builder.beginControlFlow("catch (RuntimeException e)");
286+
{
287+
builder.addStatement("discardedReasons.add(() -> String.format($S, authOption.schemeId(), e.getMessage()))",
288+
"'%s' signer could not be retrieved: %s")
289+
.addStatement("return null")
290+
.endControlFlow();
291+
}
292+
293+
277294
builder.addStatement("$T.Builder identityRequestBuilder = $T.builder()",
278295
ResolveIdentityRequest.class,
279296
ResolveIdentityRequest.class);
@@ -294,7 +311,7 @@ private MethodSpec generateTrySelectAuthScheme() {
294311
MetricUtils.class)
295312
.endControlFlow();
296313

297-
builder.addStatement("return new $T<>(identity, authScheme.signer(), authOption)", SelectedAuthScheme.class);
314+
builder.addStatement("return new $T<>(identity, signer, authOption)", SelectedAuthScheme.class);
298315
return builder.build();
299316
}
300317

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-auth-scheme-interceptor.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import software.amazon.awssdk.core.metrics.CoreMetric;
2323
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
2424
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
25+
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
2526
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
2627
import software.amazon.awssdk.identity.spi.Identity;
2728
import software.amazon.awssdk.identity.spi.IdentityProvider;
@@ -100,6 +101,14 @@ private <T extends Identity> SelectedAuthScheme<T> trySelectAuthScheme(AuthSchem
100101
.add(() -> String.format("'%s' does not have an identity provider configured.", authOption.schemeId()));
101102
return null;
102103
}
104+
HttpSigner<T> signer;
105+
try {
106+
signer = authScheme.signer();
107+
} catch (RuntimeException e) {
108+
discardedReasons.add(() -> String.format("'%s' signer could not be retrieved: %s", authOption.schemeId(),
109+
e.getMessage()));
110+
return null;
111+
}
103112
ResolveIdentityRequest.Builder identityRequestBuilder = ResolveIdentityRequest.builder();
104113
authOption.forEachIdentityProperty(identityRequestBuilder::putProperty);
105114
CompletableFuture<? extends T> identity;
@@ -110,7 +119,7 @@ private <T extends Identity> SelectedAuthScheme<T> trySelectAuthScheme(AuthSchem
110119
identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()),
111120
metricCollector, metric);
112121
}
113-
return new SelectedAuthScheme<>(identity, authScheme.signer(), authOption);
122+
return new SelectedAuthScheme<>(identity, signer, authOption);
114123
}
115124

116125
private SdkMetric<Duration> getIdentityMetric(IdentityProvider<?> identityProvider) {

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-with-allowlist-auth-scheme-interceptor.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import software.amazon.awssdk.endpoints.EndpointProvider;
2323
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
2424
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
25+
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
2526
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
2627
import software.amazon.awssdk.identity.spi.Identity;
2728
import software.amazon.awssdk.identity.spi.IdentityProvider;
@@ -117,6 +118,14 @@ private <T extends Identity> SelectedAuthScheme<T> trySelectAuthScheme(AuthSchem
117118
.add(() -> String.format("'%s' does not have an identity provider configured.", authOption.schemeId()));
118119
return null;
119120
}
121+
HttpSigner<T> signer;
122+
try {
123+
signer = authScheme.signer();
124+
} catch (RuntimeException e) {
125+
discardedReasons.add(() -> String.format("'%s' signer could not be retrieved: %s", authOption.schemeId(),
126+
e.getMessage()));
127+
return null;
128+
}
120129
ResolveIdentityRequest.Builder identityRequestBuilder = ResolveIdentityRequest.builder();
121130
authOption.forEachIdentityProperty(identityRequestBuilder::putProperty);
122131
CompletableFuture<? extends T> identity;
@@ -127,7 +136,7 @@ private <T extends Identity> SelectedAuthScheme<T> trySelectAuthScheme(AuthSchem
127136
identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()),
128137
metricCollector, metric);
129138
}
130-
return new SelectedAuthScheme<>(identity, authScheme.signer(), authOption);
139+
return new SelectedAuthScheme<>(identity, signer, authOption);
131140
}
132141

133142
private SdkMetric<Duration> getIdentityMetric(IdentityProvider<?> identityProvider) {

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/auth/scheme/query-endpoint-auth-params-without-allowlist-auth-scheme-interceptor.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import software.amazon.awssdk.endpoints.EndpointProvider;
2323
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
2424
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
25+
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
2526
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
2627
import software.amazon.awssdk.identity.spi.Identity;
2728
import software.amazon.awssdk.identity.spi.IdentityProvider;
@@ -120,6 +121,14 @@ private <T extends Identity> SelectedAuthScheme<T> trySelectAuthScheme(AuthSchem
120121
.add(() -> String.format("'%s' does not have an identity provider configured.", authOption.schemeId()));
121122
return null;
122123
}
124+
HttpSigner<T> signer;
125+
try {
126+
signer = authScheme.signer();
127+
} catch (RuntimeException e) {
128+
discardedReasons.add(() -> String.format("'%s' signer could not be retrieved: %s", authOption.schemeId(),
129+
e.getMessage()));
130+
return null;
131+
}
123132
ResolveIdentityRequest.Builder identityRequestBuilder = ResolveIdentityRequest.builder();
124133
authOption.forEachIdentityProperty(identityRequestBuilder::putProperty);
125134
CompletableFuture<? extends T> identity;
@@ -130,7 +139,7 @@ private <T extends Identity> SelectedAuthScheme<T> trySelectAuthScheme(AuthSchem
130139
identity = MetricUtils.reportDuration(() -> identityProvider.resolveIdentity(identityRequestBuilder.build()),
131140
metricCollector, metric);
132141
}
133-
return new SelectedAuthScheme<>(identity, authScheme.signer(), authOption);
142+
return new SelectedAuthScheme<>(identity, signer, authOption);
134143
}
135144

136145
private SdkMetric<Duration> getIdentityMetric(IdentityProvider<?> identityProvider) {

core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/scheme/DefaultAwsV4aAuthScheme.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,27 @@ public IdentityProvider<AwsCredentialsIdentity> identityProvider(IdentityProvide
5252
*/
5353
@Override
5454
public AwsV4aHttpSigner signer() {
55+
if (SignerSingletonHolder.ERROR != null) {
56+
throw SignerSingletonHolder.ERROR;
57+
}
5558
return SignerSingletonHolder.INSTANCE;
5659
}
5760

5861
private static class SignerSingletonHolder {
59-
private static final AwsV4aHttpSigner INSTANCE = AwsV4aHttpSigner.create();
62+
private static final AwsV4aHttpSigner INSTANCE;
63+
private static final RuntimeException ERROR;
64+
65+
// Attempt to load the Sigv4a signer and cache the error if CRT is not available on the classpath.
66+
static {
67+
AwsV4aHttpSigner instance = null;
68+
RuntimeException error = null;
69+
try {
70+
instance = AwsV4aHttpSigner.create();
71+
} catch (RuntimeException e) {
72+
error = e;
73+
}
74+
INSTANCE = instance;
75+
ERROR = error;
76+
}
6077
}
6178
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
<module>test/ruleset-testing-core</module>
8989
<module>test/old-client-version-compatibility-test</module>
9090
<module>test/bundle-logging-bridge-binding-test</module>
91+
<module>test/crt-unavailable-tests</module>
9192
</modules>
9293
<scm>
9394
<url>${scm.github.url}</url>

services/s3/src/main/resources/codegen-resources/endpoint-rule-set.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,14 @@
13401340
"url": "https://{Bucket}.ec2.{url#authority}",
13411341
"properties": {
13421342
"authSchemes": [
1343+
{
1344+
"disableDoubleEncoding": true,
1345+
"name": "sigv4a",
1346+
"signingName": "s3-outposts",
1347+
"signingRegionSet": [
1348+
"*"
1349+
]
1350+
},
13431351
{
13441352
"disableDoubleEncoding": true,
13451353
"name": "sigv4",
@@ -1445,6 +1453,14 @@
14451453
"url": "https://{Bucket}.op-{outpostId}.{url#authority}",
14461454
"properties": {
14471455
"authSchemes": [
1456+
{
1457+
"disableDoubleEncoding": true,
1458+
"name": "sigv4a",
1459+
"signingName": "s3-outposts",
1460+
"signingRegionSet": [
1461+
"*"
1462+
]
1463+
},
14481464
{
14491465
"disableDoubleEncoding": true,
14501466
"name": "sigv4",
@@ -5512,6 +5528,14 @@
55125528
"url": "https://{accessPointName}-{bucketArn#accountId}.{outpostId}.{url#authority}",
55135529
"properties": {
55145530
"authSchemes": [
5531+
{
5532+
"disableDoubleEncoding": true,
5533+
"name": "sigv4a",
5534+
"signingName": "s3-outposts",
5535+
"signingRegionSet": [
5536+
"*"
5537+
]
5538+
},
55155539
{
55165540
"disableDoubleEncoding": true,
55175541
"name": "sigv4",

0 commit comments

Comments
 (0)