From 5d7e15663eb562e83be85530a9ce4e9de0c0709e Mon Sep 17 00:00:00 2001 From: Jake Karnes Date: Fri, 6 May 2022 14:11:39 -0700 Subject: [PATCH 1/4] Improving host header handling. See #33 --- .../signing/DelegatingAwsRequestSigner.java | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java b/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java index 41ae7f0..104803d 100644 --- a/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java +++ b/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java @@ -11,6 +11,7 @@ import java.io.ByteArrayInputStream; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -21,6 +22,7 @@ import java.util.Optional; import java.util.Set; import java.util.TreeMap; +import java.util.regex.Pattern; import java.util.stream.Collectors; import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.signer.Aws4Signer; @@ -104,12 +106,55 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse URI uri; try { uri = request.getUrl().toURI(); + LogWriter.logDebug("Identified target URI as: " + uri); } catch (URISyntaxException ex) { final String errorMessage = "Bad Request URL. Not valid syntax. Error: " + ex.getMessage(); LogWriter.logError(errorMessage); throw new SigningException(errorMessage, ex); } + String targetURLHost = uri.getHost(); + LogWriter.logDebug("Extracted host value from target URI as: " + targetURLHost); + + //Get the original host header. + String originalHost = null; + int originalHostPort = uri.getPort(); + for (String header : allHeaders) { + if (header.toLowerCase().startsWith("host:")) { + String originalHostHeaderValue = header.replaceFirst("(?i)host:", "").trim(); + LogWriter.logDebug("Extracted host header value from original headers as: " + originalHostHeaderValue); + if (originalHostHeaderValue.contains(":")) { + String[] originalHostHeaderParts = originalHostHeaderValue.split(":", 2); + originalHost = originalHostHeaderParts[0]; + originalHostPort = Integer.parseInt(originalHostHeaderParts[1]); + } else { + originalHost = originalHostHeaderValue; + } + break; + } + } + + //Error if we can't find the original host header, use what's in the URI + if (originalHost == null || originalHost.isEmpty()) { + originalHost = uri.getHost(); + LogWriter.logInfo("No host header value found in original headers. Falling back to value from URI: " + targetURLHost); + } + + // If the value of the host header doesn't match the value in the target URL, we need to swap the host header value into the URL + // This maintains compatibility with SignerV1 and supports proxies where the URL may point to a localhost endpoint, + // but the request gets forwarded onto a real AWS endpoint. The host header must be the real AWS endpoint and the SigV4 signature must match + // even though the URL has the proxy endpoint. + if (!targetURLHost.equals(originalHost)) { + try { + uri = new URI(uri.getScheme(), uri.getUserInfo(), originalHost, originalHostPort, uri.getPath(), uri.getQuery(), uri.getFragment()); + LogWriter.logDebug("Updated URI for signing as: " + uri); + } catch (URISyntaxException ex) { + final String errorMessage = "Bad Request URL after update to original host \"" + originalHost + "\". Not valid syntax. Error: " + ex.getMessage(); + LogWriter.logError(errorMessage); + throw new SigningException(errorMessage, ex); + } + } + // Need to remove these headers for the SDK signedHeaderMap.remove("x-amz-security-token"); signedHeaderMap.remove("x-amz-date"); @@ -233,7 +278,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse } } } - + //Check if the credentials have a session token if (credentials.getSessionToken().isPresent()) { boolean foundHeader = false; @@ -246,7 +291,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse LogWriter.logDebug("Replaced " + header + " in request with profile's session token."); } } - if(!foundHeader){ + if (!foundHeader) { finalHeaders.add("X-Amz-Security-Token: " + credentials.getSessionToken().get()); LogWriter.logDebug("Added X-Amz-Security-Token to request with profile's session token."); } @@ -259,8 +304,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse } } } - - + LogWriter.logDebug("Final Headers: " + finalHeaders); //Handle the first request line From 3a9ec580dad58e5c6f879c99628623a1179aea4e Mon Sep 17 00:00:00 2001 From: Jake Karnes Date: Fri, 6 May 2022 14:36:27 -0700 Subject: [PATCH 2/4] Improve default port handling --- .../netspi/awssigner/signing/DelegatingAwsRequestSigner.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java b/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java index 104803d..b57e13d 100644 --- a/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java +++ b/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java @@ -118,7 +118,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse //Get the original host header. String originalHost = null; - int originalHostPort = uri.getPort(); + int originalHostPort = -1; for (String header : allHeaders) { if (header.toLowerCase().startsWith("host:")) { String originalHostHeaderValue = header.replaceFirst("(?i)host:", "").trim(); @@ -137,6 +137,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse //Error if we can't find the original host header, use what's in the URI if (originalHost == null || originalHost.isEmpty()) { originalHost = uri.getHost(); + originalHostPort = uri.getPort(); LogWriter.logInfo("No host header value found in original headers. Falling back to value from URI: " + targetURLHost); } From 8795a788a5965bb4a58a7c510b0828fa3f1c3f3f Mon Sep 17 00:00:00 2001 From: Jake Karnes Date: Fri, 20 May 2022 08:46:25 -0700 Subject: [PATCH 3/4] Bumping version number --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9906318..03c0d5a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group "com.netspi.awssigner" -version "2.0.2" +version "2.0.3" apply plugin: "java" From f74a6dfd7aecee9d970f84d1628c6ad2d2229a7c Mon Sep 17 00:00:00 2001 From: Jake Karnes Date: Fri, 20 May 2022 08:49:08 -0700 Subject: [PATCH 4/4] Minor comment cleanup --- .../netspi/awssigner/signing/DelegatingAwsRequestSigner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java b/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java index b57e13d..a1f1690 100644 --- a/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java +++ b/src/main/java/com/netspi/awssigner/signing/DelegatingAwsRequestSigner.java @@ -102,7 +102,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse } LogWriter.logDebug("signedHeaderMap: " + signedHeaderMap); - // build request object for signing + //Build request object for signing URI uri; try { uri = request.getUrl().toURI(); @@ -134,7 +134,7 @@ public byte[] sign(IHttpRequestResponse messageInfo, IRequestInfo request, Parse } } - //Error if we can't find the original host header, use what's in the URI + //If we can't find the host header, use what's in the URI if (originalHost == null || originalHost.isEmpty()) { originalHost = uri.getHost(); originalHostPort = uri.getPort();