Skip to content

Commit cac8ca7

Browse files
Seldaekfabpot
authored andcommitted
[Security] [RememberMe] Add support for parallel requests doing remember-me re-authentication
1 parent 120fc17 commit cac8ca7

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

RememberMe/PersistentRememberMeHandler.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpFoundation\RequestStack;
1616
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
1717
use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface;
18+
use Symfony\Component\Security\Core\Authentication\RememberMe\TokenVerifierInterface;
1819
use Symfony\Component\Security\Core\Exception\AuthenticationException;
1920
use Symfony\Component\Security\Core\Exception\CookieTheftException;
2021
use Symfony\Component\Security\Core\User\UserInterface;
@@ -32,13 +33,18 @@
3233
final class PersistentRememberMeHandler extends AbstractRememberMeHandler
3334
{
3435
private $tokenProvider;
36+
private $tokenVerifier;
3537
private $secret;
3638

37-
public function __construct(TokenProviderInterface $tokenProvider, string $secret, UserProviderInterface $userProvider, RequestStack $requestStack, array $options, ?LoggerInterface $logger = null)
39+
public function __construct(TokenProviderInterface $tokenProvider, string $secret, UserProviderInterface $userProvider, RequestStack $requestStack, array $options, ?LoggerInterface $logger = null, ?TokenVerifierInterface $tokenVerifier = null)
3840
{
3941
parent::__construct($userProvider, $requestStack, $options, $logger);
4042

43+
if (!$tokenVerifier && $tokenProvider instanceof TokenVerifierInterface) {
44+
$tokenVerifier = $tokenProvider;
45+
}
4146
$this->tokenProvider = $tokenProvider;
47+
$this->tokenVerifier = $tokenVerifier;
4248
$this->secret = $secret;
4349
}
4450

@@ -66,7 +72,13 @@ public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInte
6672

6773
[$series, $tokenValue] = explode(':', $rememberMeDetails->getValue());
6874
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
69-
if (!hash_equals($persistentToken->getTokenValue(), $tokenValue)) {
75+
76+
if ($this->tokenVerifier) {
77+
$isTokenValid = $this->tokenVerifier->verifyToken($persistentToken, $tokenValue);
78+
} else {
79+
$isTokenValid = hash_equals($persistentToken->getTokenValue(), $tokenValue);
80+
}
81+
if (!$isTokenValid) {
7082
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
7183
}
7284

@@ -78,7 +90,12 @@ public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInte
7890
// if multiple concurrent requests reauthenticate a user we do not want to update the token several times
7991
if ($persistentToken->getLastUsed()->getTimestamp() + 60 < time()) {
8092
$tokenValue = base64_encode(random_bytes(64));
81-
$this->tokenProvider->updateToken($series, $this->generateHash($tokenValue), new \DateTime());
93+
$tokenValueHash = $this->generateHash($tokenValue);
94+
$tokenLastUsed = new \DateTime();
95+
if ($this->tokenVerifier) {
96+
$this->tokenVerifier->updateExistingToken($persistentToken, $tokenValueHash, $tokenLastUsed);
97+
}
98+
$this->tokenProvider->updateToken($series, $tokenValueHash, $tokenLastUsed);
8299
}
83100

84101
$this->createCookie($rememberMeDetails->withValue($tokenValue));

0 commit comments

Comments
 (0)