Skip to content

Commit

Permalink
Merge pull request #1325 from georgeboot/patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
mnapoli authored Nov 22, 2022
2 parents 26b9061 + 02b46d0 commit 33d3402
Show file tree
Hide file tree
Showing 11 changed files with 368 additions and 12 deletions.
20 changes: 20 additions & 0 deletions src/Event/Http/HttpRequestEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ public function getRemotePort(): int
return (int) ($this->headers['x-forwarded-port'][0] ?? 80);
}

/**
* @return array{string, string}|array{null, null}
*/
public function getBasicAuthCredentials(): array
{
$authorizationHeader = trim($this->headers['authorization'][0] ?? '');

if (\strpos($authorizationHeader, 'Basic ') !== 0) {
return [null, null];
}

$auth = base64_decode(trim(explode(' ', $authorizationHeader)[1]));

if (! $auth || ! strpos($auth, ':')) {
return [null, null];
}

return explode(':', $auth, 2);
}

public function getServerPort(): int
{
return (int) ($this->headers['x-forwarded-port'][0] ?? 80);
Expand Down
31 changes: 21 additions & 10 deletions src/Event/Http/Psr7Bridge.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,33 @@ final class Psr7Bridge
*/
public static function convertRequest(HttpRequestEvent $event, Context $context): ServerRequestInterface
{
$headers = $event->getHeaders();

[$files, $parsedBody] = self::parseBodyAndUploadedFiles($event);
[$user, $password] = $event->getBasicAuthCredentials();

$server = [
'SERVER_PROTOCOL' => $event->getProtocolVersion(),
$server = array_filter([
'CONTENT_LENGTH' => $headers['content-length'][0] ?? null,
'CONTENT_TYPE' => $event->getContentType(),
'DOCUMENT_ROOT' => getcwd(),
'QUERY_STRING' => $event->getQueryString(),
'REQUEST_METHOD' => $event->getMethod(),
'SERVER_NAME' => $event->getServerName(),
'SERVER_PORT' => $event->getServerPort(),
'SERVER_PROTOCOL' => $event->getProtocol(),
'PATH_INFO' => $event->getPath(),
'HTTP_HOST' => $headers['host'] ?? null,
'REMOTE_ADDR' => $event->getSourceIp(),
'REMOTE_PORT' => $event->getRemotePort(),
'REQUEST_TIME' => time(),
'REQUEST_TIME_FLOAT' => microtime(true),
'QUERY_STRING' => $event->getQueryString(),
'DOCUMENT_ROOT' => getcwd(),
'REQUEST_URI' => $event->getUri(),
'REMOTE_ADDR' => $event->getSourceIp(),
];
'PHP_AUTH_USER' => $user,
'PHP_AUTH_PW' => $password,
]);

$headers = $event->getHeaders();
if (isset($headers['Host'])) {
$server['HTTP_HOST'] = $headers['Host'];
foreach ($headers as $name => $values) {
$server['HTTP_' . strtoupper(str_replace('-', '_', $name))] = $values[0];
}

/**
Expand Down Expand Up @@ -87,7 +98,7 @@ private static function parseBodyAndUploadedFiles(HttpRequestEvent $event): arra
$parsedBody = null;
$contentType = $event->getContentType();
if ($contentType !== null && $event->getMethod() === 'POST') {
if ($contentType === 'application/x-www-form-urlencoded') {
if (strpos($contentType, 'application/x-www-form-urlencoded') === 0) {
parse_str($bodyString, $parsedBody);
} else {
$document = new Part("Content-type: $contentType\r\n\r\n" . $bodyString);
Expand Down
29 changes: 29 additions & 0 deletions tests/Event/Http/CommonHttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,20 @@ public function test POST request with form data(int $version)
]);
}

/**
* @dataProvider provide API Gateway versions
*/
public function test POST request with form data and content type(int $version)
{
$this->fromFixture(__DIR__ . "/Fixture/ag-v$version-body-form-content-type.json");

$this->assertContentType('application/x-www-form-urlencoded;charset=UTF-8');
$this->assertParsedBody([
'foo' => 'bar',
'bim' => 'baz',
]);
}

public function provideHttpMethodsWithRequestBodySupport(): array
{
return [
Expand Down Expand Up @@ -438,6 +452,17 @@ public function test path parameters(int $version)
]);
}

/**
* @dataProvider provide API Gateway versions
*/
public function test request with basic auth(int $version)
{
$this->fromFixture(__DIR__ . "/Fixture/ag-v$version-header-basic-auth.json");

$this->assertBasicAuthUser('fake');
$this->assertBasicAuthPassword('secret');
}

abstract protected function fromFixture(string $file): void;

abstract protected function assertBody(string $expected): void;
Expand Down Expand Up @@ -476,6 +501,10 @@ abstract protected function assertParsedBody(array $expected): void;

abstract protected function assertSourceIp(string $expected): void;

abstract protected function assertBasicAuthUser(string $expected): void;

abstract protected function assertBasicAuthPassword(string $expected): void;

abstract protected function assertUploadedFile(
string $key,
string $filename,
Expand Down
53 changes: 53 additions & 0 deletions tests/Event/Http/Fixture/ag-v1-body-form-content-type.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"version": "1.0",
"resource": "/path",
"path": "/path",
"httpMethod": "POST",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Cache-Control": "no-cache",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"Host": "example.org",
"User-Agent": "PostmanRuntime/7.20.1",
"X-Amzn-Trace-Id": "Root=1-ffffffff-ffffffffffffffffffffffff",
"X-Forwarded-For": "1.1.1.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"resourceId": "xxxxxx",
"resourcePath": "/path",
"httpMethod": "PUT",
"extendedRequestId": "XXXXXX-xxxxxxxx=",
"requestTime": "24/Nov/2019:18:55:08 +0000",
"path": "/path",
"accountId": "123400000000",
"protocol": "HTTP/1.1",
"stage": "dev",
"domainPrefix": "dev",
"requestTimeEpoch": 1574621708700,
"requestId": "ffffffff-ffff-4fff-ffff-ffffffffffff",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"sourceIp": "1.1.1.1",
"principalOrgId": null,
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "PostmanRuntime/7.20.1",
"user": null
},
"domainName": "example.org",
"apiId": "xxxxxxxxxx"
},
"body": "foo=bar&bim=baz",
"isBase64Encoded": false
}
53 changes: 53 additions & 0 deletions tests/Event/Http/Fixture/ag-v1-header-basic-auth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"version": "1.0",
"resource": "/path",
"path": "/path",
"httpMethod": "GET",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Authorization": "Basic ZmFrZTpzZWNyZXQ=",
"Cache-Control": "no-cache",
"Host": "example.org",
"User-Agent": "PostmanRuntime/7.20.1",
"X-Amzn-Trace-Id": "Root=1-ffffffff-ffffffffffffffffffffffff",
"X-Forwarded-For": "1.1.1.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"resourceId": "xxxxxx",
"resourcePath": "/path",
"httpMethod": "PUT",
"extendedRequestId": "XXXXXX-xxxxxxxx=",
"requestTime": "24/Nov/2019:18:55:08 +0000",
"path": "/path",
"accountId": "123400000000",
"protocol": "HTTP/1.1",
"stage": "dev",
"domainPrefix": "dev",
"requestTimeEpoch": 1574621708700,
"requestId": "ffffffff-ffff-4fff-ffff-ffffffffffff",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"sourceIp": "1.1.1.1",
"principalOrgId": null,
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "PostmanRuntime/7.20.1",
"user": null
},
"domainName": "example.org",
"apiId": "xxxxxxxxxx"
},
"body": "",
"isBase64Encoded": false
}
42 changes: 42 additions & 0 deletions tests/Event/Http/Fixture/ag-v2-body-form-content-type.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"version": "2.0",
"routeKey": "ANY /path",
"rawPath": "/path",
"rawQueryString": "",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Cache-Control": "no-cache",
"Content-Length": 15,
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"Host": "example.org",
"User-Agent": "PostmanRuntime/7.20.1",
"X-Amzn-Trace-Id": "Root=1-ffffffff-ffffffffffffffffffffffff",
"X-Forwarded-For": "1.1.1.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": null,
"stageVariables": null,
"requestContext": {
"accountId": "123400000000",
"apiId": "xxxxxxxxxx",
"domainName": "example.org",
"domainPrefix": "0000000000",
"http": {
"method": "POST",
"path": "/path",
"protocol": "HTTP/1.1",
"sourceIp": "1.1.1.1",
"userAgent": "PostmanRuntime/7.20.1"
},
"requestId": "JTHoQgr2oAMEPMg=",
"routeId": "47matwk",
"routeKey": "ANY /path",
"stage": "$default",
"time": "24/Nov/2019:18:55:08 +0000",
"timeEpoch": 1574621708700
},
"body": "foo=bar&bim=baz",
"isBase64Encoded": false
}
40 changes: 40 additions & 0 deletions tests/Event/Http/Fixture/ag-v2-header-basic-auth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"version": "2.0",
"routeKey": "ANY /path",
"rawPath": "/path",
"rawQueryString": "",
"cookies": [],
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"authorization": "Basic ZmFrZTpzZWNyZXQ=",
"cache-control": "no-cache",
"host": "example.org",
"user-agent": "PostmanRuntime/7.20.1",
"x-amzn-trace-id": "Root=1-ffffffff-ffffffffffffffffffffffff",
"x-forwarded-for": "1.1.1.1",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"queryStringParameters": null,
"requestContext": {
"accountId": "123400000000",
"apiId": "xxxxxxxxxx",
"domainName": "example.org",
"domainPrefix": "0000000000",
"http": {
"method": "GET",
"path": "/path",
"protocol": "HTTP/1.1",
"sourceIp": "1.1.1.1",
"userAgent": "PostmanRuntime/7.20.1"
},
"requestId": "JTHoQgr2oAMEPMg=",
"routeId": "47matwk",
"routeKey": "ANY /path",
"stage": "$default",
"time": "24/Nov/2019:18:55:08 +0000",
"timeEpoch": 1574621708700
},
"isBase64Encoded": false
}
12 changes: 12 additions & 0 deletions tests/Event/Http/HttpRequestEventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ protected function assertPathParameters(array $expected): void
$this->assertEquals($expected, $this->event->getPathParameters());
}

protected function assertBasicAuthUser(string $expected): void
{
[$user, $pass] = $this->event->getBasicAuthCredentials();
$this->assertEquals($expected, $user);
}

protected function assertBasicAuthPassword(string $expected): void
{
[$user, $pass] = $this->event->getBasicAuthCredentials();
$this->assertEquals($expected, $pass);
}

public function test empty invocation will have friendly error message()
{
$message = 'This handler expected to be invoked with a API Gateway or ALB event. Instead, the handler was invoked with invalid event data: null';
Expand Down
14 changes: 12 additions & 2 deletions tests/Event/Http/Psr7BridgeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ protected function assertPath(string $expected): void
protected function assertQueryString(string $expected): void
{
$this->assertEquals($expected, $this->request->getUri()->getQuery());
$this->assertEquals($expected, $this->request->getServerParams()['QUERY_STRING']);
$this->assertEquals($expected, $this->request->getServerParams()['QUERY_STRING'] ?? '');
}

protected function assertQueryParameters(array $expected): void
Expand All @@ -83,12 +83,12 @@ protected function assertQueryParameters(array $expected): void
protected function assertProtocol(string $expected): void
{
$this->assertEquals($expected, 'HTTP/' . $this->request->getProtocolVersion());
$this->assertEquals($expected, $this->request->getServerParams()['SERVER_PROTOCOL']);
}

protected function assertProtocolVersion(string $expected): void
{
$this->assertEquals($expected, $this->request->getProtocolVersion());
$this->assertEquals($expected, $this->request->getServerParams()['SERVER_PROTOCOL']);
}

protected function assertHeader(string $header, array $expectedValue): void
Expand Down Expand Up @@ -157,4 +157,14 @@ protected function assertSourceIp(string $expected): void
{
$this->assertEquals($expected, $this->request->getServerParams()['REMOTE_ADDR']);
}

protected function assertBasicAuthUser(string $expected): void
{
$this->assertEquals($expected, $this->request->getServerParams()['PHP_AUTH_USER']);
}

protected function assertBasicAuthPassword(string $expected): void
{
$this->assertEquals($expected, $this->request->getServerParams()['PHP_AUTH_PW']);
}
}
Loading

0 comments on commit 33d3402

Please sign in to comment.