diff --git a/core/http-auth-aws/pom.xml b/core/http-auth-aws/pom.xml index e6f7a162aaa7..8a7c7a0a8d0f 100644 --- a/core/http-auth-aws/pom.xml +++ b/core/http-auth-aws/pom.xml @@ -69,6 +69,12 @@ checksums ${awsjavasdk.version} + + software.amazon.awssdk.crt + aws-crt + ${awscrt.version} + true + org.mockito diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32CChecksum.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32CChecksum.java index 075f7dcb1044..7f625f2acbcb 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32CChecksum.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32CChecksum.java @@ -17,10 +17,10 @@ import static software.amazon.awssdk.http.auth.aws.internal.checksums.factory.CrtBasedChecksumProvider.longToByte; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.zip.Checksum; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.crt.checksums.CRC32C; import software.amazon.awssdk.http.auth.aws.internal.checksums.factory.CrtBasedChecksumProvider; import software.amazon.awssdk.http.auth.aws.internal.checksums.factory.SdkCrc32C; @@ -83,15 +83,10 @@ public void reset() { private Checksum cloneChecksum(Checksum checksum) { if (isCrtBasedChecksum) { - try { - Method method = checksum.getClass().getDeclaredMethod("clone"); - return (Checksum) method.invoke(checksum); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Could not clone checksum class " + checksum.getClass(), e); - } - } else { - return (Checksum) ((SdkCrc32C) checksum).clone(); - + return (Checksum) ((CRC32C) checksum).clone(); } + + return (Checksum) ((SdkCrc32C) checksum).clone(); + } } diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32Checksum.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32Checksum.java index d5283d8ec359..dfc6575e3310 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32Checksum.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/checksums/Crc32Checksum.java @@ -17,10 +17,10 @@ import static software.amazon.awssdk.http.auth.aws.internal.checksums.factory.CrtBasedChecksumProvider.longToByte; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.zip.Checksum; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.crt.checksums.CRC32; import software.amazon.awssdk.http.auth.aws.internal.checksums.factory.CrtBasedChecksumProvider; import software.amazon.awssdk.http.auth.aws.internal.checksums.factory.SdkCrc32; @@ -81,14 +81,9 @@ public void reset() { private Checksum cloneChecksum(Checksum checksum) { if (isCrtBasedChecksum) { - try { - Method method = checksum.getClass().getDeclaredMethod("clone"); - return (Checksum) method.invoke(checksum); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Could not clone checksum class " + checksum.getClass(), e); - } - } else { - return (Checksum) ((SdkCrc32) checksum).clone(); + return (Checksum) ((CRC32) checksum).clone(); } + + return (Checksum) ((SdkCrc32) checksum).clone(); } } diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumInputStream.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumInputStream.java index 625af50d4b56..0ec6acbdd526 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumInputStream.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumInputStream.java @@ -23,6 +23,9 @@ import java.util.zip.Checksum; import software.amazon.awssdk.annotations.SdkInternalApi; +/** + * An input-stream that takes a collection of checksums, and updates each checksum when it reads data. + */ @SdkInternalApi public class ChecksumInputStream extends FilterInputStream { diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumSubscriber.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumSubscriber.java index 072abe63a202..c7671f8c91e4 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumSubscriber.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/io/ChecksumSubscriber.java @@ -25,6 +25,9 @@ import org.reactivestreams.Subscription; import software.amazon.awssdk.annotations.SdkInternalApi; +/** + * A subscriber that takes a collection of checksums, and updates each checksum when it receives data. + */ @SdkInternalApi public final class ChecksumSubscriber implements Subscriber { private final CompletableFuture checksumming = new CompletableFuture<>(); diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java index d4763301855a..7e1a2850ccd4 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java @@ -32,6 +32,14 @@ import software.amazon.awssdk.utils.BinaryUtils; import software.amazon.awssdk.utils.Logger; +/** + * The default implementation of a v4-request-signer. It performs each step of the SigV4 signing process, but does not add the + * signature or auth information to the request itself. + *

+ * All signing information, such as signature, signing key, canonical request, etc. is present in context object that is + * returned. This can be used by the caller to add the auth info to the request, such as adding the signature as a query + * parameter or building an authorization header using the signature and canonical request headers. + */ @SdkInternalApi public final class DefaultV4RequestSigner implements V4RequestSigner { diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java index a7b2f56ea636..fac0b56f6d40 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java @@ -35,7 +35,9 @@ import software.amazon.awssdk.http.auth.aws.signer.Checksummer; /** - * A "flexible" implementation of a checksummer. + * A "flexible" implementation of a checksummer. It takes a map of checksums and their header names, computes them efficiently + * by updating each checksum while reading the payload (once), and adds the computed checksum strings to the request using the + * given header names in the map. This should be used in cases where a (flexible) checksum algorithm is present during signing. */ @SdkInternalApi public final class FlexibleChecksummer implements Checksummer { diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java index e9adb3459f86..7a5fbb153ae8 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java @@ -28,8 +28,8 @@ /** * An implementation of a checksummer that simply passes along a computed value as a checksum. Specifically, this is used in - * the cases where the checksum is a pre-defined value that dictates specific behavior by the signer (such as aws-chunked - * payload signing, unsigned streaming with trailers, etc.). + * the cases where the checksum is a pre-defined value that dictates specific behavior by the signer, and flexible checksums is + * not enabled for the request (such as aws-chunked payload signing without trailers, unsigned streaming without trailers, etc.). */ @SdkInternalApi public final class PrecomputedChecksummer implements Checksummer { diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java index c6e542b22f68..e96b6b69e18c 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java @@ -17,6 +17,7 @@ import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32; import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32C; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.MD5; import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA1; import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA256; @@ -27,6 +28,7 @@ import software.amazon.awssdk.http.auth.aws.internal.checksums.ConstantChecksum; import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32CChecksum; import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32Checksum; +import software.amazon.awssdk.http.auth.aws.internal.checksums.Md5Checksum; import software.amazon.awssdk.http.auth.aws.internal.checksums.SdkChecksum; import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha1Checksum; import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha256Checksum; @@ -51,11 +53,7 @@ public static String checksumHeaderName(ChecksumAlgorithm checksumAlgorithm) { } /** - * Gets the SdkChecksum object based on the given ChecksumAlgorithm. Instances for CRC32C, CRC32 Algorithm will be added from - * CRT Java library once they are available in release. - * - * @param checksumAlgorithm Algorithm for calculating the checksum - * @return an SdkChecksum instance. + * Gets the SdkChecksum object based on the given ChecksumAlgorithm. */ public static SdkChecksum fromChecksumAlgorithm(ChecksumAlgorithm checksumAlgorithm) { if (SHA256.algorithmId().equals(checksumAlgorithm.algorithmId())) { @@ -74,6 +72,10 @@ public static SdkChecksum fromChecksumAlgorithm(ChecksumAlgorithm checksumAlgori return new Crc32CChecksum(); } + if (MD5.algorithmId().equals(checksumAlgorithm.algorithmId())) { + return new Md5Checksum(); + } + if (CONSTANT_CHECKSUM.equals(checksumAlgorithm.algorithmId())) { return new ConstantChecksum(((ConstantChecksumAlgorithm) checksumAlgorithm).value); } diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java index c7baa06176bc..60531c93fecc 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java @@ -48,7 +48,7 @@ static Checksummer create() { } /** - * Get a flexible checksummer that uses the given checksum-algorithm and the default. + * Get a flexible checksummer that performs two checksums: the given checksum-algorithm and the default (sha256). */ static Checksummer create(ChecksumAlgorithm checksumAlgorithm) { if (checksumAlgorithm != null) { @@ -63,14 +63,15 @@ static Checksummer create(ChecksumAlgorithm checksumAlgorithm) { } /** - * Get a flexible checksummer that uses the given checksum-algorithm and the default. + * Get a precomputed checksummer that results the given checksum string. */ static Checksummer create(String checksum) { return new PrecomputedChecksummer(() -> checksum); } /** - * Get a flexible checksummer that uses the given checksum-algorithm and the default. + * Get a flexible checksummer that performs two checksums: the given checksum-algorithm and a precomputed checksum from the + * given checksum string. */ static Checksummer create(String checksum, ChecksumAlgorithm checksumAlgorithm) { if (checksumAlgorithm != null) { diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java index f2f058c82715..6934c81e7c16 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java @@ -25,7 +25,7 @@ @SdkProtectedApi @Immutable public final class V4Context { - private final String checksum; + private final String contentHash; private final byte[] signingKey; private final String signature; private final V4CanonicalRequest canonicalRequest; @@ -33,15 +33,15 @@ public final class V4Context { public V4Context(String contentHash, byte[] signingKey, String signature, V4CanonicalRequest canonicalRequest, SdkHttpRequest.Builder signedRequest) { - this.checksum = contentHash; + this.contentHash = contentHash; this.signingKey = signingKey.clone(); this.signature = signature; this.canonicalRequest = canonicalRequest; this.signedRequest = signedRequest; } - public String getContentChecksum() { - return checksum; + public String getContentHash() { + return contentHash; } public byte[] getSigningKey() { diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java index a0486c504cdd..446fd9a53e5a 100644 --- a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java @@ -235,7 +235,7 @@ public void sign_WithPayloadSigningFalseAndChunkEncodingTrueWithoutTrailer_Throw } @Test - public void sign_withFlexibleChecksum_DelegatesToFlexibleChecksummer() { + public void sign_withChecksumAlgorithm_DelegatesToChecksummerWithThatChecksumAlgorithm() { SyncSignRequest request = generateBasicRequest( AwsCredentialsIdentity.create("access", "secret"), httpRequest -> { @@ -250,7 +250,7 @@ public void sign_withFlexibleChecksum_DelegatesToFlexibleChecksummer() { } @Test - public void sign_withFlexibleChecksumAndPayloadSigningFalse_DelegatesToFlexibleChecksummer() { + public void sign_withChecksumAlgorithmAndPayloadSigningFalse_DelegatesToChecksummerWithThatChecksumAlgorithm() { SyncSignRequest request = generateBasicRequest( AwsCredentialsIdentity.create("access", "secret"), httpRequest -> { @@ -258,7 +258,6 @@ public void sign_withFlexibleChecksumAndPayloadSigningFalse_DelegatesToFlexibleC signRequest -> signRequest .putProperty(CHECKSUM_ALGORITHM, CRC32) .putProperty(PAYLOAD_SIGNING_ENABLED, false) - ); SyncSignedRequest signedRequest = signer.sign(request); diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultChecksummerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultChecksummerTest.java new file mode 100644 index 000000000000..f59f78295b32 --- /dev/null +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultChecksummerTest.java @@ -0,0 +1,64 @@ +/* + * 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.http.auth.aws.internal.signer; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.reactivex.Flowable; +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; + +public class DefaultChecksummerTest { + + ContentStreamProvider payload = () -> new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)); + Publisher payloadAsync = Flowable.just(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); + + + SdkHttpRequest.Builder request = SdkHttpRequest.builder() + .uri(URI.create("https://localhost")) + .method(SdkHttpMethod.GET); + + @Test + public void checksummer_shouldAddSha256ChecksumToAmzContentSha256Header() { + DefaultChecksummer checksummer = new DefaultChecksummer(); + SdkHttpRequest expectedRequest = request + .putHeader("x-amz-content-sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + .build(); + + checksummer.checksum(payload, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummerAsync_shouldAddSha256ChecksumToAmzContentSha256Header() { + DefaultChecksummer checksummer = new DefaultChecksummer(); + SdkHttpRequest expectedRequest = request + .putHeader("x-amz-content-sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + .build(); + + checksummer.checksum(payloadAsync, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } +} diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultRequestSignerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultRequestSignerTest.java new file mode 100644 index 000000000000..4cbe98387ca5 --- /dev/null +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultRequestSignerTest.java @@ -0,0 +1,69 @@ +/* + * 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.http.auth.aws.internal.signer; + +import static java.time.ZoneOffset.UTC; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static software.amazon.awssdk.utils.BinaryUtils.toHex; + +import java.net.URI; +import java.time.Clock; +import java.time.Instant; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.http.auth.aws.signer.CredentialScope; +import software.amazon.awssdk.http.auth.aws.signer.V4Context; +import software.amazon.awssdk.http.auth.aws.signer.V4Properties; +import software.amazon.awssdk.http.auth.aws.signer.V4RequestSigner; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; + +public class DefaultRequestSignerTest { + + V4Properties v4Properties = V4Properties.builder() + .credentials(AwsCredentialsIdentity.create("foo", "bar")) + .credentialScope(new CredentialScope("baz", "qux", Instant.EPOCH)) + .signingClock(Clock.fixed(Instant.EPOCH, UTC)) + .doubleUrlEncode(true) + .normalizePath(true) + .build(); + + V4RequestSigner requestSigner = new DefaultV4RequestSigner(v4Properties); + + @Test + public void requestSigner_sign_shouldReturnSignedContext_butNotAddAnyAuthInfoToRequest() { + SdkHttpRequest.Builder request = SdkHttpRequest + .builder() + .uri(URI.create("https://localhost")) + .method(SdkHttpMethod.GET) + .putHeader("x-amz-content-sha256", "quux"); + String expectedContentHash = "quux"; + String expectedSigningKeyHex = "3d558b7a87b67996abc908071e0771a31b2a7977ab247144e60a6cba3356be1f"; + String expectedSignature = "7557839280ea0ef5c4acc66e5670d0857ac4f491884b1b8031d4dea2fc33483c"; + String expectedCanonicalRequestString = "GET\n/\n\n" + + "host:localhost\nx-amz-content-sha256:quux\n\n" + + "host;x-amz-content-sha256\nquux"; + String expectedHost = "localhost"; + + V4Context v4Context = requestSigner.sign(request); + + assertEquals(expectedContentHash, v4Context.getContentHash()); + assertEquals(expectedSigningKeyHex, toHex(v4Context.getSigningKey())); + assertEquals(expectedSignature, v4Context.getSignature()); + assertEquals(expectedCanonicalRequestString, v4Context.getCanonicalRequest().getCanonicalRequestString()); + assertEquals(expectedHost, v4Context.getSignedRequest().firstMatchingHeader("Host").orElse("")); + } +} diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummerTest.java new file mode 100644 index 000000000000..550fbc9ff003 --- /dev/null +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummerTest.java @@ -0,0 +1,120 @@ +/* + * 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.http.auth.aws.internal.signer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA256; + +import io.reactivex.Flowable; +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.utils.ImmutableMap; + +public class FlexibleChecksummerTest { + + ContentStreamProvider payload = () -> new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)); + Publisher payloadAsync = Flowable.just(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); + + + SdkHttpRequest.Builder request = SdkHttpRequest.builder() + .uri(URI.create("https://localhost")) + .method(SdkHttpMethod.GET); + + @Test + public void checksummer_withNoChecksums_shouldNotAddAnyChecksum() { + FlexibleChecksummer checksummer = new FlexibleChecksummer(Collections.emptyMap()); + SdkHttpRequest expectedRequest = request.build(); + + checksummer.checksum(payload, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummerAsync_withNoChecksums_shouldNotAddAnyChecksum() { + FlexibleChecksummer checksummer = new FlexibleChecksummer(Collections.emptyMap()); + SdkHttpRequest expectedRequest = request.build(); + + checksummer.checksum(payloadAsync, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummer_withOneChecksum_shouldAddOneChecksum() { + FlexibleChecksummer checksummer = new FlexibleChecksummer(ImmutableMap.of("sha256", SHA256)); + SdkHttpRequest expectedRequest = request + .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + .build(); + + checksummer.checksum(payload, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummerAsync_withOneChecksum_shouldAddOneChecksum() { + FlexibleChecksummer checksummer = new FlexibleChecksummer(Collections.emptyMap()); + SdkHttpRequest expectedRequest = request + .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + .build(); + + checksummer.checksum(payloadAsync, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummer_withTwoChecksums_shouldAddTwoChecksums() { + FlexibleChecksummer checksummer = new FlexibleChecksummer(ImmutableMap.of( + "sha256", SHA256, + "crc32", CRC32 + )); + SdkHttpRequest expectedRequest = request + .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + .putHeader("crc32", "8c736521") + .build(); + + checksummer.checksum(payload, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummerAsync_withTwoChecksums_shouldAddTwoChecksums() { + FlexibleChecksummer checksummer = new FlexibleChecksummer(ImmutableMap.of( + "sha256", SHA256, + "crc32", CRC32 + )); + SdkHttpRequest expectedRequest = request + .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + .putHeader("crc32", "8c736521") + .build(); + + checksummer.checksum(payloadAsync, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } +} diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummerTest.java new file mode 100644 index 000000000000..ead8524019eb --- /dev/null +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummerTest.java @@ -0,0 +1,64 @@ +/* + * 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.http.auth.aws.internal.signer; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.reactivex.Flowable; +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; + +public class PrecomputedChecksummerTest { + + ContentStreamProvider payload = () -> new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)); + Publisher payloadAsync = Flowable.just(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); + + + SdkHttpRequest.Builder request = SdkHttpRequest.builder() + .uri(URI.create("https://localhost")) + .method(SdkHttpMethod.GET); + + @Test + public void checksummer_shouldAddComputedValue() { + PrecomputedChecksummer checksummer = new PrecomputedChecksummer(() -> "something"); + SdkHttpRequest expectedRequest = request + .putHeader("x-amz-content-sha256", "something") + .build(); + + checksummer.checksum(payload, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } + + @Test + public void checksummerAsync_shouldAddComputedValue() { + PrecomputedChecksummer checksummer = new PrecomputedChecksummer(() -> "something"); + SdkHttpRequest expectedRequest = request + .putHeader("x-amz-content-sha256", "something") + .build(); + + checksummer.checksum(payloadAsync, request); + + assertEquals(expectedRequest.toString(), request.build().toString()); + } +} diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtilTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtilTest.java new file mode 100644 index 000000000000..f0215c94b642 --- /dev/null +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtilTest.java @@ -0,0 +1,66 @@ +/* + * 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.http.auth.aws.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32C; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.MD5; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA1; +import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA256; +import static software.amazon.awssdk.http.auth.aws.internal.util.ChecksumUtil.checksumHeaderName; +import static software.amazon.awssdk.http.auth.aws.internal.util.ChecksumUtil.fromChecksumAlgorithm; +import static software.amazon.awssdk.http.auth.aws.internal.util.ChecksumUtil.readAll; + +import java.io.ByteArrayInputStream; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32CChecksum; +import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32Checksum; +import software.amazon.awssdk.http.auth.aws.internal.checksums.Md5Checksum; +import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha1Checksum; +import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha256Checksum; + +public class ChecksumUtilTest { + + @Test + public void checksumHeaderName_shouldFormatName() { + assertEquals("x-amz-checksum-sha256", checksumHeaderName(SHA256)); + assertEquals("x-amz-checksum-sha1", checksumHeaderName(SHA1)); + assertEquals("x-amz-checksum-crc32", checksumHeaderName(CRC32)); + assertEquals("x-amz-checksum-crc32c", checksumHeaderName(CRC32C)); + assertEquals("x-amz-checksum-md5", checksumHeaderName(MD5)); + } + + @Test + public void fromChecksumAlgorithm_mapsToCorrectSdkChecksum() { + assertEquals(Sha256Checksum.class, fromChecksumAlgorithm(SHA256).getClass()); + assertEquals(Sha1Checksum.class, fromChecksumAlgorithm(SHA1).getClass()); + assertEquals(Crc32Checksum.class, fromChecksumAlgorithm(CRC32).getClass()); + assertEquals(Crc32CChecksum.class, fromChecksumAlgorithm(CRC32C).getClass()); + assertEquals(Md5Checksum.class, fromChecksumAlgorithm(MD5).getClass()); + } + + @Test + public void readAll_consumesEntireStream() { + int bytes = 4096 * 4 + 1; + byte[] buf = new byte[bytes]; + ByteArrayInputStream inputStream = new ByteArrayInputStream(buf); + + readAll(inputStream); + + assertEquals(0, inputStream.available()); + } +}