Merge branch '2.7' into 2.8
* 2.7: fixed tests migrate session after remember me authentication prevent timing attacks in digest auth listener mitigate CSRF timing attack vulnerability fix potential timing attack issue
This commit is contained in:
commit
8a6da3f021
@ -359,7 +359,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$builder = new ContainerBuilder();
|
$builder = new ContainerBuilder();
|
||||||
$builder->register('bar', 'stdClass');
|
$builder->register('bar', 'stdClass');
|
||||||
$builder->register('foo1', 'FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
|
$builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
|
||||||
$builder->setParameter('value', 'bar');
|
$builder->setParameter('value', 'bar');
|
||||||
$this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
|
$this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
|
||||||
}
|
}
|
||||||
@ -368,7 +368,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$builder = new ContainerBuilder();
|
$builder = new ContainerBuilder();
|
||||||
$builder->register('bar', 'stdClass');
|
$builder->register('bar', 'stdClass');
|
||||||
$builder->register('foo1', 'FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
|
$builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
|
||||||
$builder->setParameter('value', 'bar');
|
$builder->setParameter('value', 'bar');
|
||||||
$this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties');
|
$this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties');
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
|
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Util\StringUtils;
|
||||||
|
|
||||||
@trigger_error('The '.__NAMESPACE__.'\DefaultCsrfProvider is deprecated since version 2.4 and will be removed in version 3.0. Use the \Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage class instead.', E_USER_DEPRECATED);
|
@trigger_error('The '.__NAMESPACE__.'\DefaultCsrfProvider is deprecated since version 2.4 and will be removed in version 3.0. Use the \Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage class instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +63,17 @@ class DefaultCsrfProvider implements CsrfProviderInterface
|
|||||||
*/
|
*/
|
||||||
public function isCsrfTokenValid($intention, $token)
|
public function isCsrfTokenValid($intention, $token)
|
||||||
{
|
{
|
||||||
return $token === $this->generateCsrfToken($intention);
|
$expectedToken = $this->generateCsrfToken($intention);
|
||||||
|
|
||||||
|
if (function_exists('hash_equals')) {
|
||||||
|
return hash_equals($expectedToken, $token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (class_exists('Symfony\Component\Security\Core\Util\StringUtils')) {
|
||||||
|
return StringUtils::equals($expectedToken, $token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token === $expectedToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\Security\Http\Firewall;
|
namespace Symfony\Component\Security\Http\Firewall;
|
||||||
|
|
||||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||||
|
use Symfony\Component\Security\Core\Util\StringUtils;
|
||||||
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
|
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||||
@ -99,7 +100,7 @@ class DigestAuthenticationListener implements ListenerInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($serverDigestMd5 !== $digestAuth->getResponse()) {
|
if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) {
|
||||||
if (null !== $this->logger) {
|
if (null !== $this->logger) {
|
||||||
$this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse()));
|
$this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse()));
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
|||||||
use Symfony\Component\Security\Http\SecurityEvents;
|
use Symfony\Component\Security\Http\SecurityEvents;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||||
|
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RememberMeListener implements authentication capabilities via a cookie.
|
* RememberMeListener implements authentication capabilities via a cookie.
|
||||||
@ -56,7 +57,7 @@ class RememberMeListener implements ListenerInterface
|
|||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->dispatcher = $dispatcher;
|
$this->dispatcher = $dispatcher;
|
||||||
$this->catchExceptions = $catchExceptions;
|
$this->catchExceptions = $catchExceptions;
|
||||||
$this->sessionStrategy = $sessionStrategy;
|
$this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +78,7 @@ class RememberMeListener implements ListenerInterface
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$token = $this->authenticationManager->authenticate($token);
|
$token = $this->authenticationManager->authenticate($token);
|
||||||
if (null !== $this->sessionStrategy && $request->hasSession() && $request->getSession()->isStarted()) {
|
if ($request->hasSession() && $request->getSession()->isStarted()) {
|
||||||
$this->sessionStrategy->onAuthentication($request, $token);
|
$this->sessionStrategy->onAuthentication($request, $token);
|
||||||
}
|
}
|
||||||
$this->tokenStorage->setToken($token);
|
$this->tokenStorage->setToken($token);
|
||||||
|
@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
|
|||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
|
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Security\Core\Util\StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concrete implementation of the RememberMeServicesInterface which needs
|
* Concrete implementation of the RememberMeServicesInterface which needs
|
||||||
@ -93,7 +94,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
|
|||||||
list($series, $tokenValue) = $cookieParts;
|
list($series, $tokenValue) = $cookieParts;
|
||||||
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
|
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
|
||||||
|
|
||||||
if ($persistentToken->getTokenValue() !== $tokenValue) {
|
if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) {
|
||||||
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
|
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +246,69 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$listener->handle($event);
|
$listener->handle($event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSessionIsMigratedByDefault()
|
||||||
|
{
|
||||||
|
list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false);
|
||||||
|
|
||||||
|
$tokenStorage
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getToken')
|
||||||
|
->will($this->returnValue(null))
|
||||||
|
;
|
||||||
|
|
||||||
|
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
|
||||||
|
$service
|
||||||
|
->expects($this->once())
|
||||||
|
->method('autoLogin')
|
||||||
|
->will($this->returnValue($token))
|
||||||
|
;
|
||||||
|
|
||||||
|
$tokenStorage
|
||||||
|
->expects($this->once())
|
||||||
|
->method('setToken')
|
||||||
|
->with($this->equalTo($token))
|
||||||
|
;
|
||||||
|
|
||||||
|
$manager
|
||||||
|
->expects($this->once())
|
||||||
|
->method('authenticate')
|
||||||
|
->will($this->returnValue($token))
|
||||||
|
;
|
||||||
|
|
||||||
|
$session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface');
|
||||||
|
$session
|
||||||
|
->expects($this->once())
|
||||||
|
->method('isStarted')
|
||||||
|
->will($this->returnValue(true))
|
||||||
|
;
|
||||||
|
$session
|
||||||
|
->expects($this->once())
|
||||||
|
->method('migrate')
|
||||||
|
;
|
||||||
|
|
||||||
|
$request = $this->getMock('\Symfony\Component\HttpFoundation\Request');
|
||||||
|
$request
|
||||||
|
->expects($this->any())
|
||||||
|
->method('hasSession')
|
||||||
|
->will($this->returnValue(true))
|
||||||
|
;
|
||||||
|
|
||||||
|
$request
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getSession')
|
||||||
|
->will($this->returnValue($session))
|
||||||
|
;
|
||||||
|
|
||||||
|
$event = $this->getGetResponseEvent();
|
||||||
|
$event
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getRequest')
|
||||||
|
->will($this->returnValue($request))
|
||||||
|
;
|
||||||
|
|
||||||
|
$listener->handle($event);
|
||||||
|
}
|
||||||
|
|
||||||
public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent()
|
public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent()
|
||||||
{
|
{
|
||||||
list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true);
|
list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true);
|
||||||
|
Reference in New Issue
Block a user