|
20 | 20 | import static org.junit.Assert.assertTrue; |
21 | 21 |
|
22 | 22 | import com.google.cloud.storage.SignatureInfo.Builder; |
| 23 | +import com.google.common.hash.Hashing; |
23 | 24 | import java.net.URI; |
| 25 | +import java.nio.charset.StandardCharsets; |
24 | 26 | import java.util.HashMap; |
25 | 27 | import java.util.Map; |
26 | 28 | import org.junit.Test; |
@@ -98,4 +100,39 @@ public void constructV4QueryString() { |
98 | 100 | + "auto%2Fstorage%2Fgoog4_request&X-Goog-Date=20010909T014640Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host", |
99 | 101 | queryString); |
100 | 102 | } |
| 103 | + |
| 104 | + @Test |
| 105 | + public void constructV4UnsignedPayloadWithContentSha256Header() { |
| 106 | + Builder builder = new SignatureInfo.Builder(HttpMethod.PUT, 10L, URI.create(RESOURCE)); |
| 107 | + builder.setSignatureVersion(Storage.SignUrlOption.SignatureVersion.V4); |
| 108 | + builder. setAccountEmail( "[email protected]"); |
| 109 | + builder.setTimestamp(1000000000000L); |
| 110 | + |
| 111 | + Map<String, String> extensionHeaders = new HashMap<>(); |
| 112 | + // Add the header with a lowercase key, which triggers the bug. |
| 113 | + String contentSha256 = "sha256"; |
| 114 | + extensionHeaders.put("X-goog-content-sha256", contentSha256); |
| 115 | + builder.setCanonicalizedExtensionHeaders(extensionHeaders); |
| 116 | + |
| 117 | + // This is the payload hash that SHOULD be generated |
| 118 | + String correctCanonicalRequest = |
| 119 | + "PUT\n" |
| 120 | + + "/bucketName/blobName\n" |
| 121 | + + "X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=me%40google.com%2F20010909%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20010909T014640Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host%3Bx-goog-content-sha256\n" |
| 122 | + + "host:storage.googleapis.com\n" |
| 123 | + + "x-goog-content-sha256:" |
| 124 | + + contentSha256 |
| 125 | + + "\n" |
| 126 | + + "\n" |
| 127 | + + "host;x-goog-content-sha256\n" |
| 128 | + + contentSha256; |
| 129 | + String expectedPayloadHash = |
| 130 | + Hashing.sha256().hashString(correctCanonicalRequest, StandardCharsets.UTF_8).toString(); |
| 131 | + |
| 132 | + String unsignedPayload = builder.build().constructUnsignedPayload(); |
| 133 | + String[] parts = unsignedPayload.split("\n"); |
| 134 | + String generatedPayloadHash = parts[parts.length - 1]; |
| 135 | + |
| 136 | + assertEquals(expectedPayloadHash, generatedPayloadHash); |
| 137 | + } |
101 | 138 | } |
0 commit comments