JCLOUDS-1391: Sort headers correctly for signing

This commit is contained in:
Alin Dreghiciu 2018-03-07 20:49:51 +02:00 committed by Andrew Gaul
parent b46eb99140
commit fa88bcc0dd
2 changed files with 68 additions and 11 deletions

View File

@ -23,7 +23,8 @@ import static org.jclouds.util.Patterns.NEWLINE_PATTERN;
import static org.jclouds.util.Strings2.toInputStream; import static org.jclouds.util.Strings2.toInputStream;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -31,6 +32,11 @@ import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; 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.Constants;
import org.jclouds.crypto.Crypto; import org.jclouds.crypto.Crypto;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
@ -50,7 +56,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import com.google.common.io.ByteProcessor; import com.google.common.io.ByteProcessor;
import com.google.common.net.HttpHeaders; import com.google.common.net.HttpHeaders;
@ -150,18 +155,26 @@ public class SharedKeyLiteAuthentication implements HttpRequestFilter {
} }
private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) { private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) {
// TreeSet == Sort the headers alphabetically. // TreeMap == Sort the headers alphabetically.
Set<String> headers = Sets.newTreeSet(request.getHeaders().keySet()); Map<String, String> headers = Maps.newTreeMap();
for (String header : headers) { Multimap<String, String> requestHeaders = request.getHeaders();
for (String header : requestHeaders.keySet()) {
if (header.startsWith("x-ms-")) { if (header.startsWith("x-ms-")) {
toSign.append(header.toLowerCase()).append(":"); String value = Joiner.on(",").join(Iterables.transform(requestHeaders.get(header),
for (String value : request.getHeaders().get(header)) { new Function<String, Object>()
toSign.append(NEWLINE_PATTERN.matcher(value).replaceAll("")).append(","); {
} @Override
toSign.deleteCharAt(toSign.lastIndexOf(",")); public Object apply(final String value) {
toSign.append("\n"); return NEWLINE_PATTERN.matcher(value).replaceAll("");
}
})
);
headers.put(header.toLowerCase(), value);
} }
} }
for (Entry<String, String> entry : headers.entrySet()) {
toSign.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
}
} }
private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) { private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {

View File

@ -19,10 +19,21 @@ package org.jclouds.azureblob.blobstore.integration;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutionException; 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.integration.internal.BaseBlobIntegrationTest;
import org.jclouds.blobstore.options.CopyOptions;
import org.testng.SkipException; import org.testng.SkipException;
import org.testng.annotations.Test; 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") @Test(groups = "live")
public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest { public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
@Override @Override
@ -64,4 +75,37 @@ public class AzureBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
public void testPutBlobAccessMultipart() throws Exception { public void testPutBlobAccessMultipart() throws Exception {
super.testPutBlobAccessMultipart(); super.testPutBlobAccessMultipart();
} }
@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);
}
}
} }