Merge branch '2.8' into 3.4
* 2.8: [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer
This commit is contained in:
commit
bcf5897bb1
@ -2087,6 +2087,11 @@ class Request
|
|||||||
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
|
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
|
||||||
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
|
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
|
||||||
$forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
|
$forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
|
||||||
|
if (self::HEADER_CLIENT_PORT === $type) {
|
||||||
|
foreach ($forwardedValues as $k => $v) {
|
||||||
|
$forwardedValues[$k] = substr_replace($v, '0.0.0.0', 0, strrpos($v, ':'));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $ip) {
|
if (null !== $ip) {
|
||||||
|
@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Controller\ControllerReference;
|
use Symfony\Component\HttpKernel\Controller\ControllerReference;
|
||||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||||
|
use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler;
|
||||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
use Symfony\Component\HttpKernel\KernelEvents;
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
|
|
||||||
$level = ob_get_level();
|
$level = ob_get_level();
|
||||||
try {
|
try {
|
||||||
return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
|
return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// we dispatch the exception event to trigger the logging
|
// we dispatch the exception event to trigger the logging
|
||||||
// the response that comes back is simply ignored
|
// the response that comes back is simply ignored
|
||||||
@ -109,25 +110,6 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
$cookies = $request->cookies->all();
|
$cookies = $request->cookies->all();
|
||||||
$server = $request->server->all();
|
$server = $request->server->all();
|
||||||
|
|
||||||
// Override the arguments to emulate a sub-request.
|
|
||||||
// Sub-request object will point to localhost as client ip and real client ip
|
|
||||||
// will be included into trusted header for client ip
|
|
||||||
try {
|
|
||||||
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
|
|
||||||
$currentXForwardedFor = $request->headers->get('X_FORWARDED_FOR', '');
|
|
||||||
|
|
||||||
$server['HTTP_X_FORWARDED_FOR'] = ($currentXForwardedFor ? $currentXForwardedFor.', ' : '').$request->getClientIp();
|
|
||||||
} elseif (method_exists(Request::class, 'getTrustedHeaderName') && $trustedHeaderName = Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP, false)) {
|
|
||||||
$currentXForwardedFor = $request->headers->get($trustedHeaderName, '');
|
|
||||||
|
|
||||||
$server['HTTP_'.$trustedHeaderName] = ($currentXForwardedFor ? $currentXForwardedFor.', ' : '').$request->getClientIp();
|
|
||||||
}
|
|
||||||
} catch (\InvalidArgumentException $e) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
$server['REMOTE_ADDR'] = $this->resolveTrustedProxy();
|
|
||||||
|
|
||||||
unset($server['HTTP_IF_MODIFIED_SINCE']);
|
unset($server['HTTP_IF_MODIFIED_SINCE']);
|
||||||
unset($server['HTTP_IF_NONE_MATCH']);
|
unset($server['HTTP_IF_NONE_MATCH']);
|
||||||
|
|
||||||
@ -143,17 +125,6 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
return $subRequest;
|
return $subRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resolveTrustedProxy()
|
|
||||||
{
|
|
||||||
if (!$trustedProxies = Request::getTrustedProxies()) {
|
|
||||||
return '127.0.0.1';
|
|
||||||
}
|
|
||||||
|
|
||||||
$firstTrustedProxy = reset($trustedProxies);
|
|
||||||
|
|
||||||
return false !== ($i = strpos($firstTrustedProxy, '/')) ? substr($firstTrustedProxy, 0, $i) : $firstTrustedProxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -444,27 +444,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
|
|||||||
$this->surrogate->addSurrogateCapability($request);
|
$this->surrogate->addSurrogateCapability($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify the X-Forwarded-For header if needed
|
|
||||||
$forwardedFor = $request->headers->get('X-Forwarded-For');
|
|
||||||
if ($forwardedFor) {
|
|
||||||
$request->headers->set('X-Forwarded-For', $forwardedFor.', '.$request->server->get('REMOTE_ADDR'));
|
|
||||||
} else {
|
|
||||||
$request->headers->set('X-Forwarded-For', $request->server->get('REMOTE_ADDR'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix the client IP address by setting it to 127.0.0.1 as HttpCache
|
|
||||||
// is always called from the same process as the backend.
|
|
||||||
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
|
||||||
|
|
||||||
// make sure HttpCache is a trusted proxy
|
|
||||||
if (!\in_array('127.0.0.1', $trustedProxies = Request::getTrustedProxies())) {
|
|
||||||
$trustedProxies[] = '127.0.0.1';
|
|
||||||
Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// always a "master" request (as the real master request can be in cache)
|
// always a "master" request (as the real master request can be in cache)
|
||||||
$response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch);
|
$response = SubRequestHandler::handle($this->kernel, $request, HttpKernelInterface::MASTER_REQUEST, $catch);
|
||||||
// FIXME: we probably need to also catch exceptions if raw === true
|
|
||||||
|
|
||||||
// we don't implement the stale-if-error on Requests, which is nonetheless part of the RFC
|
// we don't implement the stale-if-error on Requests, which is nonetheless part of the RFC
|
||||||
if (null !== $entry && \in_array($response->getStatusCode(), array(500, 502, 503, 504))) {
|
if (null !== $entry && \in_array($response->getStatusCode(), array(500, 502, 503, 504))) {
|
||||||
|
104
src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php
Normal file
104
src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpKernel\HttpCache;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\IpUtils;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class SubRequestHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public static function handle(HttpKernelInterface $kernel, Request $request, $type, $catch)
|
||||||
|
{
|
||||||
|
// save global state related to trusted headers and proxies
|
||||||
|
$trustedProxies = Request::getTrustedProxies();
|
||||||
|
$trustedHeaderSet = Request::getTrustedHeaderSet();
|
||||||
|
if (\method_exists(Request::class, 'getTrustedHeaderName')) {
|
||||||
|
Request::setTrustedProxies($trustedProxies, -1);
|
||||||
|
$trustedHeaders = array(
|
||||||
|
Request::HEADER_FORWARDED => Request::getTrustedHeaderName(Request::HEADER_FORWARDED, false),
|
||||||
|
Request::HEADER_X_FORWARDED_FOR => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_FOR, false),
|
||||||
|
Request::HEADER_X_FORWARDED_HOST => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_HOST, false),
|
||||||
|
Request::HEADER_X_FORWARDED_PROTO => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_PROTO, false),
|
||||||
|
Request::HEADER_X_FORWARDED_PORT => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_PORT, false),
|
||||||
|
);
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
} else {
|
||||||
|
$trustedHeaders = array(
|
||||||
|
Request::HEADER_FORWARDED => 'FORWARDED',
|
||||||
|
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
|
||||||
|
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
|
||||||
|
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
|
||||||
|
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove untrusted values
|
||||||
|
$remoteAddr = $request->server->get('REMOTE_ADDR');
|
||||||
|
if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) {
|
||||||
|
foreach ($trustedHeaders as $key => $name) {
|
||||||
|
if ($trustedHeaderSet & $key) {
|
||||||
|
$request->headers->remove($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute trusted values, taking any trusted proxies into account
|
||||||
|
$trustedIps = array();
|
||||||
|
$trustedValues = array();
|
||||||
|
foreach (array_reverse($request->getClientIps()) as $ip) {
|
||||||
|
$trustedIps[] = $ip;
|
||||||
|
$trustedValues[] = sprintf('for="%s"', $ip);
|
||||||
|
}
|
||||||
|
if ($ip !== $remoteAddr) {
|
||||||
|
$trustedIps[] = $remoteAddr;
|
||||||
|
$trustedValues[] = sprintf('for="%s"', $remoteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set trusted values, reusing as much as possible the global trusted settings
|
||||||
|
if (Request::HEADER_FORWARDED & $trustedHeaderSet) {
|
||||||
|
$trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme());
|
||||||
|
$request->headers->set($trustedHeaders[Request::HEADER_FORWARDED], implode(', ', $trustedValues));
|
||||||
|
}
|
||||||
|
if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) {
|
||||||
|
$request->headers->set($trustedHeaders[Request::HEADER_X_FORWARDED_FOR], implode(', ', $trustedIps));
|
||||||
|
} elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) {
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR);
|
||||||
|
$request->headers->set($trustedHeaders[Request::HEADER_X_FORWARDED_FOR], implode(', ', $trustedIps));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix the client IP address by setting it to 127.0.0.1,
|
||||||
|
// which is the core responsibility of this method
|
||||||
|
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||||
|
|
||||||
|
// ensure 127.0.0.1 is set as trusted proxy
|
||||||
|
if (!IpUtils::checkIp('127.0.0.1', $trustedProxies)) {
|
||||||
|
Request::setTrustedProxies(array_merge($trustedProxies, array('127.0.0.1')), Request::getTrustedHeaderSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $kernel->handle($request, $type, $catch);
|
||||||
|
} finally {
|
||||||
|
// restore global state
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -46,7 +46,7 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
$subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');
|
$subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');
|
||||||
$subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en'));
|
$subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en'));
|
||||||
$subRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$subRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$subRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
|
||||||
|
|
||||||
@ -99,7 +99,10 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
{
|
{
|
||||||
Request::setTrustedProxies(array(), 0);
|
Request::setTrustedProxies(array(), 0);
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest(Request::create('/')));
|
$expectedSubRequest = Request::create('/');
|
||||||
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
|
|
||||||
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
$this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
|
$this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
|
||||||
|
|
||||||
Request::setTrustedProxies(array(), -1);
|
Request::setTrustedProxies(array(), -1);
|
||||||
@ -190,8 +193,8 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
|
|
||||||
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
|
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
|
||||||
}
|
}
|
||||||
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
|
|
||||||
@ -202,7 +205,7 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
|
|
||||||
public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()
|
public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()
|
||||||
{
|
{
|
||||||
Request::setTrustedProxies(array(), 0);
|
Request::setTrustedProxies(array(), Request::HEADER_FORWARDED);
|
||||||
|
|
||||||
$this->testESIHeaderIsKeptInSubrequest();
|
$this->testESIHeaderIsKeptInSubrequest();
|
||||||
|
|
||||||
@ -213,7 +216,7 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
{
|
{
|
||||||
$expectedSubRequest = Request::create('/');
|
$expectedSubRequest = Request::create('/');
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
$request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*'));
|
$request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*'));
|
||||||
@ -226,9 +229,9 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
|
|
||||||
$expectedSubRequest = Request::create('/');
|
$expectedSubRequest = Request::create('/');
|
||||||
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
||||||
$expectedSubRequest->server->set('REMOTE_ADDR', '1.1.1.1');
|
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
|
|
||||||
@ -243,9 +246,9 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
{
|
{
|
||||||
$expectedSubRequest = Request::create('/');
|
$expectedSubRequest = Request::create('/');
|
||||||
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
||||||
$expectedSubRequest->server->set('REMOTE_ADDR', '1.1.1.1');
|
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
Request::setTrustedProxies(array('1.1.1.1/24'), -1);
|
Request::setTrustedProxies(array('1.1.1.1/24'), -1);
|
||||||
|
|
||||||
|
@ -1338,20 +1338,27 @@ class HttpCacheTest extends HttpCacheTestCase
|
|||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
||||||
|
|
||||||
$this->assertEquals('127.0.0.1', $this->kernel->getBackendRequest()->server->get('REMOTE_ADDR'));
|
$this->kernel->assert(function ($backendRequest) {
|
||||||
|
$this->assertSame('127.0.0.1', $backendRequest->server->get('REMOTE_ADDR'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getTrustedProxyData
|
* @dataProvider getTrustedProxyData
|
||||||
*/
|
*/
|
||||||
public function testHttpCacheIsSetAsATrustedProxy(array $existing, array $expected)
|
public function testHttpCacheIsSetAsATrustedProxy(array $existing)
|
||||||
{
|
{
|
||||||
Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_ALL);
|
Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_ALL);
|
||||||
|
|
||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
||||||
|
$this->assertSame($existing, Request::getTrustedProxies());
|
||||||
|
|
||||||
$this->assertEquals($expected, Request::getTrustedProxies());
|
$existing = array_unique(array_merge($existing, array('127.0.0.1')));
|
||||||
|
$this->kernel->assert(function ($backendRequest) use ($existing) {
|
||||||
|
$this->assertSame($existing, Request::getTrustedProxies());
|
||||||
|
$this->assertsame('10.0.0.1', $backendRequest->getClientIp());
|
||||||
|
});
|
||||||
|
|
||||||
Request::setTrustedProxies(array(), -1);
|
Request::setTrustedProxies(array(), -1);
|
||||||
}
|
}
|
||||||
@ -1359,45 +1366,41 @@ class HttpCacheTest extends HttpCacheTestCase
|
|||||||
public function getTrustedProxyData()
|
public function getTrustedProxyData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(array(), array('127.0.0.1')),
|
array(array()),
|
||||||
array(array('10.0.0.2'), array('10.0.0.2', '127.0.0.1')),
|
array(array('10.0.0.2')),
|
||||||
array(array('10.0.0.2', '127.0.0.1'), array('10.0.0.2', '127.0.0.1')),
|
array(array('10.0.0.2', '127.0.0.1')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getXForwardedForData
|
* @dataProvider getForwardedData
|
||||||
*/
|
*/
|
||||||
public function testXForwarderForHeaderForForwardedRequests($xForwardedFor, $expected)
|
public function testForwarderHeaderForForwardedRequests($forwarded, $expected)
|
||||||
{
|
{
|
||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
$server = array('REMOTE_ADDR' => '10.0.0.1');
|
$server = array('REMOTE_ADDR' => '10.0.0.1');
|
||||||
if (false !== $xForwardedFor) {
|
if (null !== $forwarded) {
|
||||||
$server['HTTP_X_FORWARDED_FOR'] = $xForwardedFor;
|
Request::setTrustedProxies($server, -1);
|
||||||
|
$server['HTTP_FORWARDED'] = $forwarded;
|
||||||
}
|
}
|
||||||
$this->request('GET', '/', $server);
|
$this->request('GET', '/', $server);
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
|
$this->kernel->assert(function ($backendRequest) use ($expected) {
|
||||||
|
$this->assertSame($expected, $backendRequest->headers->get('Forwarded'));
|
||||||
|
});
|
||||||
|
|
||||||
|
Request::setTrustedProxies(array(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getXForwardedForData()
|
public function getForwardedData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(false, '10.0.0.1'),
|
array(null, 'for="10.0.0.1";host="localhost";proto=http'),
|
||||||
array('10.0.0.2', '10.0.0.2, 10.0.0.1'),
|
array('for=10.0.0.2', 'for="10.0.0.2";host="localhost";proto=http, for="10.0.0.1"'),
|
||||||
array('10.0.0.2, 10.0.0.3', '10.0.0.2, 10.0.0.3, 10.0.0.1'),
|
array('for=10.0.0.2, for=10.0.0.3', 'for="10.0.0.2";host="localhost";proto=http, for="10.0.0.3", for="10.0.0.1"'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testXForwarderForHeaderForPassRequests()
|
|
||||||
{
|
|
||||||
$this->setNextResponse();
|
|
||||||
$server = array('REMOTE_ADDR' => '10.0.0.1');
|
|
||||||
$this->request('POST', '/', $server);
|
|
||||||
|
|
||||||
$this->assertEquals('10.0.0.1', $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses()
|
public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses()
|
||||||
{
|
{
|
||||||
$time = \DateTime::createFromFormat('U', time());
|
$time = \DateTime::createFromFormat('U', time());
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpKernel\Tests\HttpCache;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler;
|
||||||
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
|
|
||||||
|
class SubRequestHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
private static $globalState;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
self::$globalState = $this->getGlobalState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(self::$globalState[0], self::$globalState[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTrustedHeadersAreKept()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(array('10.0.0.1'), -1);
|
||||||
|
$globalState = $this->getGlobalState();
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('X-Forwarded-For', '10.0.0.2');
|
||||||
|
$request->headers->set('X-Forwarded-Host', 'Good');
|
||||||
|
$request->headers->set('X-Forwarded-Port', '1234');
|
||||||
|
$request->headers->set('X-Forwarded-Proto', 'https');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.2', $request->getClientIp());
|
||||||
|
$this->assertSame('Good', $request->headers->get('X-Forwarded-Host'));
|
||||||
|
$this->assertSame('1234', $request->headers->get('X-Forwarded-Port'));
|
||||||
|
$this->assertSame('https', $request->headers->get('X-Forwarded-Proto'));
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame($globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUntrustedHeadersAreRemoved()
|
||||||
|
{
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('X-Forwarded-For', '10.0.0.2');
|
||||||
|
$request->headers->set('X-Forwarded-Host', 'Evil');
|
||||||
|
$request->headers->set('X-Forwarded-Port', '1234');
|
||||||
|
$request->headers->set('X-Forwarded-Proto', 'http');
|
||||||
|
$request->headers->set('Forwarded', 'Evil2');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.1', $request->getClientIp());
|
||||||
|
$this->assertFalse($request->headers->has('X-Forwarded-Host'));
|
||||||
|
$this->assertFalse($request->headers->has('X-Forwarded-Port'));
|
||||||
|
$this->assertFalse($request->headers->has('X-Forwarded-Proto'));
|
||||||
|
$this->assertSame('for="10.0.0.1";host="localhost";proto=http', $request->headers->get('Forwarded'));
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame(self::$globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTrustedForwardedHeader()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(array('10.0.0.1'), -1);
|
||||||
|
$globalState = $this->getGlobalState();
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('Forwarded', 'for="10.0.0.2";host="foo.bar:1234";proto=https');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.2', $request->getClientIp());
|
||||||
|
$this->assertSame('foo.bar:1234', $request->getHttpHost());
|
||||||
|
$this->assertSame('https', $request->getScheme());
|
||||||
|
$this->assertSame(1234, $request->getPort());
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame($globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTrustedXForwardedForHeader()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(array('10.0.0.1'), -1);
|
||||||
|
$globalState = $this->getGlobalState();
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('X-Forwarded-For', '10.0.0.2');
|
||||||
|
$request->headers->set('X-Forwarded-Host', 'foo.bar');
|
||||||
|
$request->headers->set('X-Forwarded-Proto', 'https');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.2', $request->getClientIp());
|
||||||
|
$this->assertSame('foo.bar', $request->getHttpHost());
|
||||||
|
$this->assertSame('https', $request->getScheme());
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame($globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGlobalState()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
Request::getTrustedProxies(),
|
||||||
|
Request::getTrustedHeaderSet(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSubRequestHandlerKernel implements HttpKernelInterface
|
||||||
|
{
|
||||||
|
private $assertCallback;
|
||||||
|
|
||||||
|
public function __construct(\Closure $assertCallback)
|
||||||
|
{
|
||||||
|
$this->assertCallback = $assertCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
|
||||||
|
{
|
||||||
|
$assertCallback = $this->assertCallback;
|
||||||
|
$assertCallback($request, $type, $catch);
|
||||||
|
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
}
|
@ -39,15 +39,25 @@ class TestHttpKernel extends HttpKernel implements ControllerResolverInterface,
|
|||||||
parent::__construct(new EventDispatcher(), $this, null, $this);
|
parent::__construct(new EventDispatcher(), $this, null, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBackendRequest()
|
public function assert(\Closure $callback)
|
||||||
{
|
{
|
||||||
return $this->backendRequest;
|
$trustedConfig = array(Request::getTrustedProxies(), Request::getTrustedHeaderSet());
|
||||||
|
|
||||||
|
list($trustedProxies, $trustedHeaderSet, $backendRequest) = $this->backendRequest;
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$callback($backendRequest);
|
||||||
|
} finally {
|
||||||
|
list($trustedProxies, $trustedHeaderSet) = $trustedConfig;
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false)
|
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false)
|
||||||
{
|
{
|
||||||
$this->catch = $catch;
|
$this->catch = $catch;
|
||||||
$this->backendRequest = $request;
|
$this->backendRequest = array(Request::getTrustedProxies(), Request::getTrustedHeaderSet(), $request);
|
||||||
|
|
||||||
return parent::handle($request, $type, $catch);
|
return parent::handle($request, $type, $catch);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user