Improved CrossDomainMiddleware preventing headers to be injected on non-CORS requests

This commit is contained in:
Alejandro Celaya 2016-07-19 20:20:18 +02:00
parent 0daa24739d
commit 839329d627
4 changed files with 49 additions and 16 deletions

View file

@ -34,7 +34,7 @@ abstract class AbstractRestMiddleware implements MiddlewareInterface
*/ */
public function __invoke(Request $request, Response $response, callable $out = null) public function __invoke(Request $request, Response $response, callable $out = null)
{ {
if (strtolower($request->getMethod()) === 'options') { if ($request->getMethod() === 'OPTIONS') {
return $response; return $response;
} }

View file

@ -63,7 +63,7 @@ class CheckAuthenticationMiddleware implements MiddlewareInterface
/** @var RouteResult $routeResult */ /** @var RouteResult $routeResult */
$routeResult = $request->getAttribute(RouteResult::class); $routeResult = $request->getAttribute(RouteResult::class);
if ((isset($routeResult) && $routeResult->getMatchedRouteName() === 'rest-authenticate') if ((isset($routeResult) && $routeResult->getMatchedRouteName() === 'rest-authenticate')
|| strtolower($request->getMethod()) === 'options' || $request->getMethod() === 'OPTIONS'
) { ) {
return $out($request, $response); return $out($request, $response);
} }

View file

@ -36,17 +36,26 @@ class CrossDomainMiddleware implements MiddlewareInterface
{ {
/** @var Response $response */ /** @var Response $response */
$response = $out($request, $response); $response = $out($request, $response);
if (! $request->hasHeader('Origin')) {
if (strtolower($request->getMethod()) === 'options') { return $response;
$response = $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Access-Control-Max-Age', '1000')
->withHeader(
// Allow all requested headers
'Access-Control-Allow-Headers',
$request->getHeaderLine('Access-Control-Request-Headers')
);
} }
return $response->withHeader('Access-Control-Allow-Origin', '*'); // Add Allow-Origin header
$response = $response->withHeader('Access-Control-Allow-Origin', '*');
if ($request->getMethod() !== 'OPTIONS') {
return $response;
}
// Add OPTIONS-specific headers
$headers = [
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS', // TODO Should be based on path
'Access-Control-Max-Age' => '1000',
'Access-Control-Allow-Headers' => $request->getHeaderLine('Access-Control-Request-Headers'),
];
foreach ($headers as $key => $value) {
$response = $response->withHeader($key, $value);
}
return $response;
} }
} }

View file

@ -21,15 +21,37 @@ class CrossDomainMiddlewareTest extends TestCase
/** /**
* @test * @test
*/ */
public function anyRequestIncludesTheAllowAccessHeader() public function nonCrossDomainRequestsAreNotAffected()
{ {
$originalResponse = new Response();
$response = $this->middleware->__invoke( $response = $this->middleware->__invoke(
ServerRequestFactory::fromGlobals(), ServerRequestFactory::fromGlobals(),
new Response(), $originalResponse,
function ($req, $resp) { function ($req, $resp) {
return $resp; return $resp;
} }
); );
$this->assertSame($originalResponse, $response);
$headers = $response->getHeaders();
$this->assertArrayNotHasKey('Access-Control-Allow-Origin', $headers);
$this->assertArrayNotHasKey('Access-Control-Allow-Headers', $headers);
}
/**
* @test
*/
public function anyRequestIncludesTheAllowAccessHeader()
{
$originalResponse = new Response();
$response = $this->middleware->__invoke(
ServerRequestFactory::fromGlobals()->withHeader('Origin', 'local'),
$originalResponse,
function ($req, $resp) {
return $resp;
}
);
$this->assertNotSame($originalResponse, $response);
$headers = $response->getHeaders(); $headers = $response->getHeaders();
$this->assertArrayHasKey('Access-Control-Allow-Origin', $headers); $this->assertArrayHasKey('Access-Control-Allow-Origin', $headers);
@ -41,11 +63,13 @@ class CrossDomainMiddlewareTest extends TestCase
*/ */
public function optionsRequestIncludesMoreHeaders() public function optionsRequestIncludesMoreHeaders()
{ {
$request = ServerRequestFactory::fromGlobals(['REQUEST_METHOD' => 'OPTIONS']); $originalResponse = new Response();
$request = ServerRequestFactory::fromGlobals(['REQUEST_METHOD' => 'OPTIONS'])->withHeader('Origin', 'local');
$response = $this->middleware->__invoke($request, new Response(), function ($req, $resp) { $response = $this->middleware->__invoke($request, $originalResponse, function ($req, $resp) {
return $resp; return $resp;
}); });
$this->assertNotSame($originalResponse, $response);
$headers = $response->getHeaders(); $headers = $response->getHeaders();
$this->assertArrayHasKey('Access-Control-Allow-Origin', $headers); $this->assertArrayHasKey('Access-Control-Allow-Origin', $headers);