Skip to content

Add default RegionScope for SigV4a signers #3025

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-7723452.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"category": "AWS SDK for Java v2",
"contributor": "",
"type": "feature",
"description": "Add support for setting the default `RegionScope` used by the Sigv4a signer implementations. If the region scope to use is not supplied to the signing methods, the signers will default to this scope first and then the normal signing region."
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import software.amazon.awssdk.authcrt.signer.internal.DefaultAwsCrtS3V4aSigner;
import software.amazon.awssdk.core.signer.Presigner;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.regions.RegionScope;

/**
* Enables signing and presigning for S3 using Sigv4a (Asymmetric Sigv4) through an external API call to the AWS CRT
Expand Down Expand Up @@ -49,4 +50,20 @@ public interface AwsCrtS3V4aSigner extends Signer, Presigner {
static AwsCrtS3V4aSigner create() {
return DefaultAwsCrtS3V4aSigner.create();
}

static Builder builder() {
return DefaultAwsCrtS3V4aSigner.builder();
}

interface Builder {
/**
* The region scope that this signer will default to if not provided explicitly when the signer is invoked.
*
* @param defaultRegionScope The default region scope.
* @return This builder for method chaining.
*/
Builder defaultRegionScope(RegionScope defaultRegionScope);

AwsCrtS3V4aSigner build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import software.amazon.awssdk.authcrt.signer.internal.DefaultAwsCrtV4aSigner;
import software.amazon.awssdk.core.signer.Presigner;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.regions.RegionScope;

/**
* Enables signing and presigning using Sigv4a (Asymmetric Sigv4) through an external API call to the AWS CRT
Expand All @@ -39,4 +40,20 @@ public interface AwsCrtV4aSigner extends Signer, Presigner {
static AwsCrtV4aSigner create() {
return DefaultAwsCrtV4aSigner.create();
}

static Builder builder() {
return DefaultAwsCrtV4aSigner.builder();
}

interface Builder {
/**
* The region scope that this signer will default to if not provided explicitly when the signer is invoked.
*
* @param defaultRegionScope The default region scope.
* @return This builder for method chaining.
*/
Builder defaultRegionScope(RegionScope defaultRegionScope);

AwsCrtV4aSigner build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,51 @@
import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig;
import software.amazon.awssdk.http.ContentStreamProvider;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.regions.RegionScope;

@SdkInternalApi
public final class DefaultAwsCrtS3V4aSigner implements AwsCrtS3V4aSigner {

private final AwsCrt4aSigningAdapter signerAdapter;
private final SigningConfigProvider configProvider;
private final RegionScope defaultRegionScope;

DefaultAwsCrtS3V4aSigner(AwsCrt4aSigningAdapter signerAdapter, SigningConfigProvider signingConfigProvider) {
this(signerAdapter, signingConfigProvider, null);
}

DefaultAwsCrtS3V4aSigner(AwsCrt4aSigningAdapter signerAdapter, SigningConfigProvider signingConfigProvider,
RegionScope defaultRegionScope) {
this.signerAdapter = signerAdapter;
this.configProvider = signingConfigProvider;
this.defaultRegionScope = defaultRegionScope;
}

private DefaultAwsCrtS3V4aSigner(BuilderImpl builder) {
this(new AwsCrt4aSigningAdapter(), new SigningConfigProvider(), builder.defaultRegionScope);
}

public static AwsCrtS3V4aSigner create() {
return new DefaultAwsCrtS3V4aSigner(new AwsCrt4aSigningAdapter(), new SigningConfigProvider());
return builder().build();
}

public static Builder builder() {
return new BuilderImpl();
}

@Override
public SdkHttpFullRequest sign(SdkHttpFullRequest request, ExecutionAttributes executionAttributes) {
if (credentialsAreAnonymous(executionAttributes)) {
return request;
}
AwsSigningConfig requestSigningConfig = configProvider.createS3CrtSigningConfig(executionAttributes);
if (shouldSignPayload(request, executionAttributes)) {
ExecutionAttributes defaultsApplied = applyDefaults(executionAttributes);
AwsSigningConfig requestSigningConfig = configProvider.createS3CrtSigningConfig(defaultsApplied);
if (shouldSignPayload(request, defaultsApplied)) {
requestSigningConfig.setSignedBodyValue(AwsSigningConfig.AwsSignedBodyValue.STREAMING_AWS4_ECDSA_P256_SHA256_PAYLOAD);
SdkHttpFullRequest.Builder mutableRequest = request.toBuilder();
setHeaderContentLength(mutableRequest);
SdkSigningResult signingResult = signerAdapter.sign(mutableRequest.build(), requestSigningConfig);
AwsSigningConfig chunkConfig = configProvider.createChunkedSigningConfig(executionAttributes);
AwsSigningConfig chunkConfig = configProvider.createChunkedSigningConfig(defaultsApplied);
return enablePayloadSigning(signingResult, chunkConfig);
} else {
requestSigningConfig.setSignedBodyValue(AwsSigningConfig.AwsSignedBodyValue.UNSIGNED_PAYLOAD);
Expand All @@ -71,7 +88,8 @@ public SdkHttpFullRequest presign(SdkHttpFullRequest request, ExecutionAttribute
if (credentialsAreAnonymous(executionAttributes)) {
return request;
}
return signerAdapter.signRequest(request, configProvider.createS3CrtPresigningConfig(executionAttributes));
ExecutionAttributes defaultsApplied = applyDefaults(executionAttributes);
return signerAdapter.signRequest(request, configProvider.createS3CrtPresigningConfig(defaultsApplied));
}

private boolean credentialsAreAnonymous(ExecutionAttributes executionAttributes) {
Expand Down Expand Up @@ -121,4 +139,38 @@ private boolean booleanValue(Boolean attribute) {
return Boolean.TRUE.equals(attribute);
}

/**
* Applies preconfigured defaults for values that are not present in {@code executionAttributes}.
*/
private ExecutionAttributes applyDefaults(ExecutionAttributes executionAttributes) {
return applyDefaultRegionScope(executionAttributes);
}

private ExecutionAttributes applyDefaultRegionScope(ExecutionAttributes executionAttributes) {
if (executionAttributes.getAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE) != null) {
return executionAttributes;
}

if (defaultRegionScope == null) {
return executionAttributes;
}

return executionAttributes.copy()
.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE, defaultRegionScope);
}

private static class BuilderImpl implements Builder {
private RegionScope defaultRegionScope;

@Override
public Builder defaultRegionScope(RegionScope defaultRegionScope) {
this.defaultRegionScope = defaultRegionScope;
return this;
}

@Override
public AwsCrtS3V4aSigner build() {
return new DefaultAwsCrtS3V4aSigner(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,81 @@
import software.amazon.awssdk.authcrt.signer.AwsCrtV4aSigner;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.regions.RegionScope;

@SdkInternalApi
public final class DefaultAwsCrtV4aSigner implements AwsCrtV4aSigner {

private final AwsCrt4aSigningAdapter signer;
private final SigningConfigProvider configProvider;
private final RegionScope defaultRegionScope;

private DefaultAwsCrtV4aSigner() {
signer = new AwsCrt4aSigningAdapter();
configProvider = new SigningConfigProvider();
private DefaultAwsCrtV4aSigner(BuilderImpl builder) {
this(new AwsCrt4aSigningAdapter(), new SigningConfigProvider(), builder.defaultRegionScope);
}

DefaultAwsCrtV4aSigner(AwsCrt4aSigningAdapter signer, SigningConfigProvider configProvider,
RegionScope defaultRegionScope) {
this.signer = signer;
this.configProvider = configProvider;
this.defaultRegionScope = defaultRegionScope;
}

public static AwsCrtV4aSigner create() {
return new DefaultAwsCrtV4aSigner();
return builder().build();
}

public static Builder builder() {
return new BuilderImpl();
}

@Override
public SdkHttpFullRequest sign(SdkHttpFullRequest request, ExecutionAttributes executionAttributes) {
if (CredentialUtils.isAnonymous(executionAttributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS))) {
return request;
}
return signer.signRequest(request, configProvider.createCrtSigningConfig(executionAttributes));
ExecutionAttributes defaultsApplied = applyDefaults(executionAttributes);
return signer.signRequest(request, configProvider.createCrtSigningConfig(defaultsApplied));
}

@Override
public SdkHttpFullRequest presign(SdkHttpFullRequest request, ExecutionAttributes executionAttributes) {
return signer.signRequest(request, configProvider.createCrtPresigningConfig(executionAttributes));
ExecutionAttributes defaultsApplied = applyDefaults(executionAttributes);
return signer.signRequest(request, configProvider.createCrtPresigningConfig(defaultsApplied));
}

/**
* Applies preconfigured defaults for values that are not present in {@code executionAttributes}.
*/
private ExecutionAttributes applyDefaults(ExecutionAttributes executionAttributes) {
return applyDefaultRegionScope(executionAttributes);
}

private ExecutionAttributes applyDefaultRegionScope(ExecutionAttributes executionAttributes) {
if (executionAttributes.getAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE) != null) {
return executionAttributes;
}

if (defaultRegionScope == null) {
return executionAttributes;
}

return executionAttributes.copy()
.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE, defaultRegionScope);
}

private static class BuilderImpl implements Builder {
private RegionScope defaultRegionScope;

@Override
public Builder defaultRegionScope(RegionScope defaultRegionScope) {
this.defaultRegionScope = defaultRegionScope;
return this;
}

@Override
public AwsCrtV4aSigner build() {
return new DefaultAwsCrtV4aSigner(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import software.amazon.awssdk.auth.signer.internal.SignerConstant;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig;
import software.amazon.awssdk.regions.internal.util.RegionScope;
import software.amazon.awssdk.regions.RegionScope;

@SdkInternalApi
public class SigningConfigProvider {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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.authcrt.signer.internal;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
import software.amazon.awssdk.authcrt.signer.AwsCrtS3V4aSigner;
import software.amazon.awssdk.authcrt.signer.SignerTestUtils;
import software.amazon.awssdk.authcrt.signer.SigningTestCase;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.regions.RegionScope;

public class AwsCrtS3V4aSignerSigningScopeTest extends BaseSigningScopeTest {
@Test
public void signing_chunkedEncoding_regionalScope_present_overrides() {
SigningTestCase testCase = SignerTestUtils.createBasicChunkedSigningTestCase();
SdkHttpFullRequest signedRequest = signRequestWithScope(testCase, null, RegionScope.GLOBAL);

String regionHeader = signedRequest.firstMatchingHeader("X-Amz-Region-Set").get();
assertThat(regionHeader).isEqualTo(RegionScope.GLOBAL.id());
}

@Test
public void testS3Presigning() {
SigningTestCase testCase = SignerTestUtils.createBasicQuerySigningTestCase();

SdkHttpFullRequest signedRequest = presignRequestWithScope(testCase, null, RegionScope.GLOBAL);

List<String> regionHeader = signedRequest.rawQueryParameters().get("X-Amz-Region-Set");
assertThat(regionHeader.get(0)).isEqualTo(RegionScope.GLOBAL.id());
}


protected SdkHttpFullRequest signRequestWithScope(SigningTestCase testCase, RegionScope defaultRegionScope,
RegionScope regionScope) {
ExecutionAttributes executionAttributes = SignerTestUtils.buildBasicExecutionAttributes(testCase);
if (regionScope != null) {
executionAttributes.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE, regionScope);
}
SdkHttpFullRequest request = testCase.requestBuilder.build();
return AwsCrtS3V4aSigner.builder().defaultRegionScope(defaultRegionScope).build().sign(request, executionAttributes);
}

protected SdkHttpFullRequest presignRequestWithScope(SigningTestCase testCase, RegionScope defaultRegionScope,
RegionScope regionScope) {
ExecutionAttributes executionAttributes = SignerTestUtils.buildBasicExecutionAttributes(testCase);
if (regionScope != null) {
executionAttributes.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE, regionScope);
}
SdkHttpFullRequest request = testCase.requestBuilder.build();
return AwsCrtS3V4aSigner.builder().defaultRegionScope(defaultRegionScope).build().presign(request, executionAttributes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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.authcrt.signer.internal;

import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
import software.amazon.awssdk.authcrt.signer.AwsCrtV4aSigner;
import software.amazon.awssdk.authcrt.signer.SignerTestUtils;
import software.amazon.awssdk.authcrt.signer.SigningTestCase;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.regions.RegionScope;

public class AwsCrtV4aSignerSigningScopeTest extends BaseSigningScopeTest {
@Override
protected SdkHttpFullRequest signRequestWithScope(SigningTestCase testCase, RegionScope defaultRegionScope,
RegionScope regionScope) {
ExecutionAttributes executionAttributes = SignerTestUtils.buildBasicExecutionAttributes(testCase);
if (regionScope != null) {
executionAttributes.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE, regionScope);
}
SdkHttpFullRequest request = testCase.requestBuilder.build();
return AwsCrtV4aSigner.builder().defaultRegionScope(defaultRegionScope).build().sign(request, executionAttributes);
}

@Override
protected SdkHttpFullRequest presignRequestWithScope(SigningTestCase testCase, RegionScope defaultRegionScope,
RegionScope regionScope) {
ExecutionAttributes executionAttributes = SignerTestUtils.buildBasicExecutionAttributes(testCase);
if (regionScope != null) {
executionAttributes.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION_SCOPE, regionScope);
}
SdkHttpFullRequest request = testCase.requestBuilder.build();
return AwsCrtV4aSigner.builder().defaultRegionScope(defaultRegionScope).build().presign(request, executionAttributes);
}
}
Loading