Skip to content

Commit fa8f4f8

Browse files
committed
Forced all fragment uris to be signed, even for ESI
1 parent be3c911 commit fa8f4f8

File tree

4 files changed

+71
-25
lines changed

4 files changed

+71
-25
lines changed

EventListener/FragmentListener.php

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\HttpKernel\EventListener;
1313

1414
use Symfony\Component\HttpFoundation\Request;
15-
use Symfony\Component\HttpFoundation\IpUtils;
1615
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
1716
use Symfony\Component\HttpKernel\KernelEvents;
1817
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
@@ -77,13 +76,6 @@ protected function validateRequest(Request $request)
7776
throw new AccessDeniedHttpException();
7877
}
7978

80-
// does the Request come from a trusted IP?
81-
$trustedIps = array_merge($this->getLocalIpAddresses(), $request->getTrustedProxies());
82-
$remoteAddress = $request->server->get('REMOTE_ADDR');
83-
if (IpUtils::checkIp($remoteAddress, $trustedIps)) {
84-
return;
85-
}
86-
8779
// is the Request signed?
8880
// we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering)
8981
if ($this->signer->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().(null !== ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : ''))) {
@@ -93,6 +85,11 @@ protected function validateRequest(Request $request)
9385
throw new AccessDeniedHttpException();
9486
}
9587

88+
/**
89+
* @deprecated Deprecated since 2.3.19, to be removed in 3.0.
90+
*
91+
* @return string[]
92+
*/
9693
protected function getLocalIpAddresses()
9794
{
9895
return array('127.0.0.1', 'fe80::1', '::1');

Fragment/EsiFragmentRenderer.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpFoundation\Response;
1616
use Symfony\Component\HttpKernel\Controller\ControllerReference;
1717
use Symfony\Component\HttpKernel\HttpCache\Esi;
18+
use Symfony\Component\HttpKernel\UriSigner;
1819

1920
/**
2021
* Implements the ESI rendering strategy.
@@ -25,6 +26,7 @@ class EsiFragmentRenderer extends RoutableFragmentRenderer
2526
{
2627
private $esi;
2728
private $inlineStrategy;
29+
private $signer;
2830

2931
/**
3032
* Constructor.
@@ -34,11 +36,13 @@ class EsiFragmentRenderer extends RoutableFragmentRenderer
3436
*
3537
* @param Esi $esi An Esi instance
3638
* @param FragmentRendererInterface $inlineStrategy The inline strategy to use when ESI is not supported
39+
* @param UriSigner $signer
3740
*/
38-
public function __construct(Esi $esi, FragmentRendererInterface $inlineStrategy)
41+
public function __construct(Esi $esi, FragmentRendererInterface $inlineStrategy, UriSigner $signer = null)
3942
{
4043
$this->esi = $esi;
4144
$this->inlineStrategy = $inlineStrategy;
45+
$this->signer = $signer;
4246
}
4347

4448
/**
@@ -61,12 +65,12 @@ public function render($uri, Request $request, array $options = array())
6165
}
6266

6367
if ($uri instanceof ControllerReference) {
64-
$uri = $this->generateFragmentUri($uri, $request);
68+
$uri = $this->generateSignedFragmentUri($uri, $request);
6569
}
6670

6771
$alt = isset($options['alt']) ? $options['alt'] : null;
6872
if ($alt instanceof ControllerReference) {
69-
$alt = $this->generateFragmentUri($alt, $request);
73+
$alt = $this->generateSignedFragmentUri($alt, $request);
7074
}
7175

7276
$tag = $this->esi->renderIncludeTag($uri, $alt, isset($options['ignore_errors']) ? $options['ignore_errors'] : false, isset($options['comment']) ? $options['comment'] : '');
@@ -81,4 +85,16 @@ public function getName()
8185
{
8286
return 'esi';
8387
}
88+
89+
private function generateSignedFragmentUri($uri, Request $request)
90+
{
91+
if (null === $this->signer) {
92+
throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.');
93+
}
94+
95+
// we need to sign the absolute URI, but want to return the path only.
96+
$fragmentUri = $this->signer->sign($this->generateFragmentUri($uri, $request, true));
97+
98+
return substr($fragmentUri, strlen($request->getSchemeAndHttpHost()));
99+
}
84100
}

Tests/EventListener/FragmentListenerTest.php

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,6 @@ public function testAccessDeniedWithNonSafeMethods()
5454
$listener->onKernelRequest($event);
5555
}
5656

57-
/**
58-
* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
59-
*/
60-
public function testAccessDeniedWithNonLocalIps()
61-
{
62-
$request = Request::create('http://example.com/_fragment', 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1'));
63-
64-
$listener = new FragmentListener(new UriSigner('foo'));
65-
$event = $this->createGetResponseEvent($request);
66-
67-
$listener->onKernelRequest($event);
68-
}
69-
7057
/**
7158
* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
7259
*/

Tests/Fragment/EsiFragmentRendererTest.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer;
1616
use Symfony\Component\HttpKernel\HttpCache\Esi;
1717
use Symfony\Component\HttpFoundation\Request;
18+
use Symfony\Component\HttpKernel\UriSigner;
1819

1920
class EsiFragmentRendererTest extends \PHPUnit_Framework_TestCase
2021
{
@@ -48,7 +49,52 @@ public function testRender()
4849
$this->assertEquals('<esi:include src="/" />', $strategy->render('/', $request)->getContent());
4950
$this->assertEquals("<esi:comment text=\"This is a comment\" />\n<esi:include src=\"/\" />", $strategy->render('/', $request, array('comment' => 'This is a comment'))->getContent());
5051
$this->assertEquals('<esi:include src="/" alt="foo" />', $strategy->render('/', $request, array('alt' => 'foo'))->getContent());
51-
$this->assertEquals('<esi:include src="/_fragment?_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller" alt="/_fragment?_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dalt_controller" />', $strategy->render(new ControllerReference('main_controller', array(), array()), $request, array('alt' => new ControllerReference('alt_controller', array(), array())))->getContent());
52+
}
53+
54+
public function testRenderControllerReference()
55+
{
56+
$signer = new UriSigner('foo');
57+
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(), $signer);
58+
59+
$request = Request::create('/');
60+
$request->setLocale('fr');
61+
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
62+
63+
$reference = new ControllerReference('main_controller', array(), array());
64+
$altReference = new ControllerReference('alt_controller', array(), array());
65+
66+
$this->assertEquals(
67+
'<esi:include src="/_fragment?_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller&_hash=wDaFy1WsZUOWrrMdRMgJ1cOskFo%3D" alt="/_fragment?_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dalt_controller&_hash=56ycnRUlgaremRQVStZsGbVhIv8%3D" />',
68+
$strategy->render($reference, $request, array('alt' => $altReference))->getContent()
69+
);
70+
}
71+
72+
/**
73+
* @expectedException \LogicException
74+
*/
75+
public function testRenderControllerReferenceWithoutSignerThrowsException()
76+
{
77+
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());
78+
79+
$request = Request::create('/');
80+
$request->setLocale('fr');
81+
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
82+
83+
$strategy->render(new ControllerReference('main_controller'), $request);
84+
}
85+
86+
/**
87+
* @expectedException \LogicException
88+
*/
89+
public function testRenderAltControllerReferenceWithoutSignerThrowsException()
90+
{
91+
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());
92+
93+
$request = Request::create('/');
94+
$request->setLocale('fr');
95+
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
96+
97+
$strategy->render('/', $request, array('alt' => new ControllerReference('alt_controller')));
5298
}
5399

54100
private function getInlineStrategy($called = false)

0 commit comments

Comments
 (0)