Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@

[$class, $username, $value, $last_used] = $row;

return new PersistentToken($class, $username, $series, $value, new \DateTimeImmutable($last_used));
if (method_exists(PersistentToken::class, 'getClass')) {
return new PersistentToken($class, $username, $series, $value, new \DateTimeImmutable($last_used), false);
}

return new PersistentToken($username, $series, $value, new \DateTimeImmutable($last_used));
}

public function deleteTokenBySeries(string $series): void
Expand Down Expand Up @@ -166,7 +170,14 @@
try {
$this->deleteTokenBySeries($tmpSeries);
$lastUsed = \DateTime::createFromInterface($lastUsed);
$this->createNewToken(new PersistentToken(method_exists($token, 'getClass') ? $token->getClass(false) : '', $token->getUserIdentifier(), $tmpSeries, $token->getTokenValue(), $lastUsed));

if (method_exists(PersistentToken::class, 'getClass')) {
$persistentToken = new PersistentToken($token->getClass(false), $token->getUserIdentifier(), $tmpSeries, $token->getTokenValue(), $lastUsed, false);

Check failure on line 175 in src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php:175:122: InvalidArgument: Argument 4 of Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken::__construct expects DateTimeInterface, but string provided (see https://psalm.dev/004)
} else {
$persistentToken = new PersistentToken($token->getUserIdentifier(), $tmpSeries, $token->getTokenValue(), $lastUsed);
}

$this->createNewToken($persistentToken);

$this->conn->commit();
} catch (\Exception $e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ public function testCreateNewToken()
{
$provider = $this->bootstrapProvider();

$token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'));
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'), false);
} else {
$token = new PersistentToken('someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'));
}
$provider->createNewToken($token);

$this->assertEquals($provider->loadTokenBySeries('someSeries'), $token);
Expand All @@ -45,7 +49,12 @@ public function testUpdateToken()
{
$provider = $this->bootstrapProvider();

$token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'));
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'), false);
} else {
$token = new PersistentToken('someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'));
}

$provider->createNewToken($token);
$provider->updateToken('someSeries', 'newValue', $lastUsed = new \DateTime('2014-06-26T22:03:46'));
$token = $provider->loadTokenBySeries('someSeries');
Expand All @@ -57,7 +66,11 @@ public function testUpdateToken()
public function testDeleteToken()
{
$provider = $this->bootstrapProvider();
$token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'));
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'), false);
} else {
$token = new PersistentToken('someUser', 'someSeries', 'tokenValue', new \DateTimeImmutable('2013-01-26T18:23:51'));
}
$provider->createNewToken($token);
$provider->deleteTokenBySeries('someSeries');

Expand All @@ -74,7 +87,11 @@ public function testVerifyOutdatedTokenAfterParallelRequest()
$newValue = 'newValue';

// setup existing token
$token = new PersistentToken('someClass', 'someUser', $series, $oldValue, new \DateTimeImmutable('2013-01-26T18:23:51'));
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken('someClass', 'someUser', $series, $oldValue, new \DateTimeImmutable('2013-01-26T18:23:51'), false);
} else {
$token = new PersistentToken('someUser', $series, $oldValue, new \DateTimeImmutable('2013-01-26T18:23:51'));
}
$provider->createNewToken($token);

// new request comes in requiring remember-me auth, which updates the token
Expand All @@ -99,7 +116,11 @@ public function testVerifyOutdatedTokenAfterParallelRequestFailsAfter60Seconds()
$newValue = 'newValue';

// setup existing token
$token = new PersistentToken('someClass', 'someUser', $series, $oldValue, new \DateTimeImmutable('2013-01-26T18:23:51'));
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken('someClass', 'someUser', $series, $oldValue, new \DateTimeImmutable('2013-01-26T18:23:51'), false);
} else {
$token = new PersistentToken('someUser', $series, $oldValue, new \DateTimeImmutable('2013-01-26T18:23:51'));
}
$provider->createNewToken($token);

// new request comes in requiring remember-me auth, which updates the token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@
$this->tokens[$series]->getClass(false),
$this->tokens[$series]->getUserIdentifier(),
$series,
$tokenValue,

Check failure on line 44 in src/Symfony/Component/Security/Core/Authentication/RememberMe/InMemoryTokenProvider.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/Security/Core/Authentication/RememberMe/InMemoryTokenProvider.php:44:13: InvalidArgument: Argument 4 of Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken::__construct expects DateTimeInterface, but string provided (see https://psalm.dev/004)
$lastUsed
$lastUsed,
false
);
$this->tokens[$series] = $token;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,61 @@
*/
final class PersistentToken implements PersistentTokenInterface
{
private ?string $class = null;
private string $userIdentifier;
private string $series;
private string $tokenValue;
private \DateTimeImmutable $lastUsed;

/**
* @param string $userIdentifier
* @param string $series
* @param string $tokenValue
* @param \DateTimeInterface $lastUsed
*/
public function __construct(
private string $class,
private string $userIdentifier,
private string $series,
#[\SensitiveParameter] private string $tokenValue,
\DateTimeInterface $lastUsed,
$userIdentifier,
$series,
#[\SensitiveParameter] $tokenValue,
#[\SensitiveParameter] $lastUsed,
) {
if (!$class) {
throw new \InvalidArgumentException('$class must not be empty.');
if (\func_num_args() > 4) {
if (\func_num_args() < 6 || func_get_arg(5)) {
trigger_deprecation('symfony/security-core', '7.4', 'Passing a user FQCN to %s() is deprecated. The user class will be removed from the remember-me cookie in 8.0.', __CLASS__, __NAMESPACE__);
}

if (!\is_string($userIdentifier)) {
throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a string, "%s" given.', __METHOD__, get_debug_type($userIdentifier)));
}

$this->class = $userIdentifier;
$userIdentifier = $series;
$series = $tokenValue;
$tokenValue = $lastUsed;

if (\func_num_args() <= 4) {
throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be an instance of "%s", the argument is missing.', __METHOD__, \DateTimeInterface::class));
}

$lastUsed = func_get_arg(4);
}

if (!\is_string($userIdentifier)) {
throw new \TypeError(\sprintf('The $userIdentifier argument passed to "%s()" must be a string, "%s" given.', __METHOD__, get_debug_type($userIdentifier)));
}

if (!\is_string($series)) {
throw new \TypeError(\sprintf('The $series argument passed to "%s()" must be a string, "%s" given.', __METHOD__, get_debug_type($series)));
}

if (!\is_string($tokenValue)) {
throw new \TypeError(\sprintf('The $tokenValue argument passed to "%s()" must be a string, "%s" given.', __METHOD__, get_debug_type($tokenValue)));
}

if (!$lastUsed instanceof \DateTimeInterface) {
throw new \TypeError(\sprintf('The $lastUsed argument passed to "%s()" must be an instance of "%s", "%s" given.', __METHOD__, \DateTimeInterface::class, get_debug_type($lastUsed)));
}

if ('' === $userIdentifier) {
throw new \InvalidArgumentException('$userIdentifier must not be empty.');
}
Expand All @@ -40,6 +83,9 @@ public function __construct(
throw new \InvalidArgumentException('$tokenValue must not be empty.');
}

$this->userIdentifier = $userIdentifier;
$this->series = $series;
$this->tokenValue = $tokenValue;
$this->lastUsed = \DateTimeImmutable::createFromInterface($lastUsed);
}

Expand All @@ -52,7 +98,7 @@ public function getClass(bool $triggerDeprecation = true): string
trigger_deprecation('symfony/security-core', '7.4', 'The "%s()" method is deprecated: the user class will be removed from the remember-me cookie in 8.0.', __METHOD__);
}

return $this->class;
return $this->class ?? '';
}

public function getUserIdentifier(): string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ class CacheTokenVerifierTest extends TestCase
public function testVerifyCurrentToken()
{
$verifier = new CacheTokenVerifier(new ArrayAdapter());
$token = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTimeImmutable());
$token = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTimeImmutable(), false);
$this->assertTrue($verifier->verifyToken($token, 'value'));
}

public function testVerifyFailsInvalidToken()
{
$verifier = new CacheTokenVerifier(new ArrayAdapter());
$token = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTimeImmutable());
$token = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTimeImmutable(), false);
$this->assertFalse($verifier->verifyToken($token, 'wrong-value'));
}

public function testVerifyOutdatedToken()
{
$verifier = new CacheTokenVerifier(new ArrayAdapter());
$outdatedToken = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTimeImmutable());
$newToken = new PersistentToken('class', 'user', 'series1@special:chars=/', 'newvalue', new \DateTimeImmutable());
$outdatedToken = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTimeImmutable(), false);
$newToken = new PersistentToken('class', 'user', 'series1@special:chars=/', 'newvalue', new \DateTimeImmutable(), false);
$verifier->updateExistingToken($outdatedToken, 'newvalue', new \DateTimeImmutable());
$this->assertTrue($verifier->verifyToken($newToken, 'value'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function testCreateNewToken()
{
$provider = new InMemoryTokenProvider();

$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable());
$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable(), false);
$provider->createNewToken($token);

$this->assertSame($provider->loadTokenBySeries('foo'), $token);
Expand All @@ -38,7 +38,7 @@ public function testUpdateToken()
{
$provider = new InMemoryTokenProvider();

$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable());
$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable(), false);
$provider->createNewToken($token);
$provider->updateToken('foo', 'newFoo', $lastUsed = new \DateTime());
$token = $provider->loadTokenBySeries('foo');
Expand All @@ -51,7 +51,7 @@ public function testDeleteToken()
{
$provider = new InMemoryTokenProvider();

$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable());
$token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable(), false);
$provider->createNewToken($token);
$provider->deleteTokenBySeries('foo');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class PersistentTokenTest extends TestCase
public function testConstructor()
{
$lastUsed = new \DateTimeImmutable();
$token = new PersistentToken('fooclass', 'fooname', 'fooseries', 'footokenvalue', $lastUsed);
$token = new PersistentToken('fooname', 'fooseries', 'footokenvalue', $lastUsed);

$this->assertEquals('fooname', $token->getUserIdentifier());
$this->assertEquals('fooseries', $token->getSeries());
Expand All @@ -32,7 +32,7 @@ public function testConstructor()
public function testDateTime()
{
$lastUsed = new \DateTime();
$token = new PersistentToken('fooclass', 'fooname', 'fooseries', 'footokenvalue', $lastUsed);
$token = new PersistentToken('fooname', 'fooseries', 'footokenvalue', $lastUsed);

$this->assertEquals($lastUsed, $token->getLastUsed());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@
$series = random_bytes(66);
$tokenValue = strtr(base64_encode(substr($series, 33)), '+/=', '-_~');
$series = strtr(base64_encode(substr($series, 0, 33)), '+/=', '-_~');
$token = new PersistentToken($user::class, $user->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable());
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken($user::class, $user->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable(), false);

Check failure on line 56 in src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php:56:93: InvalidArgument: Argument 4 of Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken::__construct expects DateTimeInterface, but string provided (see https://psalm.dev/004)
} else {
$token = new PersistentToken($user->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable());
}

$this->tokenProvider->createNewToken($token);
$this->createCookie(RememberMeDetails::fromPersistentToken($token, time() + $this->options['lifetime']));
Expand Down Expand Up @@ -90,16 +94,21 @@

return parent::consumeRememberMeCookie(new RememberMeDetails(
method_exists($token, 'getClass') ? $token->getClass(false) : '',
$token->getUserIdentifier(),

Check failure on line 97 in src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php:97:13: InvalidArgument: Argument 2 of Symfony\Component\Security\Http\RememberMe\RememberMeDetails::__construct expects int, but string provided (see https://psalm.dev/004)
$expires,
$token->getLastUsed()->getTimestamp().':'.$series.':'.$tokenValue.':'.(method_exists($token, 'getClass') ? $token->getClass(false) : '')
$token->getLastUsed()->getTimestamp().':'.$series.':'.$tokenValue.':'.(method_exists($token, 'getClass') ? $token->getClass(false) : ''),
false
));
}

public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInterface $user): void
{
[$lastUsed, $series, $tokenValue, $class] = explode(':', $rememberMeDetails->getValue(), 4);
$token = new PersistentToken($class, $rememberMeDetails->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable('@'.$lastUsed));
if (method_exists(PersistentToken::class, 'getClass')) {
$token = new PersistentToken($class, $rememberMeDetails->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable('@'.$lastUsed), false);

Check failure on line 108 in src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php:108:100: InvalidArgument: Argument 4 of Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken::__construct expects DateTimeInterface, but string provided (see https://psalm.dev/004)
} else {
$token = new PersistentToken($rememberMeDetails->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable('@'.$lastUsed));
}

// if a token was regenerated less than a minute ago, there is no need to regenerate it
// if multiple concurrent requests reauthenticate a user we do not want to update the token several times
Expand Down
Loading
Loading