From 35c5d7ffc07d08a19584c86135e7418b66d82b0a Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Fri, 18 Mar 2016 16:19:12 -0700 Subject: [PATCH] JCLOUDS-766: Include Content-MD5 in v4 signature Addresses AWSS3BlobIntegrationLiveTest.deleteMultipleObjects test failures. --- .../filters/Aws4SignerForAuthorizationHeader.java | 15 ++++++++++++++- .../s3/filters/Aws4SignerForChunkedUpload.java | 13 ++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForAuthorizationHeader.java b/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForAuthorizationHeader.java index 31525e7023..96526b94f1 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForAuthorizationHeader.java +++ b/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForAuthorizationHeader.java @@ -21,6 +21,8 @@ import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; +import com.google.common.hash.HashCode; +import com.google.common.io.BaseEncoding; import com.google.common.net.HttpHeaders; import com.google.inject.Inject; import org.jclouds.aws.domain.SessionCredentials; @@ -69,6 +71,8 @@ public class Aws4SignerForAuthorizationHeader extends Aws4SignerBase { checkNotNull(request, "request is not ready to sign"); checkNotNull(request.getEndpoint(), "request is not ready to sign, request.endpoint not present."); + Payload payload = request.getPayload(); + // get host from request endpoint. String host = request.getEndpoint().getHost(); @@ -82,7 +86,6 @@ public class Aws4SignerForAuthorizationHeader extends Aws4SignerBase { HttpRequest.Builder requestBuilder = request.toBuilder() // .removeHeader(AUTHORIZATION) // remove Authorization - .removeHeader(CONTENT_MD5) // aws s3 not allowed Content-MD5, use specs x-amz-content-sha256 .removeHeader(DATE); // remove date ImmutableMap.Builder signedHeadersBuilder = ImmutableSortedMap.naturalOrder(); @@ -102,6 +105,16 @@ public class Aws4SignerForAuthorizationHeader extends Aws4SignerBase { signedHeadersBuilder.put(HttpHeaders.CONTENT_LENGTH.toLowerCase(), contentLength); } + // Content MD5 + if (payload != null) { + HashCode md5 = payload.getContentMetadata().getContentMD5AsHashCode(); + if (md5 != null) { + String contentMD5 = BaseEncoding.base64().encode(md5.asBytes()); + requestBuilder.replaceHeader(CONTENT_MD5, contentMD5); + signedHeadersBuilder.put(CONTENT_MD5.toLowerCase(), contentMD5); + } + } + // host requestBuilder.replaceHeader(HttpHeaders.HOST, host); signedHeadersBuilder.put(HttpHeaders.HOST.toLowerCase(), host); diff --git a/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForChunkedUpload.java b/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForChunkedUpload.java index e4dd6ebcf1..4b6798d371 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForChunkedUpload.java +++ b/apis/s3/src/main/java/org/jclouds/s3/filters/Aws4SignerForChunkedUpload.java @@ -59,6 +59,8 @@ import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; +import com.google.common.hash.HashCode; +import com.google.common.io.BaseEncoding; import com.google.common.io.ByteProcessor; import com.google.common.net.HttpHeaders; import com.google.inject.Inject; @@ -104,7 +106,6 @@ public class Aws4SignerForChunkedUpload extends Aws4SignerBase { HttpRequest.Builder requestBuilder = request.toBuilder() // .removeHeader(AUTHORIZATION) // remove Authorization - .removeHeader(CONTENT_MD5) // aws s3 not allowed Content-MD5, use aws specs x-amz-content-sha256 .removeHeader(DATE) // remove Date .removeHeader(CONTENT_LENGTH); // remove Content-Length @@ -125,6 +126,16 @@ public class Aws4SignerForChunkedUpload extends Aws4SignerBase { requestBuilder.replaceHeader(CONTENT_LENGTH, Long.toString(totalLength)); signedHeadersBuilder.put(CONTENT_LENGTH.toLowerCase(), Long.toString(totalLength)); + // Content MD5 + if (payload != null) { + HashCode md5 = payload.getContentMetadata().getContentMD5AsHashCode(); + if (md5 != null) { + String contentMD5 = BaseEncoding.base64().encode(md5.asBytes()); + requestBuilder.replaceHeader(CONTENT_MD5, contentMD5); + signedHeadersBuilder.put(CONTENT_MD5.toLowerCase(), contentMD5); + } + } + // Content Type // content-type is not a required signing param. However, examples use this, so we include it to ease testing. String contentType = getContentType(request);