Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(storage) Add V4 signing support #4692

Merged
merged 42 commits into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d3b121c
Add support for V4 signing
JesseLovelace Nov 28, 2018
71846ac
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 8, 2019
ab931d8
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 18, 2019
d4fb299
(storage) WIP: Add V4 signing support
JesseLovelace Mar 18, 2019
4e30cdc
(storage) Add V4 signing support
JesseLovelace Mar 18, 2019
ddc786c
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 18, 2019
0d7f114
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 18, 2019
8e8ca08
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 20, 2019
d48e8c4
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 20, 2019
7d23539
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 20, 2019
d3acaf1
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 21, 2019
85a0dc2
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 21, 2019
c36cbc3
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 21, 2019
15737c5
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 21, 2019
69d4a17
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 21, 2019
964af50
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 21, 2019
9986c97
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 25, 2019
24bf576
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 25, 2019
7d18fde
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 25, 2019
c5fd070
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 25, 2019
98c31b9
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 25, 2019
e0d0f32
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 26, 2019
9709087
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 26, 2019
ed25ac4
Add V4 samples (#4753)
frankyn Mar 27, 2019
63c42ad
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 26, 2019
ed7e8c4
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Mar 27, 2019
836d7d5
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 27, 2019
022d5ba
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 27, 2019
5534b2f
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Mar 27, 2019
c104811
storage: fix v4 samples (#4754)
frankyn Mar 27, 2019
9fcb46f
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Apr 1, 2019
6d35976
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 1, 2019
54e722c
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 1, 2019
b0a992e
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Apr 1, 2019
7a836e4
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 1, 2019
0e152ec
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 1, 2019
6785005
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 1, 2019
8958a7d
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 1, 2019
b0d677d
Merge branch 'master' of github.com:googleapis/google-cloud-java into…
JesseLovelace Apr 3, 2019
d94d805
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 3, 2019
b249848
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 3, 2019
aa837fd
Merge branch 'v4support' of github.com:googleapis/google-cloud-java i…
JesseLovelace Apr 3, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ public class CanonicalExtensionHeadersSerializer {
private static final char HEADER_SEPARATOR = ':';
private static final char HEADER_NAME_SEPARATOR = ';';

public StringBuilder serialize(Map<String, String> canonicalizedExtensionHeaders) {
public StringBuilder serialize(Map<String, String> canonicalizedExtensionHeaders, boolean isV4) {

StringBuilder serializedHeaders = new StringBuilder();

if (canonicalizedExtensionHeaders == null || canonicalizedExtensionHeaders.isEmpty()) {
return serializedHeaders;
}

Map<String, String> lowercaseHeaders = getLowercaseHeaders(canonicalizedExtensionHeaders);
Map<String, String> lowercaseHeaders = getLowercaseHeaders(canonicalizedExtensionHeaders, isV4);

// Sort all custom headers by header name using a lexicographical sort by code point value.
List<String> sortedHeaderNames = new ArrayList<>(lowercaseHeaders.keySet());
Expand All @@ -68,14 +68,18 @@ public StringBuilder serialize(Map<String, String> canonicalizedExtensionHeaders
return serializedHeaders;
}

public StringBuilder serializeHeaderNames(Map<String, String> canonicalizedExtensionHeaders) {
public StringBuilder serialize(Map<String, String> canonicalizedExtensionHeaders) {
return serialize(canonicalizedExtensionHeaders, false);
}

public StringBuilder serializeHeaderNames(
Map<String, String> canonicalizedExtensionHeaders, boolean isV4) {
StringBuilder serializedHeaders = new StringBuilder();

if (canonicalizedExtensionHeaders == null || canonicalizedExtensionHeaders.isEmpty()) {
return serializedHeaders;
}

Map<String, String> lowercaseHeaders = getLowercaseHeaders(canonicalizedExtensionHeaders);
Map<String, String> lowercaseHeaders = getLowercaseHeaders(canonicalizedExtensionHeaders, isV4);

List<String> sortedHeaderNames = new ArrayList<>(lowercaseHeaders.keySet());
Collections.sort(sortedHeaderNames);
Expand All @@ -89,8 +93,12 @@ public StringBuilder serializeHeaderNames(Map<String, String> canonicalizedExten
return serializedHeaders;
}

public StringBuilder serializeHeaderNames(Map<String, String> canonicalizedExtentionHeaders) {
return serializeHeaderNames(canonicalizedExtentionHeaders, true);
}

private Map<String, String> getLowercaseHeaders(
Map<String, String> canonicalizedExtensionHeaders) {
Map<String, String> canonicalizedExtensionHeaders, boolean isV4) {
// Make all custom header names lowercase.
Map<String, String> lowercaseHeaders = new HashMap<>();
for (String headerName : new ArrayList<>(canonicalizedExtensionHeaders.keySet())) {
Expand All @@ -99,7 +107,8 @@ private Map<String, String> getLowercaseHeaders(

// If present, remove the x-goog-encryption-key and x-goog-encryption-key-sha256 headers.
if ("x-goog-encryption-key".equals(lowercaseHeaderName)
|| "x-goog-encryption-key-sha256".equals(lowercaseHeaderName)) {
|| "x-goog-encryption-key-sha256".equals(lowercaseHeaderName)
|| (isV4 && "x-goog-encryption-algorithm".equals(lowercaseHeaderName))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment x-goog-encryption-key and x-goog-encryption-key-sha256 should be removed for both v2 and v4. There's an open question the GCS team if this is the case moving forward. (no-op for now).

How does knowing v4 help here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"x-goog-encryption-key" and "x-goog-encryption-key-sha256" are removed for both v2 and v4 here. "x-goog-encyrption-algorithm" is only removed for v4 here (C# does this as well) which is why there's a check

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linking you to an internal bug: 128647687. This should be clarified when we get a response there.


continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private String constructV4CanonicalRequestHash() {
canonicalRequest.append(constructV4QueryString()).append(COMPONENT_SEPARATOR);

canonicalRequest
.append(serializer.serialize(canonicalizedExtensionHeaders))
.append(serializer.serialize(canonicalizedExtensionHeaders, true))
.append(COMPONENT_SEPARATOR);

canonicalRequest
Expand Down Expand Up @@ -175,8 +175,9 @@ public String constructV4QueryString() {
+ "&");
queryString.append("X-Goog-Date=" + exactDate + "&");
queryString.append("X-Goog-Expires=" + expiration + "&");
queryString.append("X-Goog-SignedHeaders=" + signedHeaders.toString());

queryString.append(
"X-Goog-SignedHeaders="
+ UrlEscapers.urlFormParameterEscaper().escape(signedHeaders.toString()));
return queryString.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio

long expiration =
isV4
? duration
? unit.toMillis(duration)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

V4 expects seconds as the unit of expiration. IIUC this is converting it to milliseconds.

: TimeUnit.SECONDS.convert(
getOptions().getClock().millisTime() + unit.toMillis(duration),
TimeUnit.MILLISECONDS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.iam.v1.Binding;
import com.google.iam.v1.IAMPolicyGrpc;
import com.google.iam.v1.SetIamPolicyRequest;
Expand All @@ -104,7 +109,10 @@
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -168,10 +176,15 @@ public static void beforeClass() throws IOException {
remoteStorageHelper = RemoteStorageHelper.create();
storage = remoteStorageHelper.getOptions().getService();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming you're adding integration tests (I think you mentioned it), but I want to make sure they are still added before this is merged.

storage.create( BucketInfo.newBuilder(BUCKET) .setLocation("us") .setLifecycleRules(
ImmutableList.of( new LifecycleRule( LifecycleAction.newDeleteAction(),
LifecycleCondition.newBuilder().setAge(1).build()))) .build());

storage.create(
BucketInfo.newBuilder(BUCKET)
.setLocation("us")
.setLifecycleRules(
ImmutableList.of(
new LifecycleRule(
LifecycleAction.newDeleteAction(),
LifecycleCondition.newBuilder().setAge(1).build())))
.build());

// Prepare KMS KeyRing for CMEK tests
prepareKmsKeys();
Expand Down Expand Up @@ -1841,34 +1854,80 @@ public void testGetSignedUrl() throws IOException {
}
}

public class TestCase {
String description;
String bucket;
String object;
String method;
String expiration;
String timestamp;
String expectedUrl;
JsonObject headers;

public String toString() {
return description;
}
}

@Test
//TODO rewrite this to load JSON conformance tests instead
public void testV4UrlSigning() throws IOException {
public void testV4UrlSigning() throws Exception {
Storage dummyAccountStorage =
remoteStorageHelper
.getOptions()
.toBuilder()
.setClock(
new FakeClock(TimeUnit.NANOSECONDS.convert(1549040400000L, TimeUnit.MILLISECONDS)))
.setCredentials(
ServiceAccountCredentials.fromStream(
new FileInputStream(
new File("src/test/resources/URLSignerV4TestAccount.json"))))
.build()
.getService();
String bucket = "test-bucket";
String object = "test-object";

BlobInfo blob = BlobInfo.newBuilder(bucket, object).build();
Gson gson = new GsonBuilder().create();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JesseLovelace this looks good. I think it should it be in a separate test file outside of integration tests given these tests aren't making a request to the GCS service.


String testCaseJson =
new String(Files.readAllBytes(Paths.get("src/test/resources/URLSignerV4TestData.json")));

JsonArray testCases = gson.fromJson(testCaseJson, JsonArray.class);

for (JsonElement testCaseElement : testCases) {
TestCase testCase = gson.fromJson(testCaseElement, TestCase.class);

dummyAccountStorage =
dummyAccountStorage
.getOptions()
.toBuilder()
.setClock(
new FakeClock(
TimeUnit.NANOSECONDS.convert(
new SimpleDateFormat("yyyyMMdd'T'hhmmss'Z'")
.parse(testCase.timestamp)
.getTime(),
TimeUnit.MILLISECONDS)))
.build()
.getService();

BlobInfo blob = BlobInfo.newBuilder(testCase.bucket, testCase.object).build();

Map<String, String> headers = new HashMap<>();
if (testCase.headers != null) {
for (Map.Entry<String, JsonElement> entry : testCase.headers.entrySet()) {
JsonArray value = entry.getValue().getAsJsonArray();
headers.put(entry.getKey(), value.get(0).getAsString());
}
}

assertEquals(
"https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74",
dummyAccountStorage.signUrl(
blob,
10,
TimeUnit.SECONDS,
Storage.SignUrlOption.httpMethod(HttpMethod.GET),
Storage.SignUrlOption.withV4Signature()).toString());
assertEquals(
testCase.expectedUrl,
dummyAccountStorage
.signUrl(
blob,
Long.valueOf(testCase.expiration),
TimeUnit.MILLISECONDS,
Storage.SignUrlOption.httpMethod(HttpMethod.valueOf(testCase.method)),
Storage.SignUrlOption.withExtHeaders(headers),
Storage.SignUrlOption.withV4Signature())
.toString());
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Assumed constant for all tests:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conformance tests were updated and should be updated here as well.

// - email: test-iam-credentials@dummy-project-id.iam.gserviceaccount.com
// - project: dummy-project-id
[
{
"description": "Simple GET",
"bucket": "test-bucket",
"object": "test-object",
"method": "GET",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74"
},

{
"description": "Simple PUT",
"bucket": "test-bucket",
"object": "test-object",
"method": "PUT",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=8adff1d4285739e31aa68e73767a46bc5511fde377497dbe08481bf5ceb34e29cc9a59921748d8ec3dd4085b7e9b7772a952afedfcdaecb3ae8352275b8b7c867f204e3db85076220a3127a8a9589302fc1181eae13b9b7fe41109ec8cdc93c1e8bac2d7a0cc32a109ca02d06957211326563ab3d3e678a0ba296e298b5fc5e14593c99d444c94724cc4be97015dbff1dca377b508fa0cb7169195de98d0e4ac96c42b918d28c8d92d33e1bd125ce0fb3cd7ad2c45dae65c22628378f6584971b8bf3945b26f2611eb651e9b6a8648970c1ecf386bb71327b082e7296c4e1ee2fc0bdd8983da80af375c817fb1ad491d0bc22c0f51dba0d66e2cffbc90803e47"
},

{
"description": "POST for resumable uploads",
"bucket": "test-bucket",
"object": "test-object",
"method": "POST",
"expiration": 10,
"headers": {
"x-goog-resumable": [ "start" ]
},
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host%3Bx-goog-resumable&X-Goog-Signature=4a6d39b23343cedf4c30782aed4b384001828c79ffa3a080a481ea01a640dea0a0ceb58d67a12cef3b243c3f036bb3799c6ee88e8db3eaf7d0bdd4b70a228d0736e07eaa1ee076aff5c6ce09dff1f1f03a0d8ead0d2893408dd3604fdabff553aa6d7af2da67cdba6790006a70240f96717b98f1a6ccb24f00940749599be7ef72aaa5358db63ddd54b2de9e2d6d6a586eac4fe25f36d86fc6ab150418e9c6fa01b732cded226c6d62fc95b72473a4cc55a8257482583fe66d9ab6ede909eb41516a8690946c3e87b0f2052eb0e97e012a14b2f721c42e6e19b8a1cd5658ea36264f10b9b1ada66b8ed5bf7ed7d1708377ac6e5fe608ae361fb594d2e5b24c54"
},

{
"description": "Vary expiration and timestamp",
"bucket": "test-bucket",
"object": "test-object",
"method": "GET",
"expiration": 20,
"timestamp": "20190301T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190301%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190301T090000Z&X-Goog-Expires=20&X-Goog-SignedHeaders=host&X-Goog-Signature=9669ed5b10664dc594c758296580662912cf4bcc5a4ba0b6bf055bcbf6f34eed7bdad664f534962174a924741a0c273a4f67bc1847cef20192a6beab44223bd9d4fbbd749c407b79997598c30f82ddc269ff47ec09fa3afe74e00616d438df0d96a7d8ad0adacfad1dc3286f864d924fe919fb0dce45d3d975c5afe8e13af2db9cc37ba77835f92f7669b61e94c6d562196c1274529e76cfff1564cc2cad7d5387dc8e12f7a5dfd925685fe92c30b43709eee29fa2f66067472cee5423d1a3a4182fe8cea75c9329d181dc6acad7c393cd04f8bf5bc0515127d8ebd65d80c08e19ad03316053ea60033fd1b1fd85a69c576415da3bf0a3718d9ea6d03e0d66f0"
},

{
"description": "Vary bucket and object",
"bucket": "test-bucket2",
"object": "test-object2",
"method": "GET",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket2/test-object2?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=36e3d58dfd3ec1d2dd2f24b5ee372a71e811ffaa2162a2b871d26728d0354270bc116face87127532969c4a3967ed05b7309af741e19c7202f3167aa8c2ac420b61417d6451442bb91d7c822cd17be8783f01e05372769c88913561d27e6660dd8259f0081a71f831be6c50283626cbf04494ac10c394b29bb3bce74ab91548f58a37118a452693cf0483d77561fc9cac8f1765d2c724994cca46a83517a10157ee0347a233a2aaeae6e6ab5e204ff8fc5f54f90a3efdb8301d9fff5475d58cd05b181affd657f48203f4fb133c3a3d355b8eefbd10d5a0a5fd70d06e9515460ad74e22334b2cba4b29cae4f6f285cdb92d8f3126d7a1479ca3bdb69c207d860"
},

{
"description": "Simple headers",
"bucket": "test-bucket",
"object": "test-object",
"headers": {
"foo": [ "foo-value" ],
"BAR": [ "BAR-value" ]
},
"method": "GET",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=bar%3Bfoo%3Bhost&X-Goog-Signature=68ecd3b008328ed30d91e2fe37444ed7b9b03f28ed4424555b5161980531ef87db1c3a5bc0265aad5640af30f96014c94fb2dba7479c41bfe1c020eb90c0c6d387d4dd09d4a5df8b60ea50eb6b01cdd786a1e37020f5f95eb8f9b6cd3f65a1f8a8a65c9fcb61ea662959efd9cd73b683f8d8804ef4d6d9b2852419b013368842731359d7f9e6d1139032ceca75d5e67cee5fd0192ea2125e5f2955d38d3d50cf116f3a52e6a62de77f6207f5b95aaa1d7d0f8a46de89ea72e7ea30f21286318d7eba0142232b0deb3a1dc9e1e812a981c66b5ffda3c6b01a8a9d113155792309fd53a3acfd054ca7776e8eec28c26480cd1e3c812f67f91d14217f39a606669d"
},

{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jskeet updated the conformance test to include CSEK in pr: googleapis/google-cloud-dotnet#2954

"description": "Headers should be trimmed",
"bucket": "test-bucket",
"object": "test-object",
"headers": {
"leading": [ " xyz" ],
"trailing": [ "abc " ],
"collapsed": [ "abc def" ]
},
"method": "GET",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=collapsed%3Bhost%3Bleading%3Btrailing&X-Goog-Signature=1839511d6238d9ac2bbcbba8b23515b3757db35dfa7b8f9bc4b8b4aa270224df747c812526f1a3bcf294d67ed84cd14e074c36bc090e0a542782934a7c925af4a5ea68123e97533704ce8b08ccdf5fe6b412f89c9fc4de243e29abdb098382c5672188ee3f6fef7131413e252c78e7a35658825ad842a50609e9cc463731e17284ff7a14824c989f87cef22fb99dfec20cfeed69d8b3a08f00b43b8284eecd535e50e982b05cd74c5750cd5f986cfc21a2a05f7f3ab7fc31bd684ed1b823b64d29281e923fc6580c49005552ca19c253de087d9d2df881144e44eda40965cfdb4889bf3a35553c9809f4ed20b8355be481b92b9618952b6a04f3017b36053e15"
},

// Headers associated with customer-supplied encryption keys should not be included in the signature
{
"description": "Customer-supplied encryption key",
"bucket": "test-bucket",
"object": "test-object",
"headers":
{
"X-Goog-Encryption-Key": [ "ignored" ],
"X-Goog-Encryption-Key-Sha256": [ "ignored" ],
"X-Goog-Encryption-Algorithm": [ "ignored" ]
},
"method": "GET",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74"
},

{
"description": "List Objects",
"bucket": "test-bucket",
"object": "",
"method": "GET",
"expiration": 10,
"timestamp": "20190201T090000Z",
"expectedUrl": "https://storage.googleapis.com/test-bucket/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=2a1d342f11ddf0c90c669b9ba89ab5099f94049a86351cacbc85845fd5a8b31e1f9c8d484926c19fbd6930da6c8d3049ca8ebcfeefb7b02e53137755d36f97baab479414528b2802f10d94541facb888edf886d91ba124e60cb3801464f61aadc575fc921c99cf8c52e281f7bc0d3e740f529201c469c8e52775b6433687e0c0dca1c6b874614c3c3d09599be1e192c40ad6827416e387bf6e88a5f501f1d8225bce498d134599d0dfe30c9c833c244d3f90cf9595b9f8175658b788ee5c4a90b575fde5e83c645772250c7098373ca754b39d0fc1ebca2f50261a015931541c9827920eba67a1c41613853a1bd23299a1f9f5d583c0feb05ea2f792ba390d27"
}

]