Skip to content

Commit 8702559

Browse files
committed
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
2 parents bff75a9 + 85a2451 commit 8702559

File tree

4 files changed

+70
-4
lines changed

4 files changed

+70
-4
lines changed

Firewall/DigestAuthenticationListener.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Http\Firewall;
1313

1414
use Symfony\Component\Security\Core\User\UserProviderInterface;
15+
use Symfony\Component\Security\Core\Util\StringUtils;
1516
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
1617
use Psr\Log\LoggerInterface;
1718
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -99,7 +100,7 @@ public function handle(GetResponseEvent $event)
99100
return;
100101
}
101102

102-
if ($serverDigestMd5 !== $digestAuth->getResponse()) {
103+
if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) {
103104
if (null !== $this->logger) {
104105
$this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse()));
105106
}

Firewall/RememberMeListener.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Security\Http\SecurityEvents;
2222
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2323
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
24+
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
2425

2526
/**
2627
* RememberMeListener implements authentication capabilities via a cookie.
@@ -56,7 +57,7 @@ public function __construct(TokenStorageInterface $tokenStorage, RememberMeServi
5657
$this->logger = $logger;
5758
$this->dispatcher = $dispatcher;
5859
$this->catchExceptions = $catchExceptions;
59-
$this->sessionStrategy = $sessionStrategy;
60+
$this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy;
6061
}
6162

6263
/**
@@ -77,7 +78,7 @@ public function handle(GetResponseEvent $event)
7778

7879
try {
7980
$token = $this->authenticationManager->authenticate($token);
80-
if (null !== $this->sessionStrategy && $request->hasSession() && $request->getSession()->isStarted()) {
81+
if ($request->hasSession() && $request->getSession()->isStarted()) {
8182
$this->sessionStrategy->onAuthentication($request, $token);
8283
}
8384
$this->tokenStorage->setToken($token);

RememberMe/PersistentTokenBasedRememberMeServices.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
2222
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
2323
use Psr\Log\LoggerInterface;
24+
use Symfony\Component\Security\Core\Util\StringUtils;
2425

2526
/**
2627
* Concrete implementation of the RememberMeServicesInterface which needs
@@ -93,7 +94,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request)
9394
list($series, $tokenValue) = $cookieParts;
9495
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
9596

96-
if ($persistentToken->getTokenValue() !== $tokenValue) {
97+
if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) {
9798
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
9899
}
99100

Tests/Firewall/RememberMeListenerTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,69 @@ public function testSessionStrategy()
246246
$listener->handle($event);
247247
}
248248

249+
public function testSessionIsMigratedByDefault()
250+
{
251+
list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false);
252+
253+
$tokenStorage
254+
->expects($this->once())
255+
->method('getToken')
256+
->will($this->returnValue(null))
257+
;
258+
259+
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
260+
$service
261+
->expects($this->once())
262+
->method('autoLogin')
263+
->will($this->returnValue($token))
264+
;
265+
266+
$tokenStorage
267+
->expects($this->once())
268+
->method('setToken')
269+
->with($this->equalTo($token))
270+
;
271+
272+
$manager
273+
->expects($this->once())
274+
->method('authenticate')
275+
->will($this->returnValue($token))
276+
;
277+
278+
$session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface');
279+
$session
280+
->expects($this->once())
281+
->method('isStarted')
282+
->will($this->returnValue(true))
283+
;
284+
$session
285+
->expects($this->once())
286+
->method('migrate')
287+
;
288+
289+
$request = $this->getMock('\Symfony\Component\HttpFoundation\Request');
290+
$request
291+
->expects($this->any())
292+
->method('hasSession')
293+
->will($this->returnValue(true))
294+
;
295+
296+
$request
297+
->expects($this->any())
298+
->method('getSession')
299+
->will($this->returnValue($session))
300+
;
301+
302+
$event = $this->getGetResponseEvent();
303+
$event
304+
->expects($this->once())
305+
->method('getRequest')
306+
->will($this->returnValue($request))
307+
;
308+
309+
$listener->handle($event);
310+
}
311+
249312
public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent()
250313
{
251314
list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true);

0 commit comments

Comments
 (0)