Skip to content

Commit 857717a

Browse files
author
Jan Hübner
committed
Sanitize host name for AWS requests before signing in AWSAuthV4 transport (ruflin#2090)
1 parent f72262d commit 857717a

File tree

4 files changed

+57
-3
lines changed

4 files changed

+57
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
* Updated `Query::create` PHPDoc to include supported types and propagate it to callers by @franmomu [#2088](https://github.com/ruflin/Elastica/pull/2088)
2525
* Update some iterable types in PHPDoc to be more specific by @franmomu [#2092](https://github.com/ruflin/Elastica/pull/2092)
2626
* Updated `AwsAuthV4Test` adding assertions for exception type by @franmomu [#2094](https://github.com/ruflin/Elastica/pull/2094)
27-
27+
* Update `AWSAuthV4 transport` to sanitize host name for AWS requests before signing [#2090](https://github.com/ruflin/Elastica/pull/2090)
2828
### Deprecated
2929
* Deprecated `Elastica\Reindex::WAIT_FOR_COMPLETION_FALSE`, use a boolean as parameter instead by @franmomu [#2070](https://github.com/ruflin/Elastica/pull/2070)
3030
* Passing anything else than a boolean as 1st argument to `Reindex::setWaitForCompletion`, pass a boolean instead by @franmomu [#2070](https://github.com/ruflin/Elastica/pull/2070)

phpstan-baseline.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,7 @@ parameters:
135135
count: 1
136136
path: tests/SnapshotTest.php
137137

138+
-
139+
message: "#^Function GuzzleHttp\\\\Psr7\\\\modify_request not found\\.$#"
140+
count: 1
141+
path: src/Transport/AwsAuthV4.php

src/Transport/AwsAuthV4.php

100755100644
Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use GuzzleHttp\Client;
1111
use GuzzleHttp\HandlerStack;
1212
use GuzzleHttp\Middleware;
13+
use GuzzleHttp\Psr7;
1314
use Psr\Http\Message\RequestInterface;
1415

1516
class AwsAuthV4 extends Guzzle
@@ -42,15 +43,33 @@ private function getSigningMiddleware(): callable
4243
: \getenv('AWS_REGION');
4344
$signer = new SignatureV4('es', $region);
4445
$credProvider = $this->getCredentialProvider();
46+
$transport = $this;
4547

4648
return Middleware::mapRequest(static function (RequestInterface $req) use (
4749
$signer,
48-
$credProvider
50+
$credProvider,
51+
$transport
4952
) {
50-
return $signer->signRequest($req, $credProvider()->wait());
53+
return $signer->signRequest($transport->sanitizeRequest($req), $credProvider()->wait());
5154
});
5255
}
5356

57+
private function sanitizeRequest(RequestInterface $request): RequestInterface
58+
{
59+
// Trailing dots are valid parts of DNS host names (see RFC 1034),
60+
// but interferes with header signing where AWS expects a stripped host name.
61+
if ('.' === \substr($request->getHeader('host')[0], -1)) {
62+
$changes = ['set_headers' => ['host' => \rtrim($request->getHeader('host')[0], '.')]];
63+
if (\class_exists(Psr7\Utils::class)) {
64+
$request = Psr7\Utils::modifyRequest($request, $changes);
65+
} else {
66+
$request = Psr7\modify_request($request, $changes);
67+
}
68+
}
69+
70+
return $request;
71+
}
72+
5473
private function getCredentialProvider(): callable
5574
{
5675
$connection = $this->getConnection();

tests/Transport/AwsAuthV4Test.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,35 @@ public function testSignsWithEnvironmentalCredentials(): void
205205
);
206206
}
207207
}
208+
209+
/**
210+
* @group unit
211+
* @depends testSignsWithProvidedCredentials
212+
*/
213+
public function testStripsTrailingDotInHost(): void
214+
{
215+
$host = $this->_getHost();
216+
$hostWithTrailingDot = $host.'.';
217+
218+
$config = [
219+
'persistent' => false,
220+
'transport' => 'AwsAuthV4',
221+
'aws_access_key_id' => 'foo',
222+
'aws_secret_access_key' => 'bar',
223+
'aws_session_token' => 'baz',
224+
'aws_region' => 'us-east-1',
225+
'host' => $hostWithTrailingDot,
226+
];
227+
$client = $this->_getClient($config);
228+
229+
try {
230+
$client->request('_stats');
231+
} catch (GuzzleException $e) {
232+
$guzzleException = $e->getGuzzleException();
233+
$this->assertInstanceOf(ConnectException::class, $guzzleException);
234+
$request = $guzzleException->getRequest();
235+
$this->assertSame($host, $request->getHeader('host')[0]);
236+
$this->assertSame($hostWithTrailingDot, $request->getUri()->getHost());
237+
}
238+
}
208239
}

0 commit comments

Comments
 (0)