From 481aec00fb51d8d19e54b8b38b9130b27ffee56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 21 May 2020 13:17:59 +0200 Subject: [PATCH] Fix signing of request with Date in header (#635) --- CHANGELOG.md | 4 ++++ src/Signer/SignerV4.php | 12 +----------- tests/Unit/Signer/SignerV4Test.php | 15 +++++---------- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d292b..280b4af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ - Custom endpoints should not contain `%region%` and `%service` placeholder. They won't be replaced anymore in 2.0 - Protected methods `getServiceCode`, `getSignatureVersion` and `getSignatureScopeName` of AbstractApi are deprecated and will be removed in 2.0 +### Fixed + +- Fix signing of requests with a header containing a date (like `expires` in `S3`). + ## 1.1.0 ### Added diff --git a/src/Signer/SignerV4.php b/src/Signer/SignerV4.php index 43cb5be..3763b5c 100644 --- a/src/Signer/SignerV4.php +++ b/src/Signer/SignerV4.php @@ -267,22 +267,12 @@ private function buildCanonicalHeaders(Request $request, bool $isPresign): array { // Case-insensitively aggregate all of the headers. $canonicalHeaders = []; - foreach ($request->getHeaders() as $key => $values) { + foreach ($request->getHeaders() as $key => $value) { $key = strtolower($key); if (isset(self::BLACKLIST_HEADERS[$key])) { continue; } - if (!\is_array($values) && false !== \strpos($values, ',')) { - $values = array_map('trim', \explode(',', $values)); - } - if (\is_array($values)) { - sort($values); - $value = \implode(',', $values); - } else { - $value = $values; - } - $canonicalHeaders[$key] = "$key:$value"; } ksort($canonicalHeaders); diff --git a/tests/Unit/Signer/SignerV4Test.php b/tests/Unit/Signer/SignerV4Test.php index 23c4403..32f68d0 100644 --- a/tests/Unit/Signer/SignerV4Test.php +++ b/tests/Unit/Signer/SignerV4Test.php @@ -91,11 +91,6 @@ public function provideRequests() "GET / HTTP/1.1\r\nHost: host.foo.com\r\nx-AMZ-date: 20110909T233600Z\r\nZOO:zoobar\r\n\r\n", "GET / HTTP/1.1\r\nHost: host.foo.com\r\nZOO: zoobar\r\nX-Amz-Date: 20110909T233600Z\r\nAuthorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=host;x-amz-date;zoo, Signature=287deb2c1249c9c415cb4b3ef74404629fcab56a8e9ec568bff88cf093196e8e\r\n\r\n", ], - // Duplicate header values must be sorted. - [ - "POST / HTTP/1.1\r\nHost: host.foo.com\r\nx-AMZ-date: 20110909T233600Z\r\np: z\r\np: a\r\np: p\r\np: a\r\n\r\n", - "POST / HTTP/1.1\r\nHost: host.foo.com\r\np: z, a, p, a\r\nX-Amz-Date: 20110909T233600Z\r\nAuthorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=host;p;x-amz-date, Signature=faca06aa6ae71c0a24116c9a61b01346e6d9d621001bac49d38a6fdb285649ec\r\n\r\n", - ], // Request with space. [ "GET /%20/foo HTTP/1.1\r\nHost: host.foo.com\r\n\r\n", @@ -121,11 +116,6 @@ public function provideRequests() "GET / HTTP/1.1\r\nHost: host.foo.com:443\r\nx-AMZ-date: 20110909T233600Z\r\nZOO:zoobar\r\n\r\n", "GET / HTTP/1.1\r\nHost: host.foo.com:443\r\nZOO: zoobar\r\nX-Amz-Date: 20110909T233600Z\r\nAuthorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=host;x-amz-date;zoo, Signature=69c57723eee136a804b6d4b1fd1b4d45ba059e1f758900a6b1301111e1e8c77e\r\n\r\n", ], - // HTTPS Duplicate header values must be sorted. - [ - "POST / HTTP/1.1\r\nHost: host.foo.com:443\r\nx-AMZ-date: 20110909T233600Z\r\np: z\r\np: a\r\np: p\r\np: a\r\n\r\n", - "POST / HTTP/1.1\r\nHost: host.foo.com:443\r\np: z, a, p, a\r\nX-Amz-Date: 20110909T233600Z\r\nAuthorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=host;p;x-amz-date, Signature=cec423fa9e930519918d3c05982c14ae60b7c5aedd296f2a1322b5831bbaf4ea\r\n\r\n", - ], // HTTPS Request with space. [ "GET /%20/foo HTTP/1.1\r\nHost: host.foo.com:443\r\n\r\n", @@ -142,6 +132,11 @@ public function provideRequests() "POST / HTTP/1.1\r\nHost: host.foo.com:443\r\nContent-Length: 4\r\nX-Amz-Date: 20110909T233600Z\r\nAuthorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=host;x-amz-date, Signature=e971be49c79358595ef6214f683ac9c0489d397a5d5d13b361291e751deeca03\r\n\r\nTest", "POST\n/\n\nhost:host.foo.com:443\n\nhost\n532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25", ], + // DateHeader should be kept + [ + "POST / HTTP/1.1\r\nHost: host.foo.com:443\r\nx-AMZ-date: 20110909T233600Z\r\nExpires: Thu, 21 May 20 20:54:15 +0200\r\n\r\n", + "POST / HTTP/1.1\r\nHost: host.foo.com:443\r\nexpires:Thu, 21 May 20 20:54:15 +0200\r\nX-Amz-Date: 20110909T233600Z\r\nAuthorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=expires;host;x-amz-date, Signature=7090e12acc44281b2b46ba195ee1ae09f2e8c81653fcd592abbfbc30e1a5acc6\r\n\r\n", + ], ]; }