Merge branch '2.3' into 2.5

* 2.3:
  adapted previous commit for 2.3
  [Security] Don't send remember cookie for sub request
  [HttpKernel] Fix UriSigner::check when _hash is not at the end of the uri

Conflicts:
	src/Symfony/Component/Security/Http/Tests/RememberMe/ResponseListenerTest.php
This commit is contained in:
Fabien Potencier 2015-01-03 11:26:24 +01:00
commit b1819d4498
4 changed files with 64 additions and 3 deletions

View File

@ -33,5 +33,7 @@ class UriSignerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($signer->check($signer->sign('http://example.com/foo')));
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar')));
$this->assertTrue($signer->sign('http://example.com/foo?foo=bar&bar=foo') === $signer->sign('http://example.com/foo?bar=foo&foo=bar'));
}
}

View File

@ -42,6 +42,15 @@ class UriSigner
*/
public function sign($uri)
{
$url = parse_url($uri);
if (isset($url['query'])) {
parse_str($url['query'], $params);
} else {
$params = array();
}
$uri = $this->buildUrl($url, $params);
return $uri.(false === (strpos($uri, '?')) ? '?' : '&').'_hash='.$this->computeHash($uri);
}
@ -58,15 +67,43 @@ class UriSigner
*/
public function check($uri)
{
if (!preg_match('/^(.*)(?:\?|&)_hash=(.+?)$/', $uri, $matches)) {
$url = parse_url($uri);
if (isset($url['query'])) {
parse_str($url['query'], $params);
} else {
$params = array();
}
if (empty($params['_hash'])) {
return false;
}
return $this->computeHash($matches[1]) === $matches[2];
$hash = urlencode($params['_hash']);
unset($params['_hash']);
return $this->computeHash($this->buildUrl($url, $params)) === $hash;
}
private function computeHash($uri)
{
return urlencode(base64_encode(hash_hmac('sha256', $uri, $this->secret, true)));
}
private function buildUrl(array $url, array $params = array())
{
ksort($params);
$url['query'] = http_build_query($params);
$scheme = isset($url['scheme']) ? $url['scheme'].'://' : '';
$host = isset($url['host']) ? $url['host'] : '';
$port = isset($url['port']) ? ':'.$url['port'] : '';
$user = isset($url['user']) ? $url['user'] : '';
$pass = isset($url['pass']) ? ':'.$url['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = isset($url['path']) ? $url['path'] : '';
$query = isset($url['query']) && $url['query'] ? '?'.$url['query'] : '';
$fragment = isset($url['fragment']) ? '#'.$url['fragment'] : '';
return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
}
}

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Http\RememberMe;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@ -27,6 +28,10 @@ class ResponseListener implements EventSubscriberInterface
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
$response = $event->getResponse();

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Security\Http\Tests\RememberMe;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Http\RememberMe\ResponseListener;
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
use Symfony\Component\HttpFoundation\Request;
@ -34,6 +35,21 @@ class ResponseListenerTest extends \PHPUnit_Framework_TestCase
$listener->onKernelResponse($this->getEvent($request, $response));
}
public function testRememberMeCookieIsNotSendWithResponseForSubRequests()
{
$cookie = new Cookie('rememberme');
$request = $this->getRequest(array(
RememberMeServicesInterface::COOKIE_ATTR_NAME => $cookie,
));
$response = $this->getResponse();
$response->headers->expects($this->never())->method('setCookie');
$listener = new ResponseListener();
$listener->onKernelResponse($this->getEvent($request, $response, HttpKernelInterface::SUB_REQUEST));
}
public function testRememberMeCookieIsNotSendWithResponse()
{
$request = $this->getRequest();
@ -71,13 +87,14 @@ class ResponseListenerTest extends \PHPUnit_Framework_TestCase
return $response;
}
private function getEvent($request, $response)
private function getEvent($request, $response, $type = HttpKernelInterface::MASTER_REQUEST)
{
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\FilterResponseEvent')
->disableOriginalConstructor()
->getMock();
$event->expects($this->any())->method('getRequest')->will($this->returnValue($request));
$event->expects($this->any())->method('getRequestType')->will($this->returnValue($type));
$event->expects($this->any())->method('getResponse')->will($this->returnValue($response));
return $event;