diff --git a/.changes/next-release/bugfix-AWSSDKforJavav2-66877e6.json b/.changes/next-release/bugfix-AWSSDKforJavav2-66877e6.json new file mode 100644 index 000000000000..4a45e056e13c --- /dev/null +++ b/.changes/next-release/bugfix-AWSSDKforJavav2-66877e6.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Log `AWS4 Canonical Request` in signer if DEBUG level is enabled." +} diff --git a/core/http-auth-aws/pom.xml b/core/http-auth-aws/pom.xml index 9ed593d1297d..1656df0234c7 100644 --- a/core/http-auth-aws/pom.xml +++ b/core/http-auth-aws/pom.xml @@ -125,7 +125,26 @@ reactive-streams-tck test - + + software.amazon.awssdk + test-utils + 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/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 1935fa10107a..21565d43551e 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 @@ -52,8 +52,11 @@ public V4RequestSigningResult sign(SdkHttpRequest.Builder requestBuilder) { // Step 1: Create a canonical request V4CanonicalRequest canonicalRequest = createCanonicalRequest(requestBuilder.build(), contentHash); + String canonicalRequestString = canonicalRequest.getCanonicalRequestString(); + LOG.debug(() -> "AWS4 Canonical Request: " + canonicalRequestString); + // Step 2: Create a hash of the canonical request - String canonicalRequestHash = hashCanonicalRequest(canonicalRequest.getCanonicalRequestString()); + String canonicalRequestHash = hashCanonicalRequest(canonicalRequestString); // Step 2: Create a hash of the canonical request String stringToSign = createSignString(canonicalRequestHash); 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 index dfff39536aba..b212e283ec3b 100644 --- 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 @@ -20,6 +20,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static software.amazon.awssdk.utils.BinaryUtils.toHex; +import java.util.List; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.LogEvent; +import software.amazon.awssdk.testutils.LogCaptor; + import java.net.URI; import java.time.Clock; import java.time.Instant; @@ -30,7 +35,7 @@ public class DefaultRequestSignerTest { - V4Properties v4Properties = V4Properties.builder() + private V4Properties v4Properties = V4Properties.builder() .credentials(AwsCredentialsIdentity.create("foo", "bar")) .credentialScope(new CredentialScope("baz", "qux", Instant.EPOCH)) .signingClock(Clock.fixed(Instant.EPOCH, UTC)) @@ -38,8 +43,6 @@ public class DefaultRequestSignerTest { .normalizePath(true) .build(); - DefaultV4RequestSigner requestSigner = new DefaultV4RequestSigner(v4Properties, "quux"); - @Test public void requestSigner_sign_shouldReturnSignedResult_butNotAddAnyAuthInfoToRequest() { SdkHttpRequest.Builder request = SdkHttpRequest @@ -55,13 +58,20 @@ public void requestSigner_sign_shouldReturnSignedResult_butNotAddAnyAuthInfoToRe + "host\nquux"; String expectedHost = "localhost"; - V4RequestSigningResult requestSigningResult = requestSigner.sign(request); - - assertEquals(expectedContentHash, requestSigningResult.getContentHash()); - assertEquals(expectedSigningKeyHex, toHex(requestSigningResult.getSigningKey())); - assertEquals(expectedSignature, requestSigningResult.getSignature()); - assertEquals(expectedCanonicalRequestString, requestSigningResult.getCanonicalRequest().getCanonicalRequestString()); - assertEquals(expectedHost, requestSigningResult.getSignedRequest().firstMatchingHeader("Host").orElse("")); - assertThat(requestSigningResult.getSignedRequest().build()).usingRecursiveComparison().isEqualTo(request.build()); + try (LogCaptor logCaptor = LogCaptor.create(Level.DEBUG)) { + DefaultV4RequestSigner requestSigner = new DefaultV4RequestSigner(v4Properties, "quux"); + V4RequestSigningResult requestSigningResult = requestSigner.sign(request); + assertEquals(expectedContentHash, requestSigningResult.getContentHash()); + assertEquals(expectedSigningKeyHex, toHex(requestSigningResult.getSigningKey())); + assertEquals(expectedSignature, requestSigningResult.getSignature()); + assertEquals(expectedCanonicalRequestString, requestSigningResult.getCanonicalRequest().getCanonicalRequestString()); + assertEquals(expectedHost, requestSigningResult.getSignedRequest().firstMatchingHeader("Host").orElse("")); + assertThat(requestSigningResult.getSignedRequest().build()).usingRecursiveComparison().isEqualTo(request.build()); + List logEvents = logCaptor.loggedEvents(); + assertThat(logEvents).hasSize(3); + assertThat(logEvents.get(0).getMessage().getFormattedMessage()).contains("AWS4 Canonical Request"); + assertThat(logEvents.get(1).getMessage().getFormattedMessage()).contains("AWS4 Canonical Request Hash"); + assertThat(logEvents.get(2).getMessage().getFormattedMessage()).contains("AWS4 String to sign"); + } } } diff --git a/core/http-auth-aws/src/test/resources/log4j2.properties b/core/http-auth-aws/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..5cc1706db5bd --- /dev/null +++ b/core/http-auth-aws/src/test/resources/log4j2.properties @@ -0,0 +1,38 @@ +# +# 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. +# + +status = warn + +appender.console.type = Console +appender.console.name = ConsoleAppender +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n%throwable + +rootLogger.level = error +rootLogger.appenderRef.stdout.ref = ConsoleAppender + +# Uncomment below to enable more specific logging +# +#logger.sdk.name = software.amazon.awssdk +#logger.sdk.level = debug +# +#logger.request.name = software.amazon.awssdk.request +#logger.request.level = debug +# +#logger.apache.name = org.apache.http.wire +#logger.apache.level = debug +# +#logger.netty.name = io.netty.handler.logging +#logger.netty.level = debug