From 4dcfe960521a2d8235a925f6e9f4be0b02af515f Mon Sep 17 00:00:00 2001 From: rsimion Date: Mon, 18 Mar 2019 12:30:16 -0400 Subject: [PATCH 01/16] Create signed URL V4 conformance tests --- google/cloud/storage/tests/CMakeLists.txt | 1 + .../storage/tests/UrlSignerV4TestAccount.json | 12 + .../storage/tests/UrlSignerV4TestData.json | 137 ++++++++++ .../tests/client_sign_url_integration_test.cc | 233 ++++++++++++++++++ .../tests/run_integration_tests_testbench.sh | 7 + .../storage_client_integration_tests.bzl | 1 + 6 files changed, 391 insertions(+) create mode 100644 google/cloud/storage/tests/UrlSignerV4TestAccount.json create mode 100644 google/cloud/storage/tests/UrlSignerV4TestData.json create mode 100644 google/cloud/storage/tests/client_sign_url_integration_test.cc diff --git a/google/cloud/storage/tests/CMakeLists.txt b/google/cloud/storage/tests/CMakeLists.txt index b57ffe7e381fe..73fd7e85d00bc 100644 --- a/google/cloud/storage/tests/CMakeLists.txt +++ b/google/cloud/storage/tests/CMakeLists.txt @@ -16,6 +16,7 @@ set(storage_client_integration_tests bucket_integration_test.cc + client_sign_url_integration_test.cc curl_upload_request_integration_test.cc curl_download_request_integration_test.cc curl_request_integration_test.cc diff --git a/google/cloud/storage/tests/UrlSignerV4TestAccount.json b/google/cloud/storage/tests/UrlSignerV4TestAccount.json new file mode 100644 index 0000000000000..a8a93b8aab460 --- /dev/null +++ b/google/cloud/storage/tests/UrlSignerV4TestAccount.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "dummy-project-id", + "private_key_id": "ffffffffffffffffffffffffffffffffffffffff", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCsPzMirIottfQ2\nryjQmPWocSEeGo7f7Q4/tMQXHlXFzo93AGgU2t+clEj9L5loNhLVq+vk+qmnyDz5\nQ04y8jVWyMYzzGNNrGRW/yaYqnqlKZCy1O3bmnNjV7EDbC/jE1ZLBY0U3HaSHfn6\nS9ND8MXdgD0/ulRTWwq6vU8/w6i5tYsU7n2LLlQTl1fQ7/emO9nYcCFJezHZVa0H\nmeWsdHwWsok0skwQYQNIzP3JF9BpR5gJT2gNge6KopDesJeLoLzaX7cUnDn+CAnn\nLuLDwwSsIVKyVxhBFsFXPplgpaQRwmGzwEbf/Xpt9qo26w2UMgn30jsOaKlSeAX8\ncS6ViF+tAgMBAAECggEACKRuJCP8leEOhQziUx8Nmls8wmYqO4WJJLyk5xUMUC22\nSI4CauN1e0V8aQmxnIc0CDkFT7qc9xBmsMoF+yvobbeKrFApvlyzNyM7tEa/exh8\nDGD/IzjbZ8VfWhDcUTwn5QE9DCoon9m1sG+MBNlokB3OVOt8LieAAREdEBG43kJu\nyQTOkY9BGR2AY1FnAl2VZ/jhNDyrme3tp1sW1BJrawzR7Ujo8DzlVcS2geKA9at7\n55ua5GbHz3hfzFgjVXDfnkWzId6aHypUyqHrSn1SqGEbyXTaleKTc6Pgv0PgkJjG\nhZazWWdSuf1T5Xbs0OhAK9qraoAzT6cXXvMEvvPt6QKBgQDXcZKqJAOnGEU4b9+v\nOdoh+nssdrIOBNMu1m8mYbUVYS1aakc1iDGIIWNM3qAwbG+yNEIi2xi80a2RMw2T\n9RyCNB7yqCXXVKLBiwg9FbKMai6Vpk2bWIrzahM9on7AhCax/X2AeOp+UyYhFEy6\nUFG4aHb8THscL7b515ukSuKb5QKBgQDMq+9PuaB0eHsrmL6q4vHNi3MLgijGg/zu\nAXaPygSYAwYW8KglcuLZPvWrL6OG0+CrfmaWTLsyIZO4Uhdj7MLvX6yK7IMnagvk\nL3xjgxSklEHJAwi5wFeJ8ai/1MIuCn8p2re3CbwISKpvf7Sgs/W4196P4vKvTiAz\njcTiSYFIKQKBgCjMpkS4O0TakMlGTmsFnqyOneLmu4NyIHgfPb9cA4n/9DHKLKAT\noaWxBPgatOVWs7RgtyGYsk+XubHkpC6f3X0+15mGhFwJ+CSE6tN+l2iF9zp52vqP\nQwkjzm7+pdhZbmaIpcq9m1K+9lqPWJRz/3XXuqi+5xWIZ7NaxGvRjqaNAoGAdK2b\nutZ2y48XoI3uPFsuP+A8kJX+CtWZrlE1NtmS7tnicdd19AtfmTuUL6fz0FwfW4Su\nlQZfPT/5B339CaEiq/Xd1kDor+J7rvUHM2+5p+1A54gMRGCLRv92FQ4EON0RC1o9\nm2I4SHysdO3XmjmdXmfp4BsgAKJIJzutvtbqlakCgYB+Cb10z37NJJ+WgjDt+yT2\nyUNH17EAYgWXryfRgTyi2POHuJitd64Xzuy6oBVs3wVveYFM6PIKXlj8/DahYX5I\nR2WIzoCNLL3bEZ+nC6Jofpb4kspoAeRporj29SgesK6QBYWHWX2H645RkRGYGpDo\n51gjy9m/hSNqBbH2zmh04A==\n-----END PRIVATE KEY-----\n", + "client_email": "test-iam-credentials@dummy-project-id.iam.gserviceaccount.com", + "client_id": "000000000000000000000", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com" +} diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json new file mode 100644 index 0000000000000..fe4bfb11eab17 --- /dev/null +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -0,0 +1,137 @@ +[ + { + "description": "Simple GET", + "bucket": "test-bucket", + "object": "test-object", + "method": "GET", + "expiration": 10, + "timestamp": "2019-02-01T09:00:00Z", + "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": "2019-02-01T09:00:00Z", + "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": "2019-02-01T09:00:00Z", + "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": "2019-02-01T09:00:00Z", + "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": "2019-02-01T09:00:00Z", + "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": "2019-02-01T09:00:00Z", + "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" + }, + + { + "description": "Multi-value headers", + "bucket": "test-bucket", + "object": "test-object", + "headers": { + "foo": [ "foo-value1", "foo-value2" ], + "bar": [ "bar-value1", "bar-value2" ] + }, + "method": "GET", + "expiration": 10, + "timestamp": "2019-02-01T09:00:00Z", + "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=84a14ff388457290bc3ed7bfeb4745a1c2287e58965457d9d9959326fc2cbdfbb9128b6a002e86d617cb1d2187e3e075de223489d4e91418de76e21d4e561c618bc13ac72e1cc3b4e0c9eee880be577c417eb4623347d3d1ffd2a0705ab70bab6786f67107d05dc4652f2b84531dc01a15efa9ee3fbe504f6e76e64658fd1df431bf671a997db8ef7371eae8abbcc2690c085407738e32f396d9b87d0e974740ee0b7a256fc8471db27a6b554527b96dbd972073b89f57d6486182816b0d307875f1753bf16140332c6116899447769dd9f1985a520ca6ab50c614a80b3619e9d9a81ff81a6c14f51f1cf487243c2708aa9064e30acb5694af04c3fe0f5fd5a4" + }, + + { + "description": "Headers should be trimmed", + "bucket": "test-bucket", + "object": "test-object", + "headers": { + "leading": [ " xyz" ], + "trailing": [ "abc " ], + "collapsed": [ "abc def" ] + }, + "method": "GET", + "expiration": 10, + "timestamp": "2019-02-01T09:00:00Z", + "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" + }, + + { + "description": "Trimming of multiple header values", + "bucket": "test-bucket", + "object": "test-object", + "headers": { + "foo": [ " abc ", " def ", " ghi jkl " ] + }, + "method": "GET", + "expiration": 10, + "timestamp": "2019-02-01T09:00:00Z", + "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=foo%3Bhost&X-Goog-Signature=96e36a82dd79e6d37070b5dfaffc616e8c5159c583261dd3858c2241c2a34f270f4fe2bf55ba6877a7c982f34b0b9114683ba37880e3ec378942972882dbcb99c6463573178c6167acc40b2be8db7f3a320de47373c30626a37fe9e6cc719ee6060f573bf1a30ef5e86338e834494c089226bef3722bf8ae2fa3a7599916bec92df30cf25852c3514e3be0f4541063cea2babf4825b8e38876454f1502f5e307d32381aa927113104a75c82a23f7e9597016ca0bc4971d5990515df2a0239a62c711d3aacea50b8e05106ae2a14201bd6dae369334c27fad5c14dac66103c5c1a980b3de263e85fe715010e603a518eaf6286b7beb24ca84b97752485c423f0a" + }, + + { + "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": "2019-02-01T09:00:00Z", + "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": "2019-02-01T09:00:00Z", + "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" + } + +] diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc new file mode 100644 index 0000000000000..fa4929fe29bf0 --- /dev/null +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -0,0 +1,233 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/storage/client.h" +#include "google/cloud/storage/internal/nljson.h" +#include "google/cloud/storage/list_objects_reader.h" +#include "google/cloud/storage/testing/storage_integration_test.h" +#include "google/cloud/testing_util/assert_ok.h" +#include "google/cloud/testing_util/init_google_mock.h" +#include +#include + +namespace nl = google::cloud::storage::internal::nl; + +namespace google { +namespace cloud { +namespace storage { +inline namespace STORAGE_CLIENT_NS { +namespace { + +using ::google::cloud::storage::testing::TestPermanentFailure; + +using ::testing::HasSubstr; + +/// Store the file names captured from the command-line arguments. +class ObjectTestEnvironment : public ::testing::Environment { + public: + ObjectTestEnvironment(std::string account_file_name, + std::string data_file_name) { + account_file_name_ = std::move(account_file_name); + all_file_name_ = std::move(data_file_name); + } + + static std::string const& account_file_name() { return account_file_name_; } + static std::string const& data_file_name() { return all_file_name_; } + + private: + static std::string account_file_name_; + static std::string all_file_name_; +}; + +std::string ObjectTestEnvironment::account_file_name_; +std::string ObjectTestEnvironment::all_file_name_; + +class ObjectIntegrationTest + : public google::cloud::storage::testing::StorageIntegrationTest {}; + +TEST_F(ObjectIntegrationTest, V4SignGet) { + // This test uses a disabled key to create a V4 Signed URL for a GET + // operation. The bucket name was generated at random too. + + // This is a dummy service account JSON file that is inactive. It's fine for + // it to be public. + std::string accountFile = ObjectTestEnvironment::account_file_name(); + std::string dataFile = ObjectTestEnvironment::data_file_name(); + + std::ifstream ifs(accountFile); + + if (!ifs.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + accountFile + '\n'; + return; + } + nl::json jsonObj; + jsonObj = nl::json::parse(ifs); + + // Turn json object into a string + std::string file_contents = jsonObj.dump(); + std::string kJsonKeyfileContentsForV4 = file_contents; + + auto creds = oauth2::CreateServiceAccountCredentialsFromJsonContents( + kJsonKeyfileContentsForV4); + + ASSERT_STATUS_OK(creds); + Client client(*creds); + + std::ifstream ifstr(dataFile); + + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + dataFile + '\n'; + return; + } + + nl::json jArray; + nl::json jObj; + jArray = nl::json::parse(ifstr); + + for (nl::json::iterator it = jArray.begin(); it != jArray.end(); ++it) { + jObj = *it; + if (jObj["method"] == "GET") { + std::string const method_name = jObj["method"]; // GET + std::string const bucket_name = jObj["bucket"]; + std::string const object_name = jObj["object"]; + std::string const date = jObj["timestamp"]; + int validInt = jObj["expiration"]; + auto const valid_for = std::chrono::seconds(validInt); + + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com")); + ASSERT_STATUS_OK(actual); + + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + + std::string const expected = jObj["expectedUrl"]; + EXPECT_EQ(expected, *actual); + return; + } + } +} + +TEST_F(ObjectIntegrationTest, V4SignPut) { + // This test uses a disabled key to create a V4 Signed URL for a GET + // operation. The bucket name was generated at random too. + + // This is a dummy service account JSON file that is inactive. It's fine for + // it to be public. + std::string accountFile = ObjectTestEnvironment::account_file_name(); + std::string dataFile = ObjectTestEnvironment::data_file_name(); + + std::ifstream ifs(accountFile); + + if (!ifs.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + accountFile + '\n'; + return; + } + nl::json jsonObj; + jsonObj = nl::json::parse(ifs); + + // Turn json object into a string + std::string file_contents = jsonObj.dump(); + std::string kJsonKeyfileContentsForV4 = file_contents; + + auto creds = oauth2::CreateServiceAccountCredentialsFromJsonContents( + kJsonKeyfileContentsForV4); + + ASSERT_STATUS_OK(creds); + Client client(*creds); + + std::ifstream ifstr(dataFile); + + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + dataFile + '\n'; + return; + } + + nl::json jArray; + nl::json jObj; + jArray = nl::json::parse(ifstr); + + for (nl::json::iterator it = jArray.begin(); it != jArray.end(); ++it) { + jObj = *it; + if (jObj["method"] == "POST") { + std::string const method_name = jObj["method"]; // POST + std::string const bucket_name = jObj["bucket"]; + std::string const object_name = jObj["object"]; + std::string const date = jObj["timestamp"]; + + std::string key_name; + std::string header_name; + for (auto& x : jObj["headers"].items()) { + key_name = x.key(); + header_name = x.value()[0]; + } + + int validInt = jObj["expiration"]; + auto const valid_for = std::chrono::seconds(validInt); + + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_name, header_name)); + + ASSERT_STATUS_OK(actual); + + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + + std::string const expected = jObj["expectedUrl"]; + EXPECT_EQ(expected, *actual); + return; + } + } +} +} // namespace +} // namespace STORAGE_CLIENT_NS +} // namespace storage +} // namespace cloud +} // namespace google + +int main(int argc, char* argv[]) { + google::cloud::testing_util::InitGoogleMock(argc, argv); + + // Make sure the arguments are valid. + if (argc != 3) { + std::string const cmd = argv[0]; + auto last_slash = std::string(argv[0]).find_last_of('/'); + std::cerr << "Usage: " << cmd.substr(last_slash + 1) + << " \n"; + return 1; + } + + std::string const account_file_name = argv[1]; + std::string const data_file_name = argv[2]; + (void)::testing::AddGlobalTestEnvironment( + new google::cloud::storage::ObjectTestEnvironment(account_file_name, + data_file_name)); + + return RUN_ALL_TESTS(); +} diff --git a/google/cloud/storage/tests/run_integration_tests_testbench.sh b/google/cloud/storage/tests/run_integration_tests_testbench.sh index 69ba45d92155a..821391d697ac1 100755 --- a/google/cloud/storage/tests/run_integration_tests_testbench.sh +++ b/google/cloud/storage/tests/run_integration_tests_testbench.sh @@ -30,6 +30,10 @@ export TOPIC_NAME="projects/${PROJECT_ID}/topics/fake-topic-$(date +%s)" export LOCATION="fake-region1" readonly SERVICE_ACCOUNT="fake-service-account@example.com" + +readonly TEST_ACCOUNT_FILE="${PROJECT_ROOT}/google/cloud/storage/tests/UrlSignerV4TestAccount.json" +readonly TEST_DATA_FILE="${PROJECT_ROOT}/google/cloud/storage/tests/UrlSignerV4TestData.json" + echo echo "Running Storage integration tests against local servers." start_testbench @@ -94,6 +98,9 @@ echo echo "Running GCS Projects.serviceAccount integration tests." ./service_account_integration_test "${PROJECT_ID}" "${SERVICE_ACCOUNT}" +echo +echo "Running Storage integration tests against local servers." +./client_sign_url_integration_test "${TEST_ACCOUNT_FILE}" "${TEST_DATA_FILE}" # The tests were successful, so disable dumping of test bench log during # shutdown. TESTBENCH_DUMP_LOG=no diff --git a/google/cloud/storage/tests/storage_client_integration_tests.bzl b/google/cloud/storage/tests/storage_client_integration_tests.bzl index 9904aced4b2b6..2848123d5171c 100644 --- a/google/cloud/storage/tests/storage_client_integration_tests.bzl +++ b/google/cloud/storage/tests/storage_client_integration_tests.bzl @@ -18,6 +18,7 @@ storage_client_integration_tests = [ "bucket_integration_test.cc", + "client_sign_url_integration_test.cc", "curl_upload_request_integration_test.cc", "curl_download_request_integration_test.cc", "curl_request_integration_test.cc", From a66e66f79ebc39a4dfe3ede0cbe80a5eb8987fc8 Mon Sep 17 00:00:00 2001 From: rsimion Date: Mon, 18 Mar 2019 14:46:36 -0400 Subject: [PATCH 02/16] Cchanges to simplify the code --- .../tests/client_sign_url_integration_test.cc | 140 +++++------------- .../tests/run_integration_tests_testbench.sh | 3 +- 2 files changed, 43 insertions(+), 100 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index fa4929fe29bf0..5bbe4a6af001d 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -28,30 +28,11 @@ namespace cloud { namespace storage { inline namespace STORAGE_CLIENT_NS { namespace { - -using ::google::cloud::storage::testing::TestPermanentFailure; - using ::testing::HasSubstr; -/// Store the file names captured from the command-line arguments. -class ObjectTestEnvironment : public ::testing::Environment { - public: - ObjectTestEnvironment(std::string account_file_name, - std::string data_file_name) { - account_file_name_ = std::move(account_file_name); - all_file_name_ = std::move(data_file_name); - } - - static std::string const& account_file_name() { return account_file_name_; } - static std::string const& data_file_name() { return all_file_name_; } - - private: - static std::string account_file_name_; - static std::string all_file_name_; -}; - -std::string ObjectTestEnvironment::account_file_name_; -std::string ObjectTestEnvironment::all_file_name_; +// Initialized in main() below. +char const* account_file_name_; +char const* data_file_name_; class ObjectIntegrationTest : public google::cloud::storage::testing::StorageIntegrationTest {}; @@ -62,51 +43,33 @@ TEST_F(ObjectIntegrationTest, V4SignGet) { // This is a dummy service account JSON file that is inactive. It's fine for // it to be public. - std::string accountFile = ObjectTestEnvironment::account_file_name(); - std::string dataFile = ObjectTestEnvironment::data_file_name(); - - std::ifstream ifs(accountFile); - - if (!ifs.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + accountFile + '\n'; - return; - } - nl::json jsonObj; - jsonObj = nl::json::parse(ifs); - - // Turn json object into a string - std::string file_contents = jsonObj.dump(); - std::string kJsonKeyfileContentsForV4 = file_contents; + std::string account_file = account_file_name_; + std::string data_file = data_file_name_; - auto creds = oauth2::CreateServiceAccountCredentialsFromJsonContents( - kJsonKeyfileContentsForV4); + auto creds = + oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); ASSERT_STATUS_OK(creds); Client client(*creds); - std::ifstream ifstr(dataFile); - + std::ifstream ifstr(data_file); if (!ifstr.is_open()) { // If the file does not exist, or // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + dataFile + '\n'; + std::cout << "Cannot open credentials file " + data_file + '\n'; return; } - nl::json jArray; - nl::json jObj; - jArray = nl::json::parse(ifstr); - - for (nl::json::iterator it = jArray.begin(); it != jArray.end(); ++it) { - jObj = *it; - if (jObj["method"] == "GET") { - std::string const method_name = jObj["method"]; // GET - std::string const bucket_name = jObj["bucket"]; - std::string const object_name = jObj["object"]; - std::string const date = jObj["timestamp"]; - int validInt = jObj["expiration"]; + nl::json json_array; + json_array = nl::json::parse(ifstr); + + for (auto const& j_obj : json_array) { + if (j_obj["method"] == "GET") { + std::string const method_name = j_obj["method"]; // GET + std::string const bucket_name = j_obj["bucket"]; + std::string const object_name = j_obj["object"]; + std::string const date = j_obj["timestamp"]; + int validInt = j_obj["expiration"]; auto const valid_for = std::chrono::seconds(validInt); auto actual = client.CreateV4SignedUrl( @@ -119,72 +82,54 @@ TEST_F(ObjectIntegrationTest, V4SignGet) { EXPECT_THAT(*actual, HasSubstr(bucket_name)); EXPECT_THAT(*actual, HasSubstr(object_name)); - std::string const expected = jObj["expectedUrl"]; + std::string const expected = j_obj["expectedUrl"]; EXPECT_EQ(expected, *actual); return; } } } -TEST_F(ObjectIntegrationTest, V4SignPut) { +TEST_F(ObjectIntegrationTest, V4SignPost) { // This test uses a disabled key to create a V4 Signed URL for a GET // operation. The bucket name was generated at random too. // This is a dummy service account JSON file that is inactive. It's fine for // it to be public. - std::string accountFile = ObjectTestEnvironment::account_file_name(); - std::string dataFile = ObjectTestEnvironment::data_file_name(); - - std::ifstream ifs(accountFile); - - if (!ifs.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + accountFile + '\n'; - return; - } - nl::json jsonObj; - jsonObj = nl::json::parse(ifs); - - // Turn json object into a string - std::string file_contents = jsonObj.dump(); - std::string kJsonKeyfileContentsForV4 = file_contents; + std::string account_file = account_file_name_; + std::string data_file = data_file_name_; - auto creds = oauth2::CreateServiceAccountCredentialsFromJsonContents( - kJsonKeyfileContentsForV4); + auto creds = + oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); ASSERT_STATUS_OK(creds); Client client(*creds); - std::ifstream ifstr(dataFile); - + std::ifstream ifstr(data_file); if (!ifstr.is_open()) { // If the file does not exist, or // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + dataFile + '\n'; + std::cout << "Cannot open credentials file " + data_file + '\n'; return; } - nl::json jArray; - nl::json jObj; - jArray = nl::json::parse(ifstr); + nl::json json_array; + json_array = nl::json::parse(ifstr); - for (nl::json::iterator it = jArray.begin(); it != jArray.end(); ++it) { - jObj = *it; - if (jObj["method"] == "POST") { - std::string const method_name = jObj["method"]; // POST - std::string const bucket_name = jObj["bucket"]; - std::string const object_name = jObj["object"]; - std::string const date = jObj["timestamp"]; + for (auto const& j_obj : json_array) { + if (j_obj["method"] == "POST") { + std::string const method_name = j_obj["method"]; // POST + std::string const bucket_name = j_obj["bucket"]; + std::string const object_name = j_obj["object"]; + std::string const date = j_obj["timestamp"]; std::string key_name; std::string header_name; - for (auto& x : jObj["headers"].items()) { + for (auto& x : j_obj["headers"].items()) { key_name = x.key(); header_name = x.value()[0]; } - int validInt = jObj["expiration"]; + int validInt = j_obj["expiration"]; auto const valid_for = std::chrono::seconds(validInt); auto actual = client.CreateV4SignedUrl( @@ -195,16 +140,16 @@ TEST_F(ObjectIntegrationTest, V4SignPut) { AddExtensionHeader(key_name, header_name)); ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); EXPECT_THAT(*actual, HasSubstr(object_name)); - std::string const expected = jObj["expectedUrl"]; + std::string const expected = j_obj["expectedUrl"]; EXPECT_EQ(expected, *actual); return; } } } + } // namespace } // namespace STORAGE_CLIENT_NS } // namespace storage @@ -223,11 +168,8 @@ int main(int argc, char* argv[]) { return 1; } - std::string const account_file_name = argv[1]; - std::string const data_file_name = argv[2]; - (void)::testing::AddGlobalTestEnvironment( - new google::cloud::storage::ObjectTestEnvironment(account_file_name, - data_file_name)); + google::cloud::storage::account_file_name_ = argv[1]; + google::cloud::storage::data_file_name_ = argv[2]; return RUN_ALL_TESTS(); } diff --git a/google/cloud/storage/tests/run_integration_tests_testbench.sh b/google/cloud/storage/tests/run_integration_tests_testbench.sh index 821391d697ac1..8532380a8dfd7 100755 --- a/google/cloud/storage/tests/run_integration_tests_testbench.sh +++ b/google/cloud/storage/tests/run_integration_tests_testbench.sh @@ -99,8 +99,9 @@ echo "Running GCS Projects.serviceAccount integration tests." ./service_account_integration_test "${PROJECT_ID}" "${SERVICE_ACCOUNT}" echo -echo "Running Storage integration tests against local servers." +echo "Running storage::internal::ClientSignUrl integration test." ./client_sign_url_integration_test "${TEST_ACCOUNT_FILE}" "${TEST_DATA_FILE}" + # The tests were successful, so disable dumping of test bench log during # shutdown. TESTBENCH_DUMP_LOG=no From 5599910194021eba78b80b321d4f6992596c1cdd Mon Sep 17 00:00:00 2001 From: rsimion Date: Mon, 18 Mar 2019 17:09:35 -0400 Subject: [PATCH 03/16] Some changes in the json file and integration test file --- google/cloud/storage/tests/UrlSignerV4TestData.json | 13 ++++++------- .../tests/client_sign_url_integration_test.cc | 2 -- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index fe4bfb11eab17..b3431705c427a 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -39,7 +39,7 @@ "method": "GET", "expiration": 20, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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=20&X-Goog-SignedHeaders=host&X-Goog-Signature=34c2ecf91821862880143069bc06f818495116ca95d132a87169b6d244774f3df4a9f12615169ecd81b4d5c9694ffaa2710b3d21557901c9a1bd712d59ebab3afea61f5d9885874267bde6bf82b5618d44cbaa28ed0f77b23c7f9853b58466031152678f8f57df0a38e264ab7a6f617d4f749b93cc1e8a9d310aa1481010da069679244acb929b0cc9e65fcab5cf1cbb502e1ca1b8df29f33ba0d24d37c9bfd35dd8508f473a99e9814fb57014759e054b5b39d1119ffd1c041e5da643ed434856c3de51f96d7bf268ae4ddeb2509256fdddf3d0e30b6571ffebbccef122e5f867be70fd32e025000096290590f8692f5f0a46ea97526d6eee87db3b4950fce9" }, { @@ -63,7 +63,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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" }, { @@ -77,7 +77,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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=84a14ff388457290bc3ed7bfeb4745a1c2287e58965457d9d9959326fc2cbdfbb9128b6a002e86d617cb1d2187e3e075de223489d4e91418de76e21d4e561c618bc13ac72e1cc3b4e0c9eee880be577c417eb4623347d3d1ffd2a0705ab70bab6786f67107d05dc4652f2b84531dc01a15efa9ee3fbe504f6e76e64658fd1df431bf671a997db8ef7371eae8abbcc2690c085407738e32f396d9b87d0e974740ee0b7a256fc8471db27a6b554527b96dbd972073b89f57d6486182816b0d307875f1753bf16140332c6116899447769dd9f1985a520ca6ab50c614a80b3619e9d9a81ff81a6c14f51f1cf487243c2708aa9064e30acb5694af04c3fe0f5fd5a4" + "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" }, { @@ -92,7 +92,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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" }, { @@ -105,7 +105,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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=foo%3Bhost&X-Goog-Signature=96e36a82dd79e6d37070b5dfaffc616e8c5159c583261dd3858c2241c2a34f270f4fe2bf55ba6877a7c982f34b0b9114683ba37880e3ec378942972882dbcb99c6463573178c6167acc40b2be8db7f3a320de47373c30626a37fe9e6cc719ee6060f573bf1a30ef5e86338e834494c089226bef3722bf8ae2fa3a7599916bec92df30cf25852c3514e3be0f4541063cea2babf4825b8e38876454f1502f5e307d32381aa927113104a75c82a23f7e9597016ca0bc4971d5990515df2a0239a62c711d3aacea50b8e05106ae2a14201bd6dae369334c27fad5c14dac66103c5c1a980b3de263e85fe715010e603a518eaf6286b7beb24ca84b97752485c423f0a" + "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" }, { @@ -131,7 +131,6 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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=6dbe94f8e52b2b8a9a476b1c857efa474e09944e2b52b925800316e094a7169d8dbe0df9c0ac08dabb22ac7e827470ceccd65f5a3eadba2a4fb9beebfe37f0d9bb1e552b851fa31a25045bdf019e507f5feb44f061551ef1aeb18dcec0e38ba2e2f77d560a46eaace9c56ed9aa642281301a9d848b0eb30749e34bc7f73a3d596240533466ff9b5f289cd0d4c845c7d96b82a35a5abd0c3aff83e4440ee6873e796087f43545544dc8c01afe1d79c726696b6f555371e491980e7ec145cca0803cf562c38f3fa1d724242f5dea25aac91d74ec9ddd739ff65523627763eaef25cd1f95ad985aaf0079b7c74eb5bcb2870a9b137a7b2c8e41fbe838c95872f75b" } - ] diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 5bbe4a6af001d..ec57abdbdd3ed 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -84,7 +84,6 @@ TEST_F(ObjectIntegrationTest, V4SignGet) { std::string const expected = j_obj["expectedUrl"]; EXPECT_EQ(expected, *actual); - return; } } } @@ -145,7 +144,6 @@ TEST_F(ObjectIntegrationTest, V4SignPost) { std::string const expected = j_obj["expectedUrl"]; EXPECT_EQ(expected, *actual); - return; } } } From 54ae86c92bc5fd512266c44001614fd4e41a267a Mon Sep 17 00:00:00 2001 From: rsimion Date: Tue, 19 Mar 2019 07:09:08 -0400 Subject: [PATCH 04/16] Reverted some changes --- .../cloud/storage/tests/UrlSignerV4TestData.json | 16 ++++++++-------- .../tests/client_sign_url_integration_test.cc | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index b3431705c427a..a37c39689c67e 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -39,7 +39,7 @@ "method": "GET", "expiration": 20, "timestamp": "2019-02-01T09:00:00Z", - "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=20&X-Goog-SignedHeaders=host&X-Goog-Signature=34c2ecf91821862880143069bc06f818495116ca95d132a87169b6d244774f3df4a9f12615169ecd81b4d5c9694ffaa2710b3d21557901c9a1bd712d59ebab3afea61f5d9885874267bde6bf82b5618d44cbaa28ed0f77b23c7f9853b58466031152678f8f57df0a38e264ab7a6f617d4f749b93cc1e8a9d310aa1481010da069679244acb929b0cc9e65fcab5cf1cbb502e1ca1b8df29f33ba0d24d37c9bfd35dd8508f473a99e9814fb57014759e054b5b39d1119ffd1c041e5da643ed434856c3de51f96d7bf268ae4ddeb2509256fdddf3d0e30b6571ffebbccef122e5f867be70fd32e025000096290590f8692f5f0a46ea97526d6eee87db3b4950fce9" + "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" }, { @@ -62,10 +62,9 @@ }, "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", - "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" + "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" }, - { "description": "Multi-value headers", "bucket": "test-bucket", @@ -77,7 +76,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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=84a14ff388457290bc3ed7bfeb4745a1c2287e58965457d9d9959326fc2cbdfbb9128b6a002e86d617cb1d2187e3e075de223489d4e91418de76e21d4e561c618bc13ac72e1cc3b4e0c9eee880be577c417eb4623347d3d1ffd2a0705ab70bab6786f67107d05dc4652f2b84531dc01a15efa9ee3fbe504f6e76e64658fd1df431bf671a997db8ef7371eae8abbcc2690c085407738e32f396d9b87d0e974740ee0b7a256fc8471db27a6b554527b96dbd972073b89f57d6486182816b0d307875f1753bf16140332c6116899447769dd9f1985a520ca6ab50c614a80b3619e9d9a81ff81a6c14f51f1cf487243c2708aa9064e30acb5694af04c3fe0f5fd5a4" }, { @@ -92,7 +91,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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" }, { @@ -105,7 +104,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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" + "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=foo%3Bhost&X-Goog-Signature=96e36a82dd79e6d37070b5dfaffc616e8c5159c583261dd3858c2241c2a34f270f4fe2bf55ba6877a7c982f34b0b9114683ba37880e3ec378942972882dbcb99c6463573178c6167acc40b2be8db7f3a320de47373c30626a37fe9e6cc719ee6060f573bf1a30ef5e86338e834494c089226bef3722bf8ae2fa3a7599916bec92df30cf25852c3514e3be0f4541063cea2babf4825b8e38876454f1502f5e307d32381aa927113104a75c82a23f7e9597016ca0bc4971d5990515df2a0239a62c711d3aacea50b8e05106ae2a14201bd6dae369334c27fad5c14dac66103c5c1a980b3de263e85fe715010e603a518eaf6286b7beb24ca84b97752485c423f0a" }, { @@ -131,6 +130,7 @@ "method": "GET", "expiration": 10, "timestamp": "2019-02-01T09:00:00Z", - "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=6dbe94f8e52b2b8a9a476b1c857efa474e09944e2b52b925800316e094a7169d8dbe0df9c0ac08dabb22ac7e827470ceccd65f5a3eadba2a4fb9beebfe37f0d9bb1e552b851fa31a25045bdf019e507f5feb44f061551ef1aeb18dcec0e38ba2e2f77d560a46eaace9c56ed9aa642281301a9d848b0eb30749e34bc7f73a3d596240533466ff9b5f289cd0d4c845c7d96b82a35a5abd0c3aff83e4440ee6873e796087f43545544dc8c01afe1d79c726696b6f555371e491980e7ec145cca0803cf562c38f3fa1d724242f5dea25aac91d74ec9ddd739ff65523627763eaef25cd1f95ad985aaf0079b7c74eb5bcb2870a9b137a7b2c8e41fbe838c95872f75b" + "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" } + ] diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index ec57abdbdd3ed..566ead12492e8 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -64,7 +64,7 @@ TEST_F(ObjectIntegrationTest, V4SignGet) { json_array = nl::json::parse(ifstr); for (auto const& j_obj : json_array) { - if (j_obj["method"] == "GET") { + if (j_obj["method"] == "GET" && j_obj["description"] == "Simple GET") { std::string const method_name = j_obj["method"]; // GET std::string const bucket_name = j_obj["bucket"]; std::string const object_name = j_obj["object"]; From 838663c19557e9400f18519ee44c526afcfc1dfb Mon Sep 17 00:00:00 2001 From: rsimion Date: Tue, 19 Mar 2019 15:15:54 -0400 Subject: [PATCH 05/16] A lot of changes --- .../storage/tests/UrlSignerV4TestData.json | 6 +- .../tests/client_sign_url_integration_test.cc | 268 ++++++++++++++++-- 2 files changed, 253 insertions(+), 21 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index a37c39689c67e..7863958715219 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -38,7 +38,7 @@ "object": "test-object", "method": "GET", "expiration": 20, - "timestamp": "2019-02-01T09:00:00Z", + "timestamp": "2019-03-01T09:00:00Z", "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" }, @@ -62,9 +62,10 @@ }, "method": "GET", "expiration": 10, - "timestamp": "20190201T090000Z", + "timestamp": "2019-02-01T09:00:00Z", "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" }, + { "description": "Multi-value headers", "bucket": "test-bucket", @@ -107,6 +108,7 @@ "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=foo%3Bhost&X-Goog-Signature=96e36a82dd79e6d37070b5dfaffc616e8c5159c583261dd3858c2241c2a34f270f4fe2bf55ba6877a7c982f34b0b9114683ba37880e3ec378942972882dbcb99c6463573178c6167acc40b2be8db7f3a320de47373c30626a37fe9e6cc719ee6060f573bf1a30ef5e86338e834494c089226bef3722bf8ae2fa3a7599916bec92df30cf25852c3514e3be0f4541063cea2babf4825b8e38876454f1502f5e307d32381aa927113104a75c82a23f7e9597016ca0bc4971d5990515df2a0239a62c711d3aacea50b8e05106ae2a14201bd6dae369334c27fad5c14dac66103c5c1a980b3de263e85fe715010e603a518eaf6286b7beb24ca84b97752485c423f0a" }, + { "description": "Customer-supplied encryption key", "bucket": "test-bucket", diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 566ead12492e8..57537be32afc6 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -37,7 +37,232 @@ char const* data_file_name_; class ObjectIntegrationTest : public google::cloud::storage::testing::StorageIntegrationTest {}; -TEST_F(ObjectIntegrationTest, V4SignGet) { +// Testing the objects with the 'headers' field only + +// No "Trimming of multiple header values" +// No "Multi-value headers" + +// as per original file +// https://github.com/googleapis/google-cloud-dotnet/blob/e918df5a988f53ed71cebf708a0dd06bed8bef43/apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Tests/UrlSignerV4TestData.json#L42 + +// Description: "POST for resumable uploads" +// Description: "Simple headers" +// Description: "Headers should be trimmed" + +TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { + // This test uses a disabled key to create a V4 Signed URL for a GET + // operation. The bucket name was generated at random too. + + // This is a dummy service account JSON file that is inactive. It's fine for + // it to be public. + std::string account_file = account_file_name_; + std::string data_file = data_file_name_; + + auto creds = + oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); + + ASSERT_STATUS_OK(creds); + Client client(*creds); + + std::ifstream ifstr(data_file); + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + data_file + '\n'; + return; + } + + nl::json json_array = nl::json::parse(ifstr); + + for (auto const& j_obj : json_array) { + std::string const method_name = j_obj["method"]; // GET + std::string const bucket_name = j_obj["bucket"]; + std::string const object_name = j_obj["object"]; + std::string const date = j_obj["timestamp"]; + int validInt = j_obj["expiration"]; + auto const valid_for = std::chrono::seconds(validInt); + std::string const expected = j_obj["expectedUrl"]; + + // Check for headers field in each j_obj + for (auto& header : j_obj.items()) { + int array_size_per_key = 0; + + if (header.key() == "headers") { + // The size of the headers obj, how many keys it has. + // 1 one key + // 2 two keys or 3 keys + // Each key has an array of 1 or more strings + + std::string key_name; + std::string header_name; + + std::vector key_vector; + std::vector value_vector; + + // Check for the keys of the headers field + for (auto& x : j_obj["headers"].items()) { + // Each key + key_name = x.key(); + key_vector.emplace_back(key_name); + + // Each key has an array as value + array_size_per_key = x.value().size(); + + // Only one value per key : key : [value] + header_name = x.value()[0]; + value_vector.emplace_back(header_name); + } + + // Only headers with key : [ value ] + // not key : [ value1, value2 ] + + // No Customer-supplied encryption key + // see the original file + // All the fields in the header that have only one value per key + if (array_size_per_key == 1 && + j_obj["description"] != "Customer-supplied encryption key") { + std::cout << "Description: " + << " " << j_obj["description"] << '\n'; + + // Check size of keys + // key : [ value] + if (key_vector.size() == 1) { + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_vector.at(0), value_vector.at(0))); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + + } + + // 2 key : [value] pairs + else if (key_vector.size() == 2) { + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_vector.at(0), value_vector.at(0)), + AddExtensionHeader(key_vector.at(1), value_vector.at(1))); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + + } + + // 3 key : [value ] pairs + else if (key_vector.size() == 3) { + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_vector.at(0), value_vector.at(0)), + AddExtensionHeader(key_vector.at(1), value_vector.at(1)), + AddExtensionHeader(key_vector.at(2), value_vector.at(2))); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } + } + } + } + } +} + +// Testing all the objects without the 'headers' key +// No "List Objects" +// description: "Simple GET" +// description: "Simple PUT" +// description: "Vary expiration and timestamp" +// description: "Vary bucket and object" + +TEST_F(ObjectIntegrationTest, V4SignNoHeaders) { + // This test uses a disabled key to create a V4 Signed URL for a GET + // operation. The bucket name was generated at random too. + + // This is a dummy service account JSON file that is inactive. It's fine for + // it to be public. + std::string account_file = account_file_name_; + std::string data_file = data_file_name_; + + auto creds = + oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); + + ASSERT_STATUS_OK(creds); + Client client(*creds); + + std::ifstream ifstr(data_file); + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + data_file + '\n'; + return; + } + + // nl::json json_array; + nl::json json_array = nl::json::parse(ifstr); + + for (auto const& j_obj : json_array) { + std::string const method_name = j_obj["method"]; // GET + std::string const bucket_name = j_obj["bucket"]; + std::string const object_name = j_obj["object"]; + std::string const date = j_obj["timestamp"]; + int validInt = j_obj["expiration"]; + auto const valid_for = std::chrono::seconds(validInt); + std::string const expected = j_obj["expectedUrl"]; + + std::string header_key; + std::string has_headers = "no"; + + // Check for the 'headers' field in each j_obj + for (auto& header : j_obj.items()) { + header_key = header.key(); + // std::cout << header_key << '\n'; + + if (header_key == "headers") { + has_headers = "yes"; + } + } + + // No "List Objects" + // description: "Simple GET" + // description: "Simple PUT" + // description: "Vary expiration and timestamp" + // description: "Vary bucket and object" + + if (has_headers == "no" && j_obj["description"] != "List Objects") { + std::cout << "Description: " << j_obj["description"] << '\n'; + + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com")); + ASSERT_STATUS_OK(actual); + + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } + } +} + +// Customer-supplied encryption key +// works without using headers +// as mentioned in the original file +// https://github.com/googleapis/google-cloud-dotnet/blob/e918df5a988f53ed71cebf708a0dd06bed8bef43/apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Tests/UrlSignerV4TestData.json#L42 +TEST_F(ObjectIntegrationTest, V4SignGetCustomerSupplied) { // This test uses a disabled key to create a V4 Signed URL for a GET // operation. The bucket name was generated at random too. @@ -60,11 +285,15 @@ TEST_F(ObjectIntegrationTest, V4SignGet) { return; } - nl::json json_array; - json_array = nl::json::parse(ifstr); + // nl::json json_array; + nl::json json_array = nl::json::parse(ifstr); for (auto const& j_obj : json_array) { - if (j_obj["method"] == "GET" && j_obj["description"] == "Simple GET") { + std::string method_description = j_obj["description"]; + + if (j_obj["method"] == "GET" && + method_description == "Customer-supplied encryption key") { + std::cout << "Description: " << method_description << '\n'; std::string const method_name = j_obj["method"]; // GET std::string const bucket_name = j_obj["bucket"]; std::string const object_name = j_obj["object"]; @@ -88,7 +317,10 @@ TEST_F(ObjectIntegrationTest, V4SignGet) { } } -TEST_F(ObjectIntegrationTest, V4SignPost) { +/* +//This does not work the object is empty +//description : "List Objects" +TEST_F(ObjectIntegrationTest, V4SignGetListObjects) { // This test uses a disabled key to create a V4 Signed URL for a GET // operation. The bucket name was generated at random too. @@ -111,34 +343,31 @@ TEST_F(ObjectIntegrationTest, V4SignPost) { return; } - nl::json json_array; - json_array = nl::json::parse(ifstr); + //nl::json json_array; + nl::json json_array = nl::json::parse(ifstr); for (auto const& j_obj : json_array) { - if (j_obj["method"] == "POST") { - std::string const method_name = j_obj["method"]; // POST + if (j_obj["method"] == "GET" && j_obj["description"] == "List Objects") { + + std::cout << j_obj["description"] << '\n'; + + std::string const method_name = j_obj["method"]; // GET std::string const bucket_name = j_obj["bucket"]; std::string const object_name = j_obj["object"]; std::string const date = j_obj["timestamp"]; - - std::string key_name; - std::string header_name; - for (auto& x : j_obj["headers"].items()) { - key_name = x.key(); - header_name = x.value()[0]; - } - int validInt = j_obj["expiration"]; auto const valid_for = std::chrono::seconds(validInt); + auto actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_name, header_name)); + AddExtensionHeader("host", "storage.googleapis.com") + ); ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); EXPECT_THAT(*actual, HasSubstr(object_name)); @@ -147,6 +376,7 @@ TEST_F(ObjectIntegrationTest, V4SignPost) { } } } +*/ } // namespace } // namespace STORAGE_CLIENT_NS From 94d62f998c72819453c48542874a607f8cb14762 Mon Sep 17 00:00:00 2001 From: rsimion Date: Wed, 20 Mar 2019 16:56:31 -0400 Subject: [PATCH 06/16] Major changes in both files --- .../storage/tests/UrlSignerV4TestData.json | 32 +- .../tests/client_sign_url_integration_test.cc | 360 ++++++++---------- 2 files changed, 175 insertions(+), 217 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index 7863958715219..96f35a4c5bbf0 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -1,3 +1,6 @@ +// Assumed constant for all tests: +// - email: test-iam-credentials@dummy-project-id.iam.gserviceaccount.com +// - project: dummy-project-id [ { "description": "Simple GET", @@ -5,7 +8,7 @@ "object": "test-object", "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, @@ -15,7 +18,7 @@ "object": "test-object", "method": "PUT", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, @@ -28,7 +31,7 @@ "headers": { "x-goog-resumable": [ "start" ] }, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, @@ -38,7 +41,7 @@ "object": "test-object", "method": "GET", "expiration": 20, - "timestamp": "2019-03-01T09:00:00Z", + "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" }, @@ -48,7 +51,7 @@ "object": "test-object2", "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, @@ -62,10 +65,12 @@ }, "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, + // Note: some platforms may not expose multi-value headers to clients. They could skip + // this test or perform the concatenation of header values themselves. { "description": "Multi-value headers", "bucket": "test-bucket", @@ -76,7 +81,7 @@ }, "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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=84a14ff388457290bc3ed7bfeb4745a1c2287e58965457d9d9959326fc2cbdfbb9128b6a002e86d617cb1d2187e3e075de223489d4e91418de76e21d4e561c618bc13ac72e1cc3b4e0c9eee880be577c417eb4623347d3d1ffd2a0705ab70bab6786f67107d05dc4652f2b84531dc01a15efa9ee3fbe504f6e76e64658fd1df431bf671a997db8ef7371eae8abbcc2690c085407738e32f396d9b87d0e974740ee0b7a256fc8471db27a6b554527b96dbd972073b89f57d6486182816b0d307875f1753bf16140332c6116899447769dd9f1985a520ca6ab50c614a80b3619e9d9a81ff81a6c14f51f1cf487243c2708aa9064e30acb5694af04c3fe0f5fd5a4" }, @@ -91,10 +96,11 @@ }, "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, + // Separated from "Headers should be trimmed" test so it can be skipped on single-header-value-only platforms. { "description": "Trimming of multiple header values", "bucket": "test-bucket", @@ -104,11 +110,11 @@ }, "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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=foo%3Bhost&X-Goog-Signature=96e36a82dd79e6d37070b5dfaffc616e8c5159c583261dd3858c2241c2a34f270f4fe2bf55ba6877a7c982f34b0b9114683ba37880e3ec378942972882dbcb99c6463573178c6167acc40b2be8db7f3a320de47373c30626a37fe9e6cc719ee6060f573bf1a30ef5e86338e834494c089226bef3722bf8ae2fa3a7599916bec92df30cf25852c3514e3be0f4541063cea2babf4825b8e38876454f1502f5e307d32381aa927113104a75c82a23f7e9597016ca0bc4971d5990515df2a0239a62c711d3aacea50b8e05106ae2a14201bd6dae369334c27fad5c14dac66103c5c1a980b3de263e85fe715010e603a518eaf6286b7beb24ca84b97752485c423f0a" }, - + // Headers associated with customer-supplied encryption keys should not be included in the signature { "description": "Customer-supplied encryption key", "bucket": "test-bucket", @@ -121,7 +127,7 @@ }, "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" }, @@ -131,8 +137,8 @@ "object": "", "method": "GET", "expiration": 10, - "timestamp": "2019-02-01T09:00:00Z", + "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" - } + }, ] diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 57537be32afc6..c4076317e1eff 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -20,6 +20,7 @@ #include "google/cloud/testing_util/init_google_mock.h" #include #include +#include namespace nl = google::cloud::storage::internal::nl; @@ -35,9 +36,121 @@ char const* account_file_name_; char const* data_file_name_; class ObjectIntegrationTest - : public google::cloud::storage::testing::StorageIntegrationTest {}; + : public google::cloud::storage::testing::StorageIntegrationTest { + protected: + std::string trimmedString(std::string data_file) { + std::ifstream ifstr(data_file); + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + data_file + '\n'; + return ""; + } + + std::string from_file((std::istreambuf_iterator(ifstr)), + std::istreambuf_iterator()); + + int from_file_len = from_file.length(); + std::string trimmed; + + // Check whether a character is + // within //.............\n + bool check_comment = false; + + for (int i = 0; i < from_file_len; i++) { + // Check for // + if (i == 0 && from_file[i] == '/' && from_file[i + 1] == '/') { + i++; + check_comment = true; + } -// Testing the objects with the 'headers' field only + // Check for the end of the commented line \n + else if (check_comment == true && from_file[i] == '\n') { + i++; + check_comment = false; + } + + // Check for // only and not for :// + // Do not want to remove https:// + if (from_file[i] == '/' && from_file[i + 1] == '/' && + from_file[i - 1] != ':') { + i++; + check_comment = true; + } + + else if (check_comment == false) { + trimmed += from_file[i]; + } + } + + // Remove the last comma from the string + // }, ] if any + int trimmed_len = trimmed.length(); + std::string final_trimmed_string; + + int final_comma_position = -1; + char square_bracket = ']'; + char comma = ','; + char brace = '}'; + bool comma_check = false; + + for (int i = trimmed_len - 1; i > 0; i--) { + if (isspace(trimmed[i])) { + comma_check = true; + } else if (trimmed[i] == square_bracket && comma_check == true) { + i--; + } else if (trimmed[i] == comma && comma_check == true) { + final_comma_position = i; + break; + } else if (trimmed[i] == brace && comma_check == true) { + break; + } else if (!isspace(trimmed[i])) { + comma_check = false; + } + } + + if (final_comma_position > -1) { + for (int i = 0; i < trimmed_len; i++) { + if (i != final_comma_position) { + final_trimmed_string += trimmed[i]; + } + } + return final_trimmed_string; + } + + return trimmed; + } + + std::string timestampString(std::string original_string) { + // Turn into "20190201T090000Z" + // int0 "2019-02-01T09:00:00Z" + std::string timestamp_string; + int len = original_string.length(); + + for (int i = 0; i < len; i++) { + timestamp_string += original_string[i]; + + if (i == 3 || i == 5) { + timestamp_string += '-'; + } + if (i == 10 || i == 12) { + timestamp_string += ':'; + } + } + return timestamp_string; + } +}; + +// Headers and non headers + +// Testing all the objects + +// Without headers +// No "List Objects" the object field is empty +// description: "Simple GET" +// description: "Simple PUT" +// description: "Vary expiration and timestamp" +// description: "Vary bucket and object" // No "Trimming of multiple header values" // No "Multi-value headers" @@ -45,49 +158,51 @@ class ObjectIntegrationTest // as per original file // https://github.com/googleapis/google-cloud-dotnet/blob/e918df5a988f53ed71cebf708a0dd06bed8bef43/apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Tests/UrlSignerV4TestData.json#L42 -// Description: "POST for resumable uploads" -// Description: "Simple headers" -// Description: "Headers should be trimmed" - -TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { - // This test uses a disabled key to create a V4 Signed URL for a GET - // operation. The bucket name was generated at random too. +// With headers +// description: "POST for resumable uploads" +// description: "Simple headers" +// description: "Headers should be trimmed" +// With headers key : [ "ignored" ] +// "Customer-supplied encryption key" +TEST_F(ObjectIntegrationTest, V4SignStringAll) { // This is a dummy service account JSON file that is inactive. It's fine for // it to be public. std::string account_file = account_file_name_; std::string data_file = data_file_name_; + auto trimmed_string = trimmedString(data_file); + if (trimmed_string.size() == 0) { + return; + } + + nl::json json_array = nl::json::parse(trimmed_string); auto creds = oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); ASSERT_STATUS_OK(creds); Client client(*creds); - std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return; - } - - nl::json json_array = nl::json::parse(ifstr); - for (auto const& j_obj : json_array) { std::string const method_name = j_obj["method"]; // GET std::string const bucket_name = j_obj["bucket"]; std::string const object_name = j_obj["object"]; - std::string const date = j_obj["timestamp"]; + std::string const date = timestampString(j_obj["timestamp"]); int validInt = j_obj["expiration"]; auto const valid_for = std::chrono::seconds(validInt); std::string const expected = j_obj["expectedUrl"]; - // Check for headers field in each j_obj + std::string header_key; + std::string has_headers = "no"; + + // Check for the 'headers' field in each j_obj for (auto& header : j_obj.items()) { + header_key = header.key(); int array_size_per_key = 0; - if (header.key() == "headers") { + if (header_key == "headers") { + has_headers = "yes"; + // The size of the headers obj, how many keys it has. // 1 one key // 2 two keys or 3 keys @@ -119,10 +234,8 @@ TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { // No Customer-supplied encryption key // see the original file // All the fields in the header that have only one value per key - if (array_size_per_key == 1 && - j_obj["description"] != "Customer-supplied encryption key") { - std::cout << "Description: " - << " " << j_obj["description"] << '\n'; + if (array_size_per_key == 1 && value_vector.at(0) != "ignored") { + std::cout << "Description: " << j_obj["description"] << '\n'; // Check size of keys // key : [ value] @@ -175,73 +288,32 @@ TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { EXPECT_EQ(expected, *actual); } } - } - } - } -} - -// Testing all the objects without the 'headers' key -// No "List Objects" -// description: "Simple GET" -// description: "Simple PUT" -// description: "Vary expiration and timestamp" -// description: "Vary bucket and object" - -TEST_F(ObjectIntegrationTest, V4SignNoHeaders) { - // This test uses a disabled key to create a V4 Signed URL for a GET - // operation. The bucket name was generated at random too. - - // This is a dummy service account JSON file that is inactive. It's fine for - // it to be public. - std::string account_file = account_file_name_; - std::string data_file = data_file_name_; - - auto creds = - oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); - - ASSERT_STATUS_OK(creds); - Client client(*creds); - - std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return; - } - - // nl::json json_array; - nl::json json_array = nl::json::parse(ifstr); - - for (auto const& j_obj : json_array) { - std::string const method_name = j_obj["method"]; // GET - std::string const bucket_name = j_obj["bucket"]; - std::string const object_name = j_obj["object"]; - std::string const date = j_obj["timestamp"]; - int validInt = j_obj["expiration"]; - auto const valid_for = std::chrono::seconds(validInt); - std::string const expected = j_obj["expectedUrl"]; - - std::string header_key; - std::string has_headers = "no"; - // Check for the 'headers' field in each j_obj - for (auto& header : j_obj.items()) { - header_key = header.key(); - // std::cout << header_key << '\n'; - - if (header_key == "headers") { - has_headers = "yes"; + //"Customer-supplied encryption key" + // key : ["ignored"] + if (array_size_per_key == 1 && value_vector.at(0) == "ignored") { + std::cout << "Description: " << j_obj["description"] << '\n'; + auto actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com")); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } } } - // No "List Objects" // description: "Simple GET" // description: "Simple PUT" // description: "Vary expiration and timestamp" // description: "Vary bucket and object" - if (has_headers == "no" && j_obj["description"] != "List Objects") { + // No "List Objects" , object = "" + if (has_headers == "no" && object_name != "") { std::cout << "Description: " << j_obj["description"] << '\n'; auto actual = client.CreateV4SignedUrl( @@ -249,134 +321,14 @@ TEST_F(ObjectIntegrationTest, V4SignNoHeaders) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com")); - ASSERT_STATUS_OK(actual); - - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - } - } -} - -// Customer-supplied encryption key -// works without using headers -// as mentioned in the original file -// https://github.com/googleapis/google-cloud-dotnet/blob/e918df5a988f53ed71cebf708a0dd06bed8bef43/apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Tests/UrlSignerV4TestData.json#L42 -TEST_F(ObjectIntegrationTest, V4SignGetCustomerSupplied) { - // This test uses a disabled key to create a V4 Signed URL for a GET - // operation. The bucket name was generated at random too. - - // This is a dummy service account JSON file that is inactive. It's fine for - // it to be public. - std::string account_file = account_file_name_; - std::string data_file = data_file_name_; - - auto creds = - oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); - - ASSERT_STATUS_OK(creds); - Client client(*creds); - - std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return; - } - - // nl::json json_array; - nl::json json_array = nl::json::parse(ifstr); - - for (auto const& j_obj : json_array) { - std::string method_description = j_obj["description"]; - - if (j_obj["method"] == "GET" && - method_description == "Customer-supplied encryption key") { - std::cout << "Description: " << method_description << '\n'; - std::string const method_name = j_obj["method"]; // GET - std::string const bucket_name = j_obj["bucket"]; - std::string const object_name = j_obj["object"]; - std::string const date = j_obj["timestamp"]; - int validInt = j_obj["expiration"]; - auto const valid_for = std::chrono::seconds(validInt); - - auto actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com")); - ASSERT_STATUS_OK(actual); - - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - - std::string const expected = j_obj["expectedUrl"]; - EXPECT_EQ(expected, *actual); - } - } -} - -/* -//This does not work the object is empty -//description : "List Objects" -TEST_F(ObjectIntegrationTest, V4SignGetListObjects) { - // This test uses a disabled key to create a V4 Signed URL for a GET - // operation. The bucket name was generated at random too. - - // This is a dummy service account JSON file that is inactive. It's fine for - // it to be public. - std::string account_file = account_file_name_; - std::string data_file = data_file_name_; - - auto creds = - oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); - - ASSERT_STATUS_OK(creds); - Client client(*creds); - - std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return; - } - - //nl::json json_array; - nl::json json_array = nl::json::parse(ifstr); - - for (auto const& j_obj : json_array) { - if (j_obj["method"] == "GET" && j_obj["description"] == "List Objects") { - - std::cout << j_obj["description"] << '\n'; - - std::string const method_name = j_obj["method"]; // GET - std::string const bucket_name = j_obj["bucket"]; - std::string const object_name = j_obj["object"]; - std::string const date = j_obj["timestamp"]; - int validInt = j_obj["expiration"]; - auto const valid_for = std::chrono::seconds(validInt); - - - auto actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com") - ); ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); EXPECT_THAT(*actual, HasSubstr(object_name)); - - std::string const expected = j_obj["expectedUrl"]; EXPECT_EQ(expected, *actual); } } } -*/ } // namespace } // namespace STORAGE_CLIENT_NS From cc49627dc7919662b85312411e1be19b96002c46 Mon Sep 17 00:00:00 2001 From: rsimion Date: Thu, 21 Mar 2019 20:22:28 -0400 Subject: [PATCH 07/16] Made changes in the new integration test file --- .../tests/client_sign_url_integration_test.cc | 295 +++++++++--------- 1 file changed, 145 insertions(+), 150 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index c4076317e1eff..00fe21f76d508 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -19,6 +19,7 @@ #include "google/cloud/testing_util/assert_ok.h" #include "google/cloud/testing_util/init_google_mock.h" #include +#include #include #include @@ -50,16 +51,18 @@ class ObjectIntegrationTest std::string from_file((std::istreambuf_iterator(ifstr)), std::istreambuf_iterator()); - int from_file_len = from_file.length(); + // int from_file_len = from_file.length(); + size_t from_file_len = from_file.size(); std::string trimmed; + char const slash = '/'; // Check whether a character is // within //.............\n bool check_comment = false; - for (int i = 0; i < from_file_len; i++) { + for (std::string::size_type i = 0; i < from_file_len; i++) { // Check for // - if (i == 0 && from_file[i] == '/' && from_file[i + 1] == '/') { + if (i == 0 && from_file[i] == slash && from_file[i + 1] == slash) { i++; check_comment = true; } @@ -72,7 +75,7 @@ class ObjectIntegrationTest // Check for // only and not for :// // Do not want to remove https:// - if (from_file[i] == '/' && from_file[i + 1] == '/' && + if (from_file[i] == slash && from_file[i + 1] == slash && from_file[i - 1] != ':') { i++; check_comment = true; @@ -89,13 +92,13 @@ class ObjectIntegrationTest std::string final_trimmed_string; int final_comma_position = -1; - char square_bracket = ']'; - char comma = ','; - char brace = '}'; + char const square_bracket = ']'; + char const comma = ','; + char const brace = '}'; bool comma_check = false; for (int i = trimmed_len - 1; i > 0; i--) { - if (isspace(trimmed[i])) { + if (std::isspace(trimmed[i])) { comma_check = true; } else if (trimmed[i] == square_bracket && comma_check == true) { i--; @@ -104,7 +107,7 @@ class ObjectIntegrationTest break; } else if (trimmed[i] == brace && comma_check == true) { break; - } else if (!isspace(trimmed[i])) { + } else if (!std::isspace(trimmed[i])) { comma_check = false; } } @@ -117,33 +120,52 @@ class ObjectIntegrationTest } return final_trimmed_string; } - return trimmed; } - std::string timestampString(std::string original_string) { - // Turn into "20190201T090000Z" - // int0 "2019-02-01T09:00:00Z" - std::string timestamp_string; - int len = original_string.length(); + std::string TimestampToRfc3339(std::string ts) { + if (ts.size() != 16) { + throw "The timestamp is not in the correct format!"; + } + return ts.substr(0, 4) + '-' + ts.substr(4, 2) + '-' + ts.substr(6, 2) + + 'T' + ts.substr(9, 2) + ':' + ts.substr(11, 2) + ':' + + ts.substr(13, 2) + 'Z'; + } - for (int i = 0; i < len; i++) { - timestamp_string += original_string[i]; + std::vector>> ExtractHeaders( + nl::json j_obj) { + std::vector>> headers; - if (i == 3 || i == 5) { - timestamp_string += '-'; - } - if (i == 10 || i == 12) { - timestamp_string += ':'; + for (auto& header : j_obj.items()) { + std::string header_key = header.key(); + + if (header_key == "headers") { + // The size of the headers obj, how many keys it has. + // 1 one key + // 2 two keys or 3 keys + // Each key has an array of 1 or more strings + + std::string key_name; + + // Check for the keys of the headers field + for (auto const& x : j_obj["headers"].items()) { + // The keys are being outputted in alphabetical order + // not in the order they are in the file + key_name = x.key(); + std::vector value_array; + for (auto const& f : x.value()) { + value_array.emplace_back(f); + } + headers.emplace_back(key_name, value_array); + } } } - return timestamp_string; + return headers; } }; -// Headers and non headers - // Testing all the objects +// Headers and non headers // Without headers // No "List Objects" the object field is empty @@ -165,7 +187,8 @@ class ObjectIntegrationTest // With headers key : [ "ignored" ] // "Customer-supplied encryption key" -TEST_F(ObjectIntegrationTest, V4SignStringAll) { + +TEST_F(ObjectIntegrationTest, V4SignJson) { // This is a dummy service account JSON file that is inactive. It's fine for // it to be public. std::string account_file = account_file_name_; @@ -177,156 +200,128 @@ TEST_F(ObjectIntegrationTest, V4SignStringAll) { } nl::json json_array = nl::json::parse(trimmed_string); + auto creds = oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); ASSERT_STATUS_OK(creds); Client client(*creds); + StatusOr actual; + for (auto const& j_obj : json_array) { - std::string const method_name = j_obj["method"]; // GET + std::string const method_name = j_obj["method"]; std::string const bucket_name = j_obj["bucket"]; std::string const object_name = j_obj["object"]; - std::string const date = timestampString(j_obj["timestamp"]); + std::string const date = TimestampToRfc3339(j_obj["timestamp"]); + int validInt = j_obj["expiration"]; auto const valid_for = std::chrono::seconds(validInt); std::string const expected = j_obj["expectedUrl"]; - std::string header_key; - std::string has_headers = "no"; + // ExtractHeaders for each object + // ExtractHeaders(j_obj) for each object - // Check for the 'headers' field in each j_obj - for (auto& header : j_obj.items()) { - header_key = header.key(); - int array_size_per_key = 0; + std::vector>> headers = + ExtractHeaders(j_obj); - if (header_key == "headers") { - has_headers = "yes"; - - // The size of the headers obj, how many keys it has. - // 1 one key - // 2 two keys or 3 keys - // Each key has an array of 1 or more strings - - std::string key_name; - std::string header_name; - - std::vector key_vector; - std::vector value_vector; - - // Check for the keys of the headers field - for (auto& x : j_obj["headers"].items()) { - // Each key - key_name = x.key(); - key_vector.emplace_back(key_name); - - // Each key has an array as value - array_size_per_key = x.value().size(); - - // Only one value per key : key : [value] - header_name = x.value()[0]; - value_vector.emplace_back(header_name); - } - - // Only headers with key : [ value ] - // not key : [ value1, value2 ] - - // No Customer-supplied encryption key - // see the original file - // All the fields in the header that have only one value per key - if (array_size_per_key == 1 && value_vector.at(0) != "ignored") { - std::cout << "Description: " << j_obj["description"] << '\n'; - - // Check size of keys - // key : [ value] - if (key_vector.size() == 1) { - auto actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_vector.at(0), value_vector.at(0))); - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - - } - - // 2 key : [value] pairs - else if (key_vector.size() == 2) { - auto actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_vector.at(0), value_vector.at(0)), - AddExtensionHeader(key_vector.at(1), value_vector.at(1))); - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - - } - - // 3 key : [value ] pairs - else if (key_vector.size() == 3) { - auto actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_vector.at(0), value_vector.at(0)), - AddExtensionHeader(key_vector.at(1), value_vector.at(1)), - AddExtensionHeader(key_vector.at(2), value_vector.at(2))); - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - } - } + if (headers.size() == 0) { + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com")); + if (object_name != "") { + std::cout << "No Headers " + << "Description: " << j_obj["description"] << '\n'; + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } + } - //"Customer-supplied encryption key" - // key : ["ignored"] - if (array_size_per_key == 1 && value_vector.at(0) == "ignored") { - std::cout << "Description: " << j_obj["description"] << '\n'; - auto actual = client.CreateV4SignedUrl( + else if (headers.size() > 0 && headers.front().second.size() == 1) { + if (headers.size() == 1) { + std::cout << "Headers 1 " + << "Description: " << j_obj["description"] << '\n'; + if (headers.front().second.at(0) != "ignored") { + actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com")); - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(0).first, + headers.at(0).second.at(0))); } + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); } - } - // description: "Simple GET" - // description: "Simple PUT" - // description: "Vary expiration and timestamp" - // description: "Vary bucket and object" + else if (headers.size() == 2) { + std::cout << "Headers 2 " + << "Description: " << j_obj["description"] << '\n'; + + // For some reason the function outputs them as a map + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(1).first, headers.at(1).second.at(0)), + AddExtensionHeader(headers.at(0).first, + headers.at(0).second.at(0))); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); - // No "List Objects" , object = "" - if (has_headers == "no" && object_name != "") { - std::cout << "Description: " << j_obj["description"] << '\n'; + } - auto actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com")); + else if (headers.size() == 3 && + headers.front().second.at(0) != "ignored") { + std::cout << "Headers 2 " + << "Description: " << j_obj["description"] << '\n'; + + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(1).first, headers.at(1).second.at(0)), + AddExtensionHeader(headers.at(2).first, headers.at(2).second.at(0)), + AddExtensionHeader(headers.at(0).first, + headers.at(0).second.at(0))); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); + else if (headers.size() == 3 && + headers.front().second.at(0) == "ignored") { + std::cout << "Headers 2 " + << "Description: " << j_obj["description"] << '\n'; + + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com")); + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } } + + EXPECT_LT(headers.size(), 4); } } From d9597aca68ee386c6ea46c273791ca39947f933d Mon Sep 17 00:00:00 2001 From: rsimion Date: Thu, 21 Mar 2019 21:16:19 -0400 Subject: [PATCH 08/16] Removed throw --- google/cloud/storage/tests/client_sign_url_integration_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 00fe21f76d508..1e3ca6ba670b3 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -125,7 +125,7 @@ class ObjectIntegrationTest std::string TimestampToRfc3339(std::string ts) { if (ts.size() != 16) { - throw "The timestamp is not in the correct format!"; + return ""; } return ts.substr(0, 4) + '-' + ts.substr(4, 2) + '-' + ts.substr(6, 2) + 'T' + ts.substr(9, 2) + ':' + ts.substr(11, 2) + ':' + From e725f4969c9428006ab311c32bb314369dd146aa Mon Sep 17 00:00:00 2001 From: rsimion Date: Thu, 21 Mar 2019 21:58:25 -0400 Subject: [PATCH 09/16] Minor changes --- .../storage/tests/client_sign_url_integration_test.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 1e3ca6ba670b3..cb774f4bc6302 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -148,13 +148,14 @@ class ObjectIntegrationTest std::string key_name; // Check for the keys of the headers field - for (auto const& x : j_obj["headers"].items()) { + for (auto& x : j_obj["headers"].items()) { // The keys are being outputted in alphabetical order // not in the order they are in the file key_name = x.key(); std::vector value_array; - for (auto const& f : x.value()) { - value_array.emplace_back(f); + for (auto& value : x.value()) { + std::string value_name = value; + value_array.emplace_back(value_name); } headers.emplace_back(key_name, value_array); } From 35c10c8a5dbd67277884238813bbdc927ebecd5a Mon Sep 17 00:00:00 2001 From: rsimion Date: Mon, 25 Mar 2019 15:15:06 -0400 Subject: [PATCH 10/16] Updated the json file and the integration test file --- .../storage/tests/UrlSignerV4TestData.json | 11 +- .../tests/client_sign_url_integration_test.cc | 255 +++++++++++------- 2 files changed, 157 insertions(+), 109 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index 96f35a4c5bbf0..42c95d7cf4f13 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -121,14 +121,14 @@ "object": "test-object", "headers": { - "X-Goog-Encryption-Key": [ "ignored" ], - "X-Goog-Encryption-Key-Sha256": [ "ignored" ], - "X-Goog-Encryption-Algorithm": [ "ignored" ] + "X-Goog-Encryption-Key": [ "key" ], + "X-Goog-Encryption-Key-Sha256": [ "key-hash" ], + "X-Goog-Encryption-Algorithm": [ "AES256" ] }, "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" + "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-encryption-algorithm%3Bx-goog-encryption-key%3Bx-goog-encryption-key-sha256&X-Goog-Signature=278a1c5a3bad248637054a047014760353942433955871031ed08f515b54588654ad033e91f046ab202b68673030e117d1b786c325e870238b035ba75b3feed560a17aff9bab6bddebd4a31a52cb68b214e27d3b0bd886502c6b36b164306fe88b5a07c6063592afe746b2a5d205dbe90dd5386b94f0a78f75d9f53ee884e18f476e8fc2eb1dd910ce0b4ae1f5d7b09876ef9bf983f539c028429e14bad3c75dbd4ed1ae37856f6d6f8a1805eaf8b52a0d6fc993902e4c1ee8de477661f7b67c3663000474cb00e178189789b2a3ed6bd21b4ade684fca8108ac4dd106acb17f5954d045775f7aa5a98ebda5d3075e11a8ea49c64c6ad1481e463e8c9f11f704" }, { @@ -139,6 +139,5 @@ "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" - }, - + } ] diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index cb774f4bc6302..a9a2f4412714b 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -85,44 +85,13 @@ class ObjectIntegrationTest trimmed += from_file[i]; } } - - // Remove the last comma from the string - // }, ] if any - int trimmed_len = trimmed.length(); - std::string final_trimmed_string; - - int final_comma_position = -1; - char const square_bracket = ']'; - char const comma = ','; - char const brace = '}'; - bool comma_check = false; - - for (int i = trimmed_len - 1; i > 0; i--) { - if (std::isspace(trimmed[i])) { - comma_check = true; - } else if (trimmed[i] == square_bracket && comma_check == true) { - i--; - } else if (trimmed[i] == comma && comma_check == true) { - final_comma_position = i; - break; - } else if (trimmed[i] == brace && comma_check == true) { - break; - } else if (!std::isspace(trimmed[i])) { - comma_check = false; - } - } - - if (final_comma_position > -1) { - for (int i = 0; i < trimmed_len; i++) { - if (i != final_comma_position) { - final_trimmed_string += trimmed[i]; - } - } - return final_trimmed_string; - } return trimmed; } + // Converts + // ""20190201T090000Z", + // to the following format + // "2019-02-01T09:00:00Z" std::string TimestampToRfc3339(std::string ts) { if (ts.size() != 16) { return ""; @@ -151,6 +120,19 @@ class ObjectIntegrationTest for (auto& x : j_obj["headers"].items()) { // The keys are being outputted in alphabetical order // not in the order they are in the file + + // Inside the file + // "headers": { + // "foo": [ "foo-value" ], + // "BAR": [ "BAR-value" ] + // }, + + // Output by nlohman library + // "headers": { + // "BAR": [ "BAR-value" ], + // "foo": [ "foo-value" ] + // }, + key_name = x.key(); std::vector value_array; for (auto& value : x.value()) { @@ -165,29 +147,8 @@ class ObjectIntegrationTest } }; -// Testing all the objects -// Headers and non headers - -// Without headers -// No "List Objects" the object field is empty -// description: "Simple GET" -// description: "Simple PUT" -// description: "Vary expiration and timestamp" -// description: "Vary bucket and object" - -// No "Trimming of multiple header values" -// No "Multi-value headers" - -// as per original file -// https://github.com/googleapis/google-cloud-dotnet/blob/e918df5a988f53ed71cebf708a0dd06bed8bef43/apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Tests/UrlSignerV4TestData.json#L42 - -// With headers -// description: "POST for resumable uploads" -// description: "Simple headers" -// description: "Headers should be trimmed" - -// With headers key : [ "ignored" ] -// "Customer-supplied encryption key" +// Testing all the objects in the json file +// Objects with headers and without headers TEST_F(ObjectIntegrationTest, V4SignJson) { // This is a dummy service account JSON file that is inactive. It's fine for @@ -199,15 +160,12 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { if (trimmed_string.size() == 0) { return; } - nl::json json_array = nl::json::parse(trimmed_string); - auto creds = oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); ASSERT_STATUS_OK(creds); Client client(*creds); - StatusOr actual; for (auto const& j_obj : json_array) { @@ -220,9 +178,7 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { auto const valid_for = std::chrono::seconds(validInt); std::string const expected = j_obj["expectedUrl"]; - // ExtractHeaders for each object - // ExtractHeaders(j_obj) for each object - + // Extract headers for each object std::vector>> headers = ExtractHeaders(j_obj); @@ -242,6 +198,10 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { } } + // headers.front().second.size() == 1 means + // key : [value] + // not + // key : [value1, value2, .. ] else if (headers.size() > 0 && headers.front().second.size() == 1) { if (headers.size() == 1) { std::cout << "Headers 1 " @@ -255,14 +215,7 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { AddExtensionHeader(headers.at(0).first, headers.at(0).second.at(0))); } - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - } - - else if (headers.size() == 2) { + } else if (headers.size() == 2) { std::cout << "Headers 2 " << "Description: " << j_obj["description"] << '\n'; @@ -275,17 +228,8 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { AddExtensionHeader(headers.at(1).first, headers.at(1).second.at(0)), AddExtensionHeader(headers.at(0).first, headers.at(0).second.at(0))); - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - - } - - else if (headers.size() == 3 && - headers.front().second.at(0) != "ignored") { - std::cout << "Headers 2 " + } else if (headers.size() == 3) { + std::cout << "Headers 3 " << "Description: " << j_obj["description"] << '\n'; actual = client.CreateV4SignedUrl( @@ -297,32 +241,137 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { AddExtensionHeader(headers.at(2).first, headers.at(2).second.at(0)), AddExtensionHeader(headers.at(0).first, headers.at(0).second.at(0))); - - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); } + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } + EXPECT_LT(headers.size(), 4); + } +} - else if (headers.size() == 3 && - headers.front().second.at(0) == "ignored") { - std::cout << "Headers 2 " - << "Description: " << j_obj["description"] << '\n'; +TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { + // This test uses a disabled key to create a V4 Signed URL for a GET + // operation. The bucket name was generated at random too. - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com")); + // This is a dummy service account JSON file that is inactive. It's fine for + // it to be public. + std::string account_file = account_file_name_; + std::string data_file = data_file_name_; - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); + auto creds = + oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); + + ASSERT_STATUS_OK(creds); + Client client(*creds); + StatusOr actual; + + auto trimmed_string = trimmedString(data_file); + if (trimmed_string.size() == 0) { + return; + } + + nl::json json_array = nl::json::parse(trimmed_string); + + for (auto const& j_obj : json_array) { + std::string const method_name = j_obj["method"]; + std::string const bucket_name = j_obj["bucket"]; + std::string const object_name = j_obj["object"]; + std::string const date = TimestampToRfc3339(j_obj["timestamp"]); + int validInt = j_obj["expiration"]; + auto const valid_for = std::chrono::seconds(validInt); + std::string const expected = j_obj["expectedUrl"]; + + // Check for headers field in each j_obj + for (auto& header : j_obj.items()) { + int array_size_per_key = 0; + + if (header.key() == "headers") { + // The size of the headers obj, how many keys it has. + // 1 one key + // 2 two keys or 3 keys + // Each key has an array of 1 or more strings + + std::string key_name; + std::string header_name; + + std::vector key_vector; + std::vector value_vector; + + // Check for the keys of the headers field + for (auto& x : j_obj["headers"].items()) { + // Each key + key_name = x.key(); + key_vector.emplace_back(key_name); + + // Each key has an array as value + array_size_per_key = x.value().size(); + + // Only one value per key : key : [value] + header_name = x.value()[0]; + value_vector.emplace_back(header_name); + } + + // Only headers with key : [ value ] + // not key : [ value1, value2 ] + + // All the fields in the header that have only one value per key + if (array_size_per_key == 1) { + // std::cout << "Description: " + // << " " << j_obj["description"] << '\n'; + + // Check size of keys + // key : [ value] + if (key_vector.size() == 1) { + std::cout << "Headers 1 " + << "Description: " << j_obj["description"] << '\n'; + + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_vector.at(0), value_vector.at(0))); + } + + // 2 key : [value] pairs + else if (key_vector.size() == 2) { + std::cout << "Headers 2 " + << "Description: " << j_obj["description"] << '\n'; + + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_vector.at(0), value_vector.at(0)), + AddExtensionHeader(key_vector.at(1), value_vector.at(1))); + + } + + // 3 key : [value ] pairs + else if (key_vector.size() == 3) { + std::cout << "Headers 3 " + << "Description: " << j_obj["description"] << '\n'; + + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(key_vector.at(0), value_vector.at(0)), + AddExtensionHeader(key_vector.at(1), value_vector.at(1)), + AddExtensionHeader(key_vector.at(2), value_vector.at(2))); + } + + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); + } } } - - EXPECT_LT(headers.size(), 4); } } From 3b1923ae66cfe225d032ceba8c5777ccb89fb5d9 Mon Sep 17 00:00:00 2001 From: rsimion Date: Wed, 27 Mar 2019 10:15:53 -0400 Subject: [PATCH 11/16] New changes in both, json and integration test files --- .../storage/tests/UrlSignerV4TestData.json | 49 ++--- .../tests/client_sign_url_integration_test.cc | 198 +++++------------- 2 files changed, 66 insertions(+), 181 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index 42c95d7cf4f13..fdbc42d134e2d 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -1,6 +1,3 @@ -// Assumed constant for all tests: -// - email: test-iam-credentials@dummy-project-id.iam.gserviceaccount.com -// - project: dummy-project-id [ { "description": "Simple GET", @@ -21,7 +18,7 @@ "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", @@ -29,7 +26,7 @@ "method": "POST", "expiration": 10, "headers": { - "x-goog-resumable": [ "start" ] + "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" @@ -60,8 +57,8 @@ "bucket": "test-bucket", "object": "test-object", "headers": { - "foo": [ "foo-value" ], - "BAR": [ "BAR-value" ] + "foo": "foo-value", + "BAR": "BAR-value" }, "method": "GET", "expiration": 10, @@ -69,30 +66,14 @@ "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" }, - // Note: some platforms may not expose multi-value headers to clients. They could skip - // this test or perform the concatenation of header values themselves. - { - "description": "Multi-value headers", - "bucket": "test-bucket", - "object": "test-object", - "headers": { - "foo": [ "foo-value1", "foo-value2" ], - "bar": [ "bar-value1", "bar-value2" ] - }, - "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=84a14ff388457290bc3ed7bfeb4745a1c2287e58965457d9d9959326fc2cbdfbb9128b6a002e86d617cb1d2187e3e075de223489d4e91418de76e21d4e561c618bc13ac72e1cc3b4e0c9eee880be577c417eb4623347d3d1ffd2a0705ab70bab6786f67107d05dc4652f2b84531dc01a15efa9ee3fbe504f6e76e64658fd1df431bf671a997db8ef7371eae8abbcc2690c085407738e32f396d9b87d0e974740ee0b7a256fc8471db27a6b554527b96dbd972073b89f57d6486182816b0d307875f1753bf16140332c6116899447769dd9f1985a520ca6ab50c614a80b3619e9d9a81ff81a6c14f51f1cf487243c2708aa9064e30acb5694af04c3fe0f5fd5a4" - }, - { "description": "Headers should be trimmed", "bucket": "test-bucket", "object": "test-object", "headers": { - "leading": [ " xyz" ], - "trailing": [ "abc " ], - "collapsed": [ "abc def" ] + "leading": " xyz", + "trailing": "abc ", + "collapsed": "abc def" }, "method": "GET", "expiration": 10, @@ -100,37 +81,35 @@ "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" }, - // Separated from "Headers should be trimmed" test so it can be skipped on single-header-value-only platforms. { - "description": "Trimming of multiple header values", + "description": "Header value with multiple inline values", "bucket": "test-bucket", "object": "test-object", "headers": { - "foo": [ " abc ", " def ", " ghi jkl " ] + "multiple": " xyz , abc, def , xyz " }, "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=foo%3Bhost&X-Goog-Signature=96e36a82dd79e6d37070b5dfaffc616e8c5159c583261dd3858c2241c2a34f270f4fe2bf55ba6877a7c982f34b0b9114683ba37880e3ec378942972882dbcb99c6463573178c6167acc40b2be8db7f3a320de47373c30626a37fe9e6cc719ee6060f573bf1a30ef5e86338e834494c089226bef3722bf8ae2fa3a7599916bec92df30cf25852c3514e3be0f4541063cea2babf4825b8e38876454f1502f5e307d32381aa927113104a75c82a23f7e9597016ca0bc4971d5990515df2a0239a62c711d3aacea50b8e05106ae2a14201bd6dae369334c27fad5c14dac66103c5c1a980b3de263e85fe715010e603a518eaf6286b7beb24ca84b97752485c423f0a" + "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%3Bmultiple&X-Goog-Signature=5cc113735625341f59c7203f0c2c9febc95ba6af6b9c38814f8e523214712087dc0996e4960d273ae1889f248ac1e58d4d19cb3a69ad7670e9a8ca1b434e878f59339dc7006cf32dfd715337e9f593e0504371839174962a08294586e0c78160a7aa303397888c8350637c6af3b32ac310886cc4590bfda9ca561ee58fb5b8ec56bc606d2ada6e7df31f4276e9dcb96bcaea39dc2cd096f3fad774f9c4b30e317ad43736c05f76831437f44e8726c1e90d3f6c9827dc273f211f32fc85658dfc5d357eb606743a6b00a29e519eef1bebaf9db3e8f4b1f5f9afb648ad06e60bc42fa8b57025056697c874c9ea76f5a73201c9717ea43e54713ff3502ff3fc626b" }, - // 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": [ "key" ], - "X-Goog-Encryption-Key-Sha256": [ "key-hash" ], - "X-Goog-Encryption-Algorithm": [ "AES256" ] + "X-Goog-Encryption-Key": "key", + "X-Goog-Encryption-Key-Sha256": "key-hash", + "X-Goog-Encryption-Algorithm": "AES256" }, "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%3Bx-goog-encryption-algorithm%3Bx-goog-encryption-key%3Bx-goog-encryption-key-sha256&X-Goog-Signature=278a1c5a3bad248637054a047014760353942433955871031ed08f515b54588654ad033e91f046ab202b68673030e117d1b786c325e870238b035ba75b3feed560a17aff9bab6bddebd4a31a52cb68b214e27d3b0bd886502c6b36b164306fe88b5a07c6063592afe746b2a5d205dbe90dd5386b94f0a78f75d9f53ee884e18f476e8fc2eb1dd910ce0b4ae1f5d7b09876ef9bf983f539c028429e14bad3c75dbd4ed1ae37856f6d6f8a1805eaf8b52a0d6fc993902e4c1ee8de477661f7b67c3663000474cb00e178189789b2a3ed6bd21b4ade684fca8108ac4dd106acb17f5954d045775f7aa5a98ebda5d3075e11a8ea49c64c6ad1481e463e8c9f11f704" }, - + { "description": "List Objects", "bucket": "test-bucket", diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index a9a2f4412714b..4d9b468eb6465 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -39,59 +39,8 @@ char const* data_file_name_; class ObjectIntegrationTest : public google::cloud::storage::testing::StorageIntegrationTest { protected: - std::string trimmedString(std::string data_file) { - std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return ""; - } - - std::string from_file((std::istreambuf_iterator(ifstr)), - std::istreambuf_iterator()); - - // int from_file_len = from_file.length(); - size_t from_file_len = from_file.size(); - std::string trimmed; - char const slash = '/'; - - // Check whether a character is - // within //.............\n - bool check_comment = false; - - for (std::string::size_type i = 0; i < from_file_len; i++) { - // Check for // - if (i == 0 && from_file[i] == slash && from_file[i + 1] == slash) { - i++; - check_comment = true; - } - - // Check for the end of the commented line \n - else if (check_comment == true && from_file[i] == '\n') { - i++; - check_comment = false; - } - - // Check for // only and not for :// - // Do not want to remove https:// - if (from_file[i] == slash && from_file[i + 1] == slash && - from_file[i - 1] != ':') { - i++; - check_comment = true; - } - - else if (check_comment == false) { - trimmed += from_file[i]; - } - } - return trimmed; - } - - // Converts - // ""20190201T090000Z", - // to the following format - // "2019-02-01T09:00:00Z" + // Converts ""20190201T090000Z", + // to "2019-02-01T09:00:00Z" std::string TimestampToRfc3339(std::string ts) { if (ts.size() != 16) { return ""; @@ -101,21 +50,16 @@ class ObjectIntegrationTest ts.substr(13, 2) + 'Z'; } - std::vector>> ExtractHeaders( + std::vector> ExtractHeaders( nl::json j_obj) { - std::vector>> headers; + std::vector> headers; for (auto& header : j_obj.items()) { std::string header_key = header.key(); if (header_key == "headers") { - // The size of the headers obj, how many keys it has. - // 1 one key - // 2 two keys or 3 keys - // Each key has an array of 1 or more strings - std::string key_name; - + std::string value_name; // Check for the keys of the headers field for (auto& x : j_obj["headers"].items()) { // The keys are being outputted in alphabetical order @@ -123,23 +67,19 @@ class ObjectIntegrationTest // Inside the file // "headers": { - // "foo": [ "foo-value" ], - // "BAR": [ "BAR-value" ] + // "foo": "foo-value" , + // "BAR": "BAR-value" // }, // Output by nlohman library // "headers": { - // "BAR": [ "BAR-value" ], - // "foo": [ "foo-value" ] + // "BAR": "BAR-value" , + // "foo": "foo-value" // }, key_name = x.key(); - std::vector value_array; - for (auto& value : x.value()) { - std::string value_name = value; - value_array.emplace_back(value_name); - } - headers.emplace_back(key_name, value_array); + value_name = x.value(); + headers.emplace_back(key_name, value_name); } } } @@ -147,20 +87,21 @@ class ObjectIntegrationTest } }; -// Testing all the objects in the json file -// Objects with headers and without headers - TEST_F(ObjectIntegrationTest, V4SignJson) { // This is a dummy service account JSON file that is inactive. It's fine for // it to be public. std::string account_file = account_file_name_; std::string data_file = data_file_name_; - auto trimmed_string = trimmedString(data_file); - if (trimmed_string.size() == 0) { + std::ifstream ifstr(data_file); + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + data_file + '\n'; return; } - nl::json json_array = nl::json::parse(trimmed_string); + // nl::json json_array; + nl::json json_array = nl::json::parse(ifstr); auto creds = oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); @@ -179,7 +120,7 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { std::string const expected = j_obj["expectedUrl"]; // Extract headers for each object - std::vector>> headers = + std::vector> headers = ExtractHeaders(j_obj); if (headers.size() == 0) { @@ -196,24 +137,17 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { EXPECT_THAT(*actual, HasSubstr(object_name)); EXPECT_EQ(expected, *actual); } - } - - // headers.front().second.size() == 1 means - // key : [value] - // not - // key : [value1, value2, .. ] - else if (headers.size() > 0 && headers.front().second.size() == 1) { + } else if (headers.size() > 0) { if (headers.size() == 1) { std::cout << "Headers 1 " << "Description: " << j_obj["description"] << '\n'; - if (headers.front().second.at(0) != "ignored") { + if (headers.front().second != "ignored") { actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, - headers.at(0).second.at(0))); + AddExtensionHeader(headers.at(0).first, headers.at(0).second)); } } else if (headers.size() == 2) { std::cout << "Headers 2 " @@ -225,9 +159,8 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(1).first, headers.at(1).second.at(0)), - AddExtensionHeader(headers.at(0).first, - headers.at(0).second.at(0))); + AddExtensionHeader(headers.at(1).first, headers.at(1).second), + AddExtensionHeader(headers.at(0).first, headers.at(0).second)); } else if (headers.size() == 3) { std::cout << "Headers 3 " << "Description: " << j_obj["description"] << '\n'; @@ -237,10 +170,9 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(1).first, headers.at(1).second.at(0)), - AddExtensionHeader(headers.at(2).first, headers.at(2).second.at(0)), - AddExtensionHeader(headers.at(0).first, - headers.at(0).second.at(0))); + AddExtensionHeader(headers.at(1).first, headers.at(1).second), + AddExtensionHeader(headers.at(2).first, headers.at(2).second), + AddExtensionHeader(headers.at(0).first, headers.at(0).second)); } ASSERT_STATUS_OK(actual); EXPECT_THAT(*actual, HasSubstr(bucket_name)); @@ -251,7 +183,7 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { } } -TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { +TEST_F(ObjectIntegrationTest, V4SignJsonHeaders) { // This test uses a disabled key to create a V4 Signed URL for a GET // operation. The bucket name was generated at random too. @@ -267,12 +199,15 @@ TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { Client client(*creds); StatusOr actual; - auto trimmed_string = trimmedString(data_file); - if (trimmed_string.size() == 0) { + std::ifstream ifstr(data_file); + if (!ifstr.is_open()) { + // If the file does not exist, or + // if we were unable to open it for some other reason. + std::cout << "Cannot open credentials file " + data_file + '\n'; return; } - - nl::json json_array = nl::json::parse(trimmed_string); + // nl::json json_array; + nl::json json_array = nl::json::parse(ifstr); for (auto const& j_obj : json_array) { std::string const method_name = j_obj["method"]; @@ -285,90 +220,61 @@ TEST_F(ObjectIntegrationTest, V4SignWithHeaders) { // Check for headers field in each j_obj for (auto& header : j_obj.items()) { - int array_size_per_key = 0; - if (header.key() == "headers") { - // The size of the headers obj, how many keys it has. - // 1 one key - // 2 two keys or 3 keys - // Each key has an array of 1 or more strings - std::string key_name; std::string header_name; + std::vector> headers; - std::vector key_vector; - std::vector value_vector; - - // Check for the keys of the headers field for (auto& x : j_obj["headers"].items()) { // Each key key_name = x.key(); - key_vector.emplace_back(key_name); - - // Each key has an array as value - array_size_per_key = x.value().size(); - - // Only one value per key : key : [value] - header_name = x.value()[0]; - value_vector.emplace_back(header_name); + header_name = x.value(); + headers.emplace_back(key_name, header_name); } - // Only headers with key : [ value ] - // not key : [ value1, value2 ] - - // All the fields in the header that have only one value per key - if (array_size_per_key == 1) { - // std::cout << "Description: " - // << " " << j_obj["description"] << '\n'; - - // Check size of keys - // key : [ value] - if (key_vector.size() == 1) { + if (headers.size() > 0) { + // 1 key:value pair + if (headers.size() == 1) { std::cout << "Headers 1 " << "Description: " << j_obj["description"] << '\n'; - actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_vector.at(0), value_vector.at(0))); + AddExtensionHeader(headers.at(0).first, headers.at(0).second)); } - - // 2 key : [value] pairs - else if (key_vector.size() == 2) { + // 2 key:value pairs + else if (headers.size() == 2) { std::cout << "Headers 2 " << "Description: " << j_obj["description"] << '\n'; - actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_vector.at(0), value_vector.at(0)), - AddExtensionHeader(key_vector.at(1), value_vector.at(1))); - + AddExtensionHeader(headers.at(0).first, headers.at(0).second), + AddExtensionHeader(headers.at(1).first, headers.at(1).second)); } - // 3 key : [value ] pairs - else if (key_vector.size() == 3) { + // 3 key:value pairs + else if (headers.size() == 3) { std::cout << "Headers 3 " << "Description: " << j_obj["description"] << '\n'; - actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(key_vector.at(0), value_vector.at(0)), - AddExtensionHeader(key_vector.at(1), value_vector.at(1)), - AddExtensionHeader(key_vector.at(2), value_vector.at(2))); + AddExtensionHeader(headers.at(0).first, headers.at(0).second), + AddExtensionHeader(headers.at(1).first, headers.at(1).second), + AddExtensionHeader(headers.at(2).first, headers.at(2).second)); } - ASSERT_STATUS_OK(actual); EXPECT_THAT(*actual, HasSubstr(bucket_name)); EXPECT_THAT(*actual, HasSubstr(object_name)); EXPECT_EQ(expected, *actual); + EXPECT_LT(headers.size(), 4); } } } From ce7edd14e63f56d1b8bf2ce2968df76214f5fc78 Mon Sep 17 00:00:00 2001 From: rsimion Date: Wed, 27 Mar 2019 11:24:37 -0400 Subject: [PATCH 12/16] Fixing my mistake in the integration test file --- .../tests/client_sign_url_integration_test.cc | 107 +----------------- 1 file changed, 4 insertions(+), 103 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 4d9b468eb6465..c3dbfc85a5642 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -159,8 +159,8 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(1).first, headers.at(1).second), - AddExtensionHeader(headers.at(0).first, headers.at(0).second)); + AddExtensionHeader(headers.at(0).first, headers.at(0).second), + AddExtensionHeader(headers.at(1).first, headers.at(1).second)); } else if (headers.size() == 3) { std::cout << "Headers 3 " << "Description: " << j_obj["description"] << '\n'; @@ -170,9 +170,9 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(0).first, headers.at(0).second), AddExtensionHeader(headers.at(1).first, headers.at(1).second), - AddExtensionHeader(headers.at(2).first, headers.at(2).second), - AddExtensionHeader(headers.at(0).first, headers.at(0).second)); + AddExtensionHeader(headers.at(2).first, headers.at(2).second)); } ASSERT_STATUS_OK(actual); EXPECT_THAT(*actual, HasSubstr(bucket_name)); @@ -182,105 +182,6 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { EXPECT_LT(headers.size(), 4); } } - -TEST_F(ObjectIntegrationTest, V4SignJsonHeaders) { - // This test uses a disabled key to create a V4 Signed URL for a GET - // operation. The bucket name was generated at random too. - - // This is a dummy service account JSON file that is inactive. It's fine for - // it to be public. - std::string account_file = account_file_name_; - std::string data_file = data_file_name_; - - auto creds = - oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); - - ASSERT_STATUS_OK(creds); - Client client(*creds); - StatusOr actual; - - std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return; - } - // nl::json json_array; - nl::json json_array = nl::json::parse(ifstr); - - for (auto const& j_obj : json_array) { - std::string const method_name = j_obj["method"]; - std::string const bucket_name = j_obj["bucket"]; - std::string const object_name = j_obj["object"]; - std::string const date = TimestampToRfc3339(j_obj["timestamp"]); - int validInt = j_obj["expiration"]; - auto const valid_for = std::chrono::seconds(validInt); - std::string const expected = j_obj["expectedUrl"]; - - // Check for headers field in each j_obj - for (auto& header : j_obj.items()) { - if (header.key() == "headers") { - std::string key_name; - std::string header_name; - std::vector> headers; - - for (auto& x : j_obj["headers"].items()) { - // Each key - key_name = x.key(); - header_name = x.value(); - headers.emplace_back(key_name, header_name); - } - - if (headers.size() > 0) { - // 1 key:value pair - if (headers.size() == 1) { - std::cout << "Headers 1 " - << "Description: " << j_obj["description"] << '\n'; - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second)); - } - // 2 key:value pairs - else if (headers.size() == 2) { - std::cout << "Headers 2 " - << "Description: " << j_obj["description"] << '\n'; - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second), - AddExtensionHeader(headers.at(1).first, headers.at(1).second)); - } - - // 3 key:value pairs - else if (headers.size() == 3) { - std::cout << "Headers 3 " - << "Description: " << j_obj["description"] << '\n'; - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second), - AddExtensionHeader(headers.at(1).first, headers.at(1).second), - AddExtensionHeader(headers.at(2).first, headers.at(2).second)); - } - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - EXPECT_LT(headers.size(), 4); - } - } - } - } -} - } // namespace } // namespace STORAGE_CLIENT_NS } // namespace storage From 51b7581ebd3b6475096214ceb93f417653523df7 Mon Sep 17 00:00:00 2001 From: rsimion Date: Wed, 27 Mar 2019 12:15:48 -0400 Subject: [PATCH 13/16] Cleaning up the clutter --- .../tests/client_sign_url_integration_test.cc | 111 ++++++------------ 1 file changed, 39 insertions(+), 72 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index c3dbfc85a5642..c4137f0e251b7 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -19,12 +19,9 @@ #include "google/cloud/testing_util/assert_ok.h" #include "google/cloud/testing_util/init_google_mock.h" #include -#include #include -#include namespace nl = google::cloud::storage::internal::nl; - namespace google { namespace cloud { namespace storage { @@ -62,21 +59,9 @@ class ObjectIntegrationTest std::string value_name; // Check for the keys of the headers field for (auto& x : j_obj["headers"].items()) { - // The keys are being outputted in alphabetical order - // not in the order they are in the file - - // Inside the file - // "headers": { - // "foo": "foo-value" , - // "BAR": "BAR-value" - // }, - - // Output by nlohman library - // "headers": { - // "BAR": "BAR-value" , - // "foo": "foo-value" - // }, - + // The keys are returned in alphabetical order by nlohmann::json, but + // the order does not matter when creating signed urls. in + // alphabetical order key_name = x.key(); value_name = x.value(); headers.emplace_back(key_name, value_name); @@ -94,13 +79,8 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { std::string data_file = data_file_name_; std::ifstream ifstr(data_file); - if (!ifstr.is_open()) { - // If the file does not exist, or - // if we were unable to open it for some other reason. - std::cout << "Cannot open credentials file " + data_file + '\n'; - return; - } - // nl::json json_array; + ASSERT_TRUE(ifstr.is_open()); + nl::json json_array = nl::json::parse(ifstr); auto creds = oauth2::CreateServiceAccountCredentialsFromJsonFilePath(account_file); @@ -114,12 +94,10 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { std::string const bucket_name = j_obj["bucket"]; std::string const object_name = j_obj["object"]; std::string const date = TimestampToRfc3339(j_obj["timestamp"]); - - int validInt = j_obj["expiration"]; - auto const valid_for = std::chrono::seconds(validInt); + auto const valid_for = std::chrono::seconds(j_obj["expiration"]); std::string const expected = j_obj["expectedUrl"]; - // Extract headers for each object + // Extract the headers for each object std::vector> headers = ExtractHeaders(j_obj); @@ -129,59 +107,48 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com")); - if (object_name != "") { - std::cout << "No Headers " - << "Description: " << j_obj["description"] << '\n'; - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); - } - } else if (headers.size() > 0) { - if (headers.size() == 1) { - std::cout << "Headers 1 " - << "Description: " << j_obj["description"] << '\n'; - if (headers.front().second != "ignored") { - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second)); - } - } else if (headers.size() == 2) { - std::cout << "Headers 2 " - << "Description: " << j_obj["description"] << '\n'; - - // For some reason the function outputs them as a map - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second), - AddExtensionHeader(headers.at(1).first, headers.at(1).second)); - } else if (headers.size() == 3) { - std::cout << "Headers 3 " - << "Description: " << j_obj["description"] << '\n'; + // TODO(#2350) + if (object_name == "") { + continue; + } + } else if (headers.size() == 1) { + if (headers.front().second != "ignored") { actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second), - AddExtensionHeader(headers.at(1).first, headers.at(1).second), - AddExtensionHeader(headers.at(2).first, headers.at(2).second)); + AddExtensionHeader(headers.at(0).first, headers.at(0).second)); } - ASSERT_STATUS_OK(actual); - EXPECT_THAT(*actual, HasSubstr(bucket_name)); - EXPECT_THAT(*actual, HasSubstr(object_name)); - EXPECT_EQ(expected, *actual); + } else if (headers.size() == 2) { + // For some reason the function outputs them as a map + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(0).first, headers.at(0).second), + AddExtensionHeader(headers.at(1).first, headers.at(1).second)); + } else if (headers.size() == 3) { + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(0).first, headers.at(0).second), + AddExtensionHeader(headers.at(1).first, headers.at(1).second), + AddExtensionHeader(headers.at(2).first, headers.at(2).second)); + } else { + EXPECT_LT(headers.size(), 4); } - EXPECT_LT(headers.size(), 4); + ASSERT_STATUS_OK(actual); + EXPECT_THAT(*actual, HasSubstr(bucket_name)); + EXPECT_THAT(*actual, HasSubstr(object_name)); + EXPECT_EQ(expected, *actual); } } + } // namespace } // namespace STORAGE_CLIENT_NS } // namespace storage From 8316edbb5db08f1895012cac38d0db369cef60a9 Mon Sep 17 00:00:00 2001 From: rsimion Date: Wed, 27 Mar 2019 20:17:40 -0400 Subject: [PATCH 14/16] Minor change of a comment --- google/cloud/storage/tests/client_sign_url_integration_test.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index c4137f0e251b7..25902b1ebc343 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -60,8 +60,7 @@ class ObjectIntegrationTest // Check for the keys of the headers field for (auto& x : j_obj["headers"].items()) { // The keys are returned in alphabetical order by nlohmann::json, but - // the order does not matter when creating signed urls. in - // alphabetical order + // the order does not matter when creating signed urls. key_name = x.key(); value_name = x.value(); headers.emplace_back(key_name, value_name); From 4118acca164c3e6e8c21f0c1eb83b4d862975c43 Mon Sep 17 00:00:00 2001 From: rsimion Date: Thu, 28 Mar 2019 07:37:52 -0400 Subject: [PATCH 15/16] More cleanup --- .../tests/client_sign_url_integration_test.cc | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 25902b1ebc343..5bcd49bf31360 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -51,21 +51,11 @@ class ObjectIntegrationTest nl::json j_obj) { std::vector> headers; - for (auto& header : j_obj.items()) { - std::string header_key = header.key(); - - if (header_key == "headers") { - std::string key_name; - std::string value_name; - // Check for the keys of the headers field - for (auto& x : j_obj["headers"].items()) { - // The keys are returned in alphabetical order by nlohmann::json, but - // the order does not matter when creating signed urls. - key_name = x.key(); - value_name = x.value(); - headers.emplace_back(key_name, value_name); - } - } + // Check for the keys of the headers field + for (auto& x : j_obj["headers"].items()) { + // The keys are returned in alphabetical order by nlohmann::json, but + // the order does not matter when creating signed urls. + headers.emplace_back(x.key(), x.value()); } return headers; } @@ -107,21 +97,18 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com")); - // TODO(#2350) + // TODO(#2350) - when that bug is fixed we can remove this if() block. if (object_name == "") { continue; } } else if (headers.size() == 1) { - if (headers.front().second != "ignored") { - actual = client.CreateV4SignedUrl( - method_name, bucket_name, object_name, - SignedUrlTimestamp(internal::ParseRfc3339(date)), - SignedUrlDuration(valid_for), - AddExtensionHeader("host", "storage.googleapis.com"), - AddExtensionHeader(headers.at(0).first, headers.at(0).second)); - } + actual = client.CreateV4SignedUrl( + method_name, bucket_name, object_name, + SignedUrlTimestamp(internal::ParseRfc3339(date)), + SignedUrlDuration(valid_for), + AddExtensionHeader("host", "storage.googleapis.com"), + AddExtensionHeader(headers.at(0).first, headers.at(0).second)); } else if (headers.size() == 2) { - // For some reason the function outputs them as a map actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name, SignedUrlTimestamp(internal::ParseRfc3339(date)), From 307a7a2a7ef3b671478b33d5b24d817a3fb79be5 Mon Sep 17 00:00:00 2001 From: rsimion Date: Thu, 28 Mar 2019 08:23:19 -0400 Subject: [PATCH 16/16] Updated both files after #2350 was fixed --- google/cloud/storage/tests/UrlSignerV4TestData.json | 2 +- .../cloud/storage/tests/client_sign_url_integration_test.cc | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/google/cloud/storage/tests/UrlSignerV4TestData.json b/google/cloud/storage/tests/UrlSignerV4TestData.json index fdbc42d134e2d..6e8037040d4f9 100644 --- a/google/cloud/storage/tests/UrlSignerV4TestData.json +++ b/google/cloud/storage/tests/UrlSignerV4TestData.json @@ -117,6 +117,6 @@ "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" + "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=6dbe94f8e52b2b8a9a476b1c857efa474e09944e2b52b925800316e094a7169d8dbe0df9c0ac08dabb22ac7e827470ceccd65f5a3eadba2a4fb9beebfe37f0d9bb1e552b851fa31a25045bdf019e507f5feb44f061551ef1aeb18dcec0e38ba2e2f77d560a46eaace9c56ed9aa642281301a9d848b0eb30749e34bc7f73a3d596240533466ff9b5f289cd0d4c845c7d96b82a35a5abd0c3aff83e4440ee6873e796087f43545544dc8c01afe1d79c726696b6f555371e491980e7ec145cca0803cf562c38f3fa1d724242f5dea25aac91d74ec9ddd739ff65523627763eaef25cd1f95ad985aaf0079b7c74eb5bcb2870a9b137a7b2c8e41fbe838c95872f75b" } ] diff --git a/google/cloud/storage/tests/client_sign_url_integration_test.cc b/google/cloud/storage/tests/client_sign_url_integration_test.cc index 5bcd49bf31360..d15596ed7f148 100644 --- a/google/cloud/storage/tests/client_sign_url_integration_test.cc +++ b/google/cloud/storage/tests/client_sign_url_integration_test.cc @@ -96,11 +96,6 @@ TEST_F(ObjectIntegrationTest, V4SignJson) { SignedUrlTimestamp(internal::ParseRfc3339(date)), SignedUrlDuration(valid_for), AddExtensionHeader("host", "storage.googleapis.com")); - - // TODO(#2350) - when that bug is fixed we can remove this if() block. - if (object_name == "") { - continue; - } } else if (headers.size() == 1) { actual = client.CreateV4SignedUrl( method_name, bucket_name, object_name,