diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/DisablePayloadSigningInterceptor.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/DisablePayloadSigningInterceptor.java new file mode 100644 index 000000000000..0fab4dc487ee --- /dev/null +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/handlers/DisablePayloadSigningInterceptor.java @@ -0,0 +1,35 @@ +/* + * 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.s3.internal.handlers; + +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.auth.signer.S3SignerExecutionAttribute; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; + +/** + * Disables payload signing for all S3 operations. + * + *

TODO(sra-identity-auth): After S3's migration to the SRA, we should use signer properties in the auth scheme resolver. + */ +@SdkInternalApi +public class DisablePayloadSigningInterceptor implements ExecutionInterceptor { + @Override + public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { + executionAttributes.putAttributeIfAbsent(S3SignerExecutionAttribute.ENABLE_PAYLOAD_SIGNING, false); + } +} diff --git a/services/s3/src/main/resources/codegen-resources/customization.config b/services/s3/src/main/resources/codegen-resources/customization.config index 327e28e62b34..02ee8a5b6bb2 100644 --- a/services/s3/src/main/resources/codegen-resources/customization.config +++ b/services/s3/src/main/resources/codegen-resources/customization.config @@ -256,7 +256,8 @@ "software.amazon.awssdk.services.s3.internal.handlers.EnableTrailingChecksumInterceptor", "software.amazon.awssdk.services.s3.internal.handlers.ExceptionTranslationInterceptor", "software.amazon.awssdk.services.s3.internal.handlers.GetObjectInterceptor", - "software.amazon.awssdk.services.s3.internal.handlers.CopySourceInterceptor" + "software.amazon.awssdk.services.s3.internal.handlers.CopySourceInterceptor", + "software.amazon.awssdk.services.s3.internal.handlers.DisablePayloadSigningInterceptor" ], "requiredTraitValidationEnabled": true, "enableEndpointAuthSchemeParams": true, diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/PayloadSigningDisabledTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/PayloadSigningDisabledTest.java new file mode 100644 index 000000000000..0ac8d0eec1bb --- /dev/null +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/PayloadSigningDisabledTest.java @@ -0,0 +1,118 @@ +/* + * 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.s3; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.signer.S3SignerExecutionAttribute; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.http.HttpExecuteResponse; +import software.amazon.awssdk.http.SdkHttpResponse; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.testutils.service.http.MockAsyncHttpClient; +import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient; + +/** + * Ensure that payload signing is disabled for S3 operations. + */ +public class PayloadSigningDisabledTest { + private static final AwsCredentialsProvider CREDENTIALS = () -> AwsBasicCredentials.create("akid", "skid"); + private static final ClientOverrideConfiguration ENABLE_PAYLOAD_SIGNING_CONFIG = + ClientOverrideConfiguration.builder() + .putExecutionAttribute(S3SignerExecutionAttribute.ENABLE_PAYLOAD_SIGNING, true) + .build(); + + @Test + public void syncPayloadSigningIsDisabled() { + try (MockSyncHttpClient httpClient = new MockSyncHttpClient(); + S3Client s3 = S3Client.builder() + .region(Region.US_WEST_2) + .credentialsProvider(CREDENTIALS) + .httpClient(httpClient) + .build()) { + httpClient.stubNextResponse(HttpExecuteResponse.builder() + .response(SdkHttpResponse.builder().statusCode(200).build()) + .build()); + + s3.createBucket(r -> r.bucket("foo")); + + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-content-sha256")) + .hasValue("UNSIGNED-PAYLOAD"); + } + } + + @Test + public void asyncPayloadSigningIsDisabled() { + try (MockAsyncHttpClient httpClient = new MockAsyncHttpClient(); + S3AsyncClient s3 = S3AsyncClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(CREDENTIALS) + .httpClient(httpClient) + .build()) { + httpClient.stubNextResponse(HttpExecuteResponse.builder() + .response(SdkHttpResponse.builder().statusCode(200).build()) + .build()); + + s3.createBucket(r -> r.bucket("foo")).join(); + + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-content-sha256")) + .hasValue("UNSIGNED-PAYLOAD"); + } + } + + @Test + public void syncPayloadSigningCanBeEnabled() { + try (MockSyncHttpClient httpClient = new MockSyncHttpClient(); + S3Client s3 = S3Client.builder() + .region(Region.US_WEST_2) + .credentialsProvider(CREDENTIALS) + .httpClient(httpClient) + .overrideConfiguration(ENABLE_PAYLOAD_SIGNING_CONFIG) + .build()) { + httpClient.stubNextResponse(HttpExecuteResponse.builder() + .response(SdkHttpResponse.builder().statusCode(200).build()) + .build()); + + s3.createBucket(r -> r.bucket("foo")); + + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-content-sha256")) + .hasValue("a40ef303139635de59992f34c1c7da763f89200f2d55b71016f7c156527d63a0"); + } + } + + @Test + public void asyncPayloadSigningCanBeEnabled() { + try (MockAsyncHttpClient httpClient = new MockAsyncHttpClient(); + S3AsyncClient s3 = S3AsyncClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(CREDENTIALS) + .httpClient(httpClient) + .overrideConfiguration(ENABLE_PAYLOAD_SIGNING_CONFIG) + .build()) { + httpClient.stubNextResponse(HttpExecuteResponse.builder() + .response(SdkHttpResponse.builder().statusCode(200).build()) + .build()); + + s3.createBucket(r -> r.bucket("foo")).join(); + + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-content-sha256")) + .hasValue("a40ef303139635de59992f34c1c7da763f89200f2d55b71016f7c156527d63a0"); + } + } +}