diff --git a/.changes/next-release/feature-AWSSDKforJavav2-9f69c81.json b/.changes/next-release/feature-AWSSDKforJavav2-9f69c81.json new file mode 100644 index 000000000000..a81060310906 --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-9f69c81.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Fixed SigV4a signing to respect pre-existing Host headers to be consistent with existing SigV4 signing behavior." +} diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/crt/internal/util/CrtUtils.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/crt/internal/util/CrtUtils.java index 8ac8cac1bbbc..64004f12cf86 100644 --- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/crt/internal/util/CrtUtils.java +++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/crt/internal/util/CrtUtils.java @@ -25,6 +25,7 @@ import static software.amazon.awssdk.http.auth.aws.internal.signer.util.SignerConstant.X_AMZ_SIGNED_HEADERS; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; @@ -56,7 +57,7 @@ private CrtUtils() { * Sanitize an {@link SdkHttpRequest}, in order to prepare it for converting to a CRT request destined to be signed. *

* Sanitizing includes checking the path is not empty, filtering headers and query parameters that are forbidden in CRT, and - * adding the host header (overriding if already presesnt). + * adding the host header */ public static SdkHttpRequest sanitizeRequest(SdkHttpRequest request) { @@ -77,11 +78,17 @@ public static SdkHttpRequest sanitizeRequest(SdkHttpRequest request) { } }); - // Add host, which must be signed. We ignore any pre-existing Host header to match the behavior of the SigV4 signer. - String hostHeader = SdkHttpUtils.isUsingStandardPort(request.protocol(), request.port()) - ? request.host() - : request.host() + ":" + request.port(); - builder.putHeader(HOST, hostHeader); + // Add host header, which must be signed. If the SdkHttpRequest has an associated Host header + // already set, prefer to use that. + Optional existingHostHeader = request.firstMatchingHeader(HOST); + if (existingHostHeader.isPresent()) { + builder.putHeader(HOST, existingHostHeader.get()); + } else { + String hostHeader = SdkHttpUtils.isUsingStandardPort(request.protocol(), request.port()) + ? request.host() + : request.host() + ":" + request.port(); + builder.putHeader(HOST, hostHeader); + } builder.clearQueryParameters(); diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/crt/internal/signer/DefaultAwsCrtV4aHttpSignerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/crt/internal/signer/DefaultAwsCrtV4aHttpSignerTest.java index 647354e472ed..4c1a01f6f2e3 100644 --- a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/crt/internal/signer/DefaultAwsCrtV4aHttpSignerTest.java +++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/crt/internal/signer/DefaultAwsCrtV4aHttpSignerTest.java @@ -412,4 +412,26 @@ public void sign_checksumValueProvided_shouldNotOverrideChecksumHeader() { assertThat(signedRequest.request().firstMatchingHeader("x-amz-checksum-crc32")) .contains("some value"); } + + @Test + public void sign_withProvidedHostHeader_shouldRespectUserHostHeader() { + AwsCredentialsIdentity credentials = + AwsCredentialsIdentity.create("access", "secret"); + + String hostOverride = "virtual-host.localhost"; + SignRequest request = generateBasicRequest( + credentials, + httpRequest -> httpRequest.putHeader("Host", hostOverride).port(443), + signRequest -> { + + } + ); + + SignedRequest signedRequest = signer.sign(request); + + assertThat(signedRequest.request().firstMatchingHeader("Host")).hasValue(hostOverride); + assertThat(signedRequest.request().firstMatchingHeader("X-Amz-Date")).hasValue("20200803T174823Z"); + assertThat(signedRequest.request().firstMatchingHeader("X-Amz-Region-Set")).hasValue("aws-global"); + assertThat(signedRequest.request().firstMatchingHeader("Authorization")).isPresent(); + } }