Skip to content

Commit 4f04ae1

Browse files
authored
Topic/convert headers to lowercase when calculating signature (#179)
* Convert headers to lowercase when calculating signature via HttpSignatureHeaders::forConfig. guzzle/nyholm psr7 libraries infer the "Host" header (capitalized) from the URI if not explicitly specified. User may also specify other headers which aren't already lowercased. Amazon requires header names to be lowercased before generating the hash: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html "To create the canonical headers list, convert all header names to lowercase ...". Mixed header case was already somewhat handled but inconsistent across different functions. * Added test for somewhat validating header names are converted to lowercase. * Fixed failing test.
1 parent 2361032 commit 4f04ae1

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

src/AmazonPHP/SellingPartner/HttpSignatureHeaders.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ public static function forConfig(
7373
$canonicalHeaders = [];
7474

7575
foreach ($allHeaders as $headerName => $headerValue) {
76-
if (\in_array(\strtolower($headerName), $blacklistHeaders, true)) {
76+
$headerName = \strtolower($headerName);
77+
78+
if (\in_array($headerName, $blacklistHeaders, true)) {
7779
continue;
7880
}
7981

@@ -204,17 +206,19 @@ public static function raw(
204206
$canonicalHeaders = [];
205207

206208
foreach ($allHeaders as $headerName => $headerValue) {
207-
if (\in_array(\strtolower($headerName), $blacklistHeaders, true)) {
209+
$headerName = \strtolower($headerName);
210+
211+
if (\in_array($headerName, $blacklistHeaders, true)) {
208212
continue;
209213
}
210214

211-
$canonicalHeaders[\strtolower($headerName)] = $headerValue;
215+
$canonicalHeaders[$headerName] = $headerValue;
212216

213217
if (\count($headerValue) > 0) {
214218
\sort($headerValue);
215219
}
216220

217-
$canonicalHeadersStr .= \strtolower($headerName) . ':' . \implode(',', $headerValue) . "\n";
221+
$canonicalHeadersStr .= $headerName . ':' . \implode(',', $headerValue) . "\n";
218222
}
219223

220224
$signedHeadersStr = \implode(';', \array_keys($canonicalHeaders));
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace AmazonPHP\Test\AmazonPHP\SellingPartner\Tests\Unit;
4+
5+
use AmazonPHP\SellingPartner\AccessToken;
6+
use AmazonPHP\SellingPartner\Configuration;
7+
use AmazonPHP\SellingPartner\HttpSignatureHeaders;
8+
use AmazonPHP\SellingPartner\Regions;
9+
use Nyholm\Psr7\Request;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class HttpSignatureHeadersTest extends TestCase
13+
{
14+
private ?Configuration $configuration;
15+
16+
private ?AccessToken $accessToken;
17+
18+
protected function setUp(): void
19+
{
20+
$this->configuration = Configuration::forIAMUser('testId', 'testSecret', 'testAccessKey', 'testSecretKey');
21+
$this->accessToken = new AccessToken('testAccessToken', 'testRefreshToken', 'bearer', 3600, 'refresh_token');
22+
}
23+
24+
protected function tearDown(): void
25+
{
26+
$this->configuration = null;
27+
$this->accessToken = null;
28+
}
29+
30+
public function test_converts_header_names_to_lowercase(): void
31+
{
32+
$shortDate = gmdate('Ymd');
33+
$request = new Request(
34+
'GET',
35+
'https://sellingpartnerapi-fe.amazon.com/sellers/v1/marketplaceParticipations',
36+
// both guzzlehttp/psr7 and nyholm/psr7 infer the host from the URI as "Host" (capitalized).
37+
// explicitly specifying uppercase in-case behaviour of the PSR7 library used in the test changes.
38+
['Host' => ['sellingpartnerapi-fe.amazon.com']]
39+
);
40+
$signedRequest = HttpSignatureHeaders::forConfig(
41+
$this->configuration,
42+
$this->accessToken,
43+
Regions::FAR_EAST,
44+
$request
45+
);
46+
47+
$this->assertMatchesRegularExpression(
48+
"#^AWS4-HMAC-SHA256 Credential=testAccessKey/$shortDate/us-west-2/execute-api/aws4_request, " .
49+
"SignedHeaders=host;x-amz-access-token;x-amz-date, " .
50+
"Signature=[0-9a-f]{64}$#",
51+
$signedRequest->getHeader('Authorization')[0]
52+
);
53+
}
54+
}

0 commit comments

Comments
 (0)