From d14ccec0930232bbf934d937784fb51137662b42 Mon Sep 17 00:00:00 2001 From: Alin Dreghiciu Date: Wed, 7 Mar 2018 20:49:51 +0200 Subject: [PATCH 1/3] [JCLOUDS-1391] Sort headers alfabetically/lowercase before signing --- .../filters/SharedKeyLiteAuthentication.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java index aebcf9592dd..b70ac901652 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java +++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java @@ -23,6 +23,8 @@ import static org.jclouds.util.Strings2.toInputStream; import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import javax.annotation.Resource; @@ -31,6 +33,11 @@ import javax.inject.Provider; import javax.inject.Singleton; +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import org.jclouds.Constants; import org.jclouds.crypto.Crypto; import org.jclouds.date.TimeStamp; @@ -150,18 +157,26 @@ private void appendMethod(HttpRequest request, StringBuilder toSign) { } private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) { - // TreeSet == Sort the headers alphabetically. - Set headers = Sets.newTreeSet(request.getHeaders().keySet()); - for (String header : headers) { + // TreeMap == Sort the headers alphabetically. + Map headers = Maps.newTreeMap(); + Multimap requestHeaders = request.getHeaders(); + for (String header : requestHeaders.keySet()) { if (header.startsWith("x-ms-")) { - toSign.append(header.toLowerCase()).append(":"); - for (String value : request.getHeaders().get(header)) { - toSign.append(NEWLINE_PATTERN.matcher(value).replaceAll("")).append(","); - } - toSign.deleteCharAt(toSign.lastIndexOf(",")); - toSign.append("\n"); + String value = Joiner.on(",").join(Iterables.transform(requestHeaders.get(header), + new Function() + { + @Override + public Object apply(final String value) { + return NEWLINE_PATTERN.matcher(value).replaceAll(""); + } + }) + ); + headers.put(header.toLowerCase(), value); } } + for (Entry entry : headers.entrySet()) { + toSign.append(entry.getKey()).append(":").append(entry.getValue()).append("\n"); + } } private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) { From a8eddc81f5e1c43de59ed076ded1dcb7483dc66a Mon Sep 17 00:00:00 2001 From: Alin Dreghiciu Date: Wed, 7 Mar 2018 21:12:01 +0200 Subject: [PATCH 2/3] Remove imports --- .../azure/storage/filters/SharedKeyLiteAuthentication.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java index b70ac901652..700c610b575 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java +++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java @@ -25,7 +25,6 @@ import java.util.Collection; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import javax.annotation.Resource; import javax.inject.Inject; @@ -57,7 +56,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.Multimaps; -import com.google.common.collect.Sets; import com.google.common.io.ByteProcessor; import com.google.common.net.HttpHeaders; From d27f323bff1881f0a1716f2e54895236bb5c5ebe Mon Sep 17 00:00:00 2001 From: Alin Dreghiciu Date: Wed, 7 Mar 2018 23:29:41 +0200 Subject: [PATCH 3/3] Add integration test --- .../AzureBlobIntegrationLiveTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java index 67223fc9b2f..d48b2f8d4f9 100644 --- a/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java +++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/blobstore/integration/AzureBlobIntegrationLiveTest.java @@ -19,10 +19,21 @@ import java.io.IOException; import java.util.concurrent.ExecutionException; +import javax.ws.rs.core.MediaType; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableMap; +import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest; +import org.jclouds.blobstore.options.CopyOptions; import org.testng.SkipException; import org.testng.annotations.Test; +import static com.google.common.hash.Hashing.md5; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + @Test(groups = "live") public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest { @Override @@ -64,4 +75,38 @@ public void testPutBlobAccess() throws Exception { public void testPutBlobAccessMultipart() throws Exception { super.testPutBlobAccessMultipart(); } + + // see https://issues.apache.org/jira/browse/JCLOUDS-1391 + @Test(groups = { "integration", "live" }) + public void testSigningOfUppercaseMetadata() throws InterruptedException { + String containerName = getContainerName(); + String blobName = "testSigningOfUppercaseMetadata"; + + Blob blob = view.getBlobStore().blobBuilder(blobName) + .userMetadata(ImmutableMap.of("B", "b", "a", "a")) + .payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN) + .contentMD5(md5().hashString(TEST_STRING, Charsets.UTF_8)) + .build(); + + try { + assertNull(view.getBlobStore().blobMetadata(containerName, blobName)); + + addBlobToContainer(containerName, blob); + assertConsistencyAwareContainerSize(containerName, 1); + + view.getBlobStore().copyBlob( + containerName, blobName, containerName, blobName, + CopyOptions.builder().userMetadata(ImmutableMap.of("B", "b", "a", "a")).build() + ); + + Blob newObject = view.getBlobStore().getBlob(containerName, blobName); + + assertNotNull(newObject); + assertEquals(newObject.getMetadata().getUserMetadata().get("b"), "b"); + assertEquals(newObject.getMetadata().getUserMetadata().get("a"), "a"); + + } finally { + returnContainer(containerName); + } + } }