From 78478b0c563999eb67fdcfc7ea0462c8c452dbde Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 23 May 2023 17:24:39 +0200 Subject: [PATCH 01/32] [7.0] Bump to PHP 8.2 minimum --- composer.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index ba1c62fa..0bc2c140 100644 --- a/composer.json +++ b/composer.json @@ -16,30 +16,30 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/event-dispatcher-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/password-hasher": "^5.4|^6.0|^7.0" + "symfony/password-hasher": "^6.4|^7.0" }, "require-dev": { "psr/container": "^1.1|^2.0", "psr/cache": "^1.0|^2.0|^3.0", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/ldap": "^5.4|^6.0|^7.0", - "symfony/string": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/validator": "^5.4|^6.0|^7.0", + "symfony/cache": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/ldap": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/event-dispatcher": "<5.4", - "symfony/http-foundation": "<5.4", - "symfony/security-guard": "<5.4", - "symfony/ldap": "<5.4", - "symfony/validator": "<5.4" + "symfony/event-dispatcher": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/security-guard": "<6.4", + "symfony/ldap": "<6.4", + "symfony/validator": "<6.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Security\\Core\\": "" }, From bf58846b673cbfeb597360c8c8fb6096afd0f214 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 30 Jun 2023 10:51:15 +0200 Subject: [PATCH 02/32] [7.0] Fix various `@psalm-return` annotations --- Authorization/Voter/VoterInterface.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Authorization/Voter/VoterInterface.php b/Authorization/Voter/VoterInterface.php index 8eea57e7..5255c88e 100644 --- a/Authorization/Voter/VoterInterface.php +++ b/Authorization/Voter/VoterInterface.php @@ -33,9 +33,7 @@ interface VoterInterface * @param mixed $subject The subject to secure * @param array $attributes An array of attributes associated with the method being invoked * - * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED - * - * @psalm-return self::ACCESS_* must be transformed into @return on Symfony 7 + * @return self::ACCESS_* */ - public function vote(TokenInterface $token, mixed $subject, array $attributes); + public function vote(TokenInterface $token, mixed $subject, array $attributes): int; } From 3c7de5601a92acae8f4279d8bc9fdbd1f8fd3091 Mon Sep 17 00:00:00 2001 From: Frank Fiebig Date: Tue, 4 Jul 2023 11:21:50 +0200 Subject: [PATCH 03/32] [Lock] 7.0 remove deprecations in Lock Component --- Authentication/Token/Storage/TokenStorage.php | 6 +- Authorization/AuthorizationChecker.php | 15 +-- Security.php | 11 --- .../Token/Storage/TokenStorageTest.php | 19 ---- Tests/SecurityTest.php | 98 ------------------- User/ChainUserProvider.php | 8 -- User/InMemoryUserProvider.php | 10 +- 7 files changed, 8 insertions(+), 159 deletions(-) delete mode 100644 Tests/SecurityTest.php diff --git a/Authentication/Token/Storage/TokenStorage.php b/Authentication/Token/Storage/TokenStorage.php index 0ec6b1cf..8acc31bc 100644 --- a/Authentication/Token/Storage/TokenStorage.php +++ b/Authentication/Token/Storage/TokenStorage.php @@ -40,12 +40,8 @@ public function getToken(): ?TokenInterface /** * @return void */ - public function setToken(TokenInterface $token = null) + public function setToken(?TokenInterface $token) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/security-core', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } - if ($token) { // ensure any initializer is called $this->getToken(); diff --git a/Authorization/AuthorizationChecker.php b/Authorization/AuthorizationChecker.php index 3827f8b9..c748697c 100644 --- a/Authorization/AuthorizationChecker.php +++ b/Authorization/AuthorizationChecker.php @@ -24,17 +24,10 @@ */ class AuthorizationChecker implements AuthorizationCheckerInterface { - private TokenStorageInterface $tokenStorage; - private AccessDecisionManagerInterface $accessDecisionManager; - - public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, bool $exceptionOnNoToken = false) - { - if ($exceptionOnNoToken) { - throw new \LogicException(sprintf('Argument $exceptionOnNoToken of "%s()" must be set to "false".', __METHOD__)); - } - - $this->tokenStorage = $tokenStorage; - $this->accessDecisionManager = $accessDecisionManager; + public function __construct( + private TokenStorageInterface $tokenStorage, + private AccessDecisionManagerInterface $accessDecisionManager, + ) { } final public function isGranted(mixed $attribute, mixed $subject = null): bool diff --git a/Security.php b/Security.php index 97f1c8ce..bb2576a7 100644 --- a/Security.php +++ b/Security.php @@ -24,19 +24,8 @@ */ class Security implements AuthorizationCheckerInterface { - /** - * @deprecated since Symfony 6.2, use \Symfony\Bundle\SecurityBundle\Security::ACCESS_DENIED_ERROR instead - */ public const ACCESS_DENIED_ERROR = '_security.403_error'; - - /** - * @deprecated since Symfony 6.2, use \Symfony\Bundle\SecurityBundle\Security::AUTHENTICATION_ERROR instead - */ public const AUTHENTICATION_ERROR = '_security.last_error'; - - /** - * @deprecated since Symfony 6.2, use \Symfony\Bundle\SecurityBundle\Security::LAST_USERNAME instead - */ public const LAST_USERNAME = '_security.last_username'; /** diff --git a/Tests/Authentication/Token/Storage/TokenStorageTest.php b/Tests/Authentication/Token/Storage/TokenStorageTest.php index 5b260b50..26d20ae4 100644 --- a/Tests/Authentication/Token/Storage/TokenStorageTest.php +++ b/Tests/Authentication/Token/Storage/TokenStorageTest.php @@ -12,31 +12,12 @@ namespace Symfony\Component\Security\Core\Tests\Authentication\Token\Storage; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\User\InMemoryUser; class TokenStorageTest extends TestCase { - use ExpectDeprecationTrait; - - /** - * @group legacy - */ - public function testGetSetTokenLegacy() - { - $tokenStorage = new TokenStorage(); - $token = new UsernamePasswordToken(new InMemoryUser('username', 'password'), 'provider'); - $tokenStorage->setToken($token); - $this->assertSame($token, $tokenStorage->getToken()); - - $this->expectDeprecation('Since symfony/security-core 6.2: Calling "Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage::setToken()" without any arguments is deprecated, pass null explicitly instead.'); - - $tokenStorage->setToken(); - $this->assertNull($tokenStorage->getToken()); - } - public function testGetSetToken() { $tokenStorage = new TokenStorage(); diff --git a/Tests/SecurityTest.php b/Tests/SecurityTest.php deleted file mode 100644 index 00436895..00000000 --- a/Tests/SecurityTest.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\Security; -use Symfony\Component\Security\Core\User\InMemoryUser; - -/** - * @group legacy - */ -class SecurityTest extends TestCase -{ - public function testGetToken() - { - $token = new UsernamePasswordToken(new InMemoryUser('foo', 'bar'), 'provider'); - $tokenStorage = $this->createMock(TokenStorageInterface::class); - - $tokenStorage->expects($this->once()) - ->method('getToken') - ->willReturn($token); - - $container = $this->createContainer('security.token_storage', $tokenStorage); - - $security = new Security($container); - $this->assertSame($token, $security->getToken()); - } - - /** - * @dataProvider getUserTests - */ - public function testGetUser($userInToken, $expectedUser) - { - $token = $this->createMock(TokenInterface::class); - $token->expects($this->any()) - ->method('getUser') - ->willReturn($userInToken); - $tokenStorage = $this->createMock(TokenStorageInterface::class); - - $tokenStorage->expects($this->once()) - ->method('getToken') - ->willReturn($token); - - $container = $this->createContainer('security.token_storage', $tokenStorage); - - $security = new Security($container); - $this->assertSame($expectedUser, $security->getUser()); - } - - public static function getUserTests() - { - yield [null, null]; - - $user = new InMemoryUser('nice_user', 'foo'); - yield [$user, $user]; - } - - public function testIsGranted() - { - $authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class); - - $authorizationChecker->expects($this->once()) - ->method('isGranted') - ->with('SOME_ATTRIBUTE', 'SOME_SUBJECT') - ->willReturn(true); - - $container = $this->createContainer('security.authorization_checker', $authorizationChecker); - - $security = new Security($container); - $this->assertTrue($security->isGranted('SOME_ATTRIBUTE', 'SOME_SUBJECT')); - } - - private function createContainer($serviceId, $serviceObject) - { - $container = $this->createMock(ContainerInterface::class); - - $container->expects($this->atLeastOnce()) - ->method('get') - ->with($serviceId) - ->willReturn($serviceObject); - - return $container; - } -} diff --git a/User/ChainUserProvider.php b/User/ChainUserProvider.php index 47ebbc1a..045697fb 100644 --- a/User/ChainUserProvider.php +++ b/User/ChainUserProvider.php @@ -46,14 +46,6 @@ public function getProviders(): array return $this->providers; } - /** - * @internal for compatibility with Symfony 5.4 - */ - public function loadUserByUsername(string $username): UserInterface - { - return $this->loadUserByIdentifier($username); - } - public function loadUserByIdentifier(string $identifier): UserInterface { foreach ($this->providers as $provider) { diff --git a/User/InMemoryUserProvider.php b/User/InMemoryUserProvider.php index e0aef90a..13441bc7 100644 --- a/User/InMemoryUserProvider.php +++ b/User/InMemoryUserProvider.php @@ -51,13 +51,11 @@ public function __construct(array $users = []) * Adds a new User to the provider. * * @return void - * - * @throws \LogicException */ public function createUser(UserInterface $user) { if (!$user instanceof InMemoryUser) { - trigger_deprecation('symfony/security-core', '6.3', 'Passing users that are not instance of "%s" to "%s" is deprecated, "%s" given.', InMemoryUser::class, __METHOD__, get_debug_type($user)); + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user))); } $userIdentifier = strtolower($user->getUserIdentifier()); @@ -93,13 +91,11 @@ public function supportsClass(string $class): bool } /** - * Returns the user by given username. - * - * @return InMemoryUser change return type on 7.0 + * Returns the user by given user. * * @throws UserNotFoundException if user whose given username does not exist */ - private function getUser(string $username): UserInterface + private function getUser(string $username): InMemoryUser { if (!isset($this->users[strtolower($username)])) { $ex = new UserNotFoundException(sprintf('Username "%s" does not exist.', $username)); From d888d4a7f9ffff7cb0b969ea4ee7abd00e4b8e4b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 4 Jul 2023 14:50:59 +0200 Subject: [PATCH 04/32] [7.0] Remove remaining deprecated code paths --- CHANGELOG.md | 6 +++++ Security.php | 69 ---------------------------------------------------- 2 files changed, 6 insertions(+), 69 deletions(-) delete mode 100644 Security.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b489556c..663b5999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +7.0 +--- + + * Remove the `Security` class, use `Symfony\Bundle\SecurityBundle\Security` instead + * Require explicit argument when calling `TokenStorage::setToken()` + 6.3 --- diff --git a/Security.php b/Security.php deleted file mode 100644 index bb2576a7..00000000 --- a/Security.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core; - -use Psr\Container\ContainerInterface; -use Symfony\Bundle\SecurityBundle\Security as NewSecurityHelper; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\User\UserInterface; - -/** - * Helper class for commonly-needed security tasks. - * - * @deprecated since Symfony 6.2, use \Symfony\Bundle\SecurityBundle\Security instead - */ -class Security implements AuthorizationCheckerInterface -{ - public const ACCESS_DENIED_ERROR = '_security.403_error'; - public const AUTHENTICATION_ERROR = '_security.last_error'; - public const LAST_USERNAME = '_security.last_username'; - - /** - * @deprecated since Symfony 6.2, use \Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge::MAX_USERNAME_LENGTH instead - */ - public const MAX_USERNAME_LENGTH = 4096; - - private ContainerInterface $container; - - public function __construct(ContainerInterface $container, bool $triggerDeprecation = true) - { - $this->container = $container; - - if ($triggerDeprecation) { - trigger_deprecation('symfony/security-core', '6.2', 'The "%s" class is deprecated, use "%s" instead.', __CLASS__, NewSecurityHelper::class); - } - } - - public function getUser(): ?UserInterface - { - if (!$token = $this->getToken()) { - return null; - } - - return $token->getUser(); - } - - /** - * Checks if the attributes are granted against the current authentication token and optionally supplied subject. - */ - public function isGranted(mixed $attributes, mixed $subject = null): bool - { - return $this->container->get('security.authorization_checker') - ->isGranted($attributes, $subject); - } - - public function getToken(): ?TokenInterface - { - return $this->container->get('security.token_storage')->getToken(); - } -} From e267f60fb5549032781a48ec6c4fb6ce6f73ebdb Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 2 Jul 2023 23:52:21 +0200 Subject: [PATCH 05/32] [Components] Convert to native return types --- .../RememberMe/InMemoryTokenProvider.php | 15 +++----------- .../RememberMe/TokenProviderInterface.php | 16 ++++----------- Authentication/Token/AbstractToken.php | 20 ++++--------------- Authentication/Token/NullToken.php | 20 ++++--------------- Authentication/Token/Storage/TokenStorage.php | 10 ++-------- .../Token/Storage/TokenStorageInterface.php | 4 +--- Authentication/Token/TokenInterface.php | 17 ++++------------ Authorization/Voter/RoleHierarchyVoter.php | 5 +---- Authorization/Voter/RoleVoter.php | 5 +---- Event/AuthenticationEvent.php | 5 +---- Exception/AccessDeniedException.php | 10 ++-------- Exception/AccountStatusException.php | 5 +---- Exception/AuthenticationException.php | 9 ++------- ...ustomUserMessageAccountStatusException.php | 4 +--- ...stomUserMessageAuthenticationException.php | 4 +--- Role/RoleHierarchy.php | 5 +---- User/InMemoryUserChecker.php | 10 ++-------- User/InMemoryUserProvider.php | 4 +--- User/UserCheckerInterface.php | 8 ++------ User/UserInterface.php | 4 +--- User/UserProviderInterface.php | 8 ++------ .../Constraints/UserPasswordValidator.php | 5 +---- 22 files changed, 42 insertions(+), 151 deletions(-) diff --git a/Authentication/RememberMe/InMemoryTokenProvider.php b/Authentication/RememberMe/InMemoryTokenProvider.php index 341883f3..1cc6ded5 100644 --- a/Authentication/RememberMe/InMemoryTokenProvider.php +++ b/Authentication/RememberMe/InMemoryTokenProvider.php @@ -31,10 +31,7 @@ public function loadTokenBySeries(string $series): PersistentTokenInterface return $this->tokens[$series]; } - /** - * @return void - */ - public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed) + public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed): void { if (!isset($this->tokens[$series])) { throw new TokenNotFoundException('No token found.'); @@ -50,18 +47,12 @@ public function updateToken(string $series, #[\SensitiveParameter] string $token $this->tokens[$series] = $token; } - /** - * @return void - */ - public function deleteTokenBySeries(string $series) + public function deleteTokenBySeries(string $series): void { unset($this->tokens[$series]); } - /** - * @return void - */ - public function createNewToken(PersistentTokenInterface $token) + public function createNewToken(PersistentTokenInterface $token): void { $this->tokens[$token->getSeries()] = $token; } diff --git a/Authentication/RememberMe/TokenProviderInterface.php b/Authentication/RememberMe/TokenProviderInterface.php index cf41e0c5..8be82c26 100644 --- a/Authentication/RememberMe/TokenProviderInterface.php +++ b/Authentication/RememberMe/TokenProviderInterface.php @@ -23,32 +23,24 @@ interface TokenProviderInterface /** * Loads the active token for the given series. * - * @return PersistentTokenInterface - * * @throws TokenNotFoundException if the token is not found */ - public function loadTokenBySeries(string $series); + public function loadTokenBySeries(string $series): PersistentTokenInterface; /** * Deletes all tokens belonging to series. - * - * @return void */ - public function deleteTokenBySeries(string $series); + public function deleteTokenBySeries(string $series): void; /** * Updates the token according to this data. * - * @return void - * * @throws TokenNotFoundException if the token is not found */ - public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed); + public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed): void; /** * Creates a new token. - * - * @return void */ - public function createNewToken(PersistentTokenInterface $token); + public function createNewToken(PersistentTokenInterface $token): void; } diff --git a/Authentication/Token/AbstractToken.php b/Authentication/Token/AbstractToken.php index 10cb8f77..36d64766 100644 --- a/Authentication/Token/AbstractToken.php +++ b/Authentication/Token/AbstractToken.php @@ -53,18 +53,12 @@ public function getUser(): ?UserInterface return $this->user; } - /** - * @return void - */ - public function setUser(UserInterface $user) + public function setUser(UserInterface $user): void { $this->user = $user; } - /** - * @return void - */ - public function eraseCredentials() + public function eraseCredentials(): void { if ($this->getUser() instanceof UserInterface) { $this->getUser()->eraseCredentials(); @@ -118,10 +112,7 @@ public function getAttributes(): array return $this->attributes; } - /** - * @return void - */ - public function setAttributes(array $attributes) + public function setAttributes(array $attributes): void { $this->attributes = $attributes; } @@ -140,10 +131,7 @@ public function getAttribute(string $name): mixed return $this->attributes[$name]; } - /** - * @return void - */ - public function setAttribute(string $name, mixed $value) + public function setAttribute(string $name, mixed $value): void { $this->attributes[$name] = $value; } diff --git a/Authentication/Token/NullToken.php b/Authentication/Token/NullToken.php index eabfe17b..9c2e4892 100644 --- a/Authentication/Token/NullToken.php +++ b/Authentication/Token/NullToken.php @@ -33,10 +33,7 @@ public function getUser(): ?UserInterface return null; } - /** - * @return never - */ - public function setUser(UserInterface $user) + public function setUser(UserInterface $user): never { throw new \BadMethodCallException('Cannot set user on a NullToken.'); } @@ -46,10 +43,7 @@ public function getUserIdentifier(): string return ''; } - /** - * @return void - */ - public function eraseCredentials() + public function eraseCredentials(): void { } @@ -58,10 +52,7 @@ public function getAttributes(): array return []; } - /** - * @return never - */ - public function setAttributes(array $attributes) + public function setAttributes(array $attributes): never { throw new \BadMethodCallException('Cannot set attributes of NullToken.'); } @@ -76,10 +67,7 @@ public function getAttribute(string $name): mixed return null; } - /** - * @return never - */ - public function setAttribute(string $name, mixed $value) + public function setAttribute(string $name, mixed $value): never { throw new \BadMethodCallException('Cannot add attribute to NullToken.'); } diff --git a/Authentication/Token/Storage/TokenStorage.php b/Authentication/Token/Storage/TokenStorage.php index 8acc31bc..42234f86 100644 --- a/Authentication/Token/Storage/TokenStorage.php +++ b/Authentication/Token/Storage/TokenStorage.php @@ -37,10 +37,7 @@ public function getToken(): ?TokenInterface return $this->token; } - /** - * @return void - */ - public function setToken(?TokenInterface $token) + public function setToken(?TokenInterface $token): void { if ($token) { // ensure any initializer is called @@ -56,10 +53,7 @@ public function setInitializer(?callable $initializer): void $this->initializer = null === $initializer ? null : $initializer(...); } - /** - * @return void - */ - public function reset() + public function reset(): void { $this->setToken(null); } diff --git a/Authentication/Token/Storage/TokenStorageInterface.php b/Authentication/Token/Storage/TokenStorageInterface.php index 5fdfa4e9..0f611ca4 100644 --- a/Authentication/Token/Storage/TokenStorageInterface.php +++ b/Authentication/Token/Storage/TokenStorageInterface.php @@ -29,8 +29,6 @@ public function getToken(): ?TokenInterface; * Sets the authentication token. * * @param TokenInterface|null $token A TokenInterface token, or null if no further authentication information should be stored - * - * @return void */ - public function setToken(?TokenInterface $token); + public function setToken(?TokenInterface $token): void; } diff --git a/Authentication/Token/TokenInterface.php b/Authentication/Token/TokenInterface.php index d9b80ae1..6d74add1 100644 --- a/Authentication/Token/TokenInterface.php +++ b/Authentication/Token/TokenInterface.php @@ -50,27 +50,21 @@ public function getUser(): ?UserInterface; /** * Sets the authenticated user in the token. * - * @return void - * * @throws \InvalidArgumentException */ - public function setUser(UserInterface $user); + public function setUser(UserInterface $user): void; /** * Removes sensitive information from the token. - * - * @return void */ - public function eraseCredentials(); + public function eraseCredentials(): void; public function getAttributes(): array; /** * @param array $attributes The token attributes - * - * @return void */ - public function setAttributes(array $attributes); + public function setAttributes(array $attributes): void; public function hasAttribute(string $name): bool; @@ -79,10 +73,7 @@ public function hasAttribute(string $name): bool; */ public function getAttribute(string $name): mixed; - /** - * @return void - */ - public function setAttribute(string $name, mixed $value); + public function setAttribute(string $name, mixed $value): void; /** * Returns all the necessary state of the object for serialization purposes. diff --git a/Authorization/Voter/RoleHierarchyVoter.php b/Authorization/Voter/RoleHierarchyVoter.php index c8db1485..3535ca11 100644 --- a/Authorization/Voter/RoleHierarchyVoter.php +++ b/Authorization/Voter/RoleHierarchyVoter.php @@ -31,10 +31,7 @@ public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefi parent::__construct($prefix); } - /** - * @return array - */ - protected function extractRoles(TokenInterface $token) + protected function extractRoles(TokenInterface $token): array { return $this->roleHierarchy->getReachableRoleNames($token->getRoleNames()); } diff --git a/Authorization/Voter/RoleVoter.php b/Authorization/Voter/RoleVoter.php index 70dddcff..dbf50478 100644 --- a/Authorization/Voter/RoleVoter.php +++ b/Authorization/Voter/RoleVoter.php @@ -58,10 +58,7 @@ public function supportsType(string $subjectType): bool return true; } - /** - * @return array - */ - protected function extractRoles(TokenInterface $token) + protected function extractRoles(TokenInterface $token): array { return $token->getRoleNames(); } diff --git a/Event/AuthenticationEvent.php b/Event/AuthenticationEvent.php index 054dd957..6fca50d4 100644 --- a/Event/AuthenticationEvent.php +++ b/Event/AuthenticationEvent.php @@ -28,10 +28,7 @@ public function __construct(TokenInterface $token) $this->authenticationToken = $token; } - /** - * @return TokenInterface - */ - public function getAuthenticationToken() + public function getAuthenticationToken(): TokenInterface { return $this->authenticationToken; } diff --git a/Exception/AccessDeniedException.php b/Exception/AccessDeniedException.php index c95bae03..43df719e 100644 --- a/Exception/AccessDeniedException.php +++ b/Exception/AccessDeniedException.php @@ -34,10 +34,7 @@ public function getAttributes(): array return $this->attributes; } - /** - * @return void - */ - public function setAttributes(array|string $attributes) + public function setAttributes(array|string $attributes): void { $this->attributes = (array) $attributes; } @@ -47,10 +44,7 @@ public function getSubject(): mixed return $this->subject; } - /** - * @return void - */ - public function setSubject(mixed $subject) + public function setSubject(mixed $subject): void { $this->subject = $subject; } diff --git a/Exception/AccountStatusException.php b/Exception/AccountStatusException.php index 5b064929..c0176e08 100644 --- a/Exception/AccountStatusException.php +++ b/Exception/AccountStatusException.php @@ -32,10 +32,7 @@ public function getUser(): ?UserInterface return $this->user; } - /** - * @return void - */ - public function setUser(UserInterface $user) + public function setUser(UserInterface $user): void { $this->user = $user; } diff --git a/Exception/AuthenticationException.php b/Exception/AuthenticationException.php index adec6f87..548d4853 100644 --- a/Exception/AuthenticationException.php +++ b/Exception/AuthenticationException.php @@ -39,10 +39,7 @@ public function getToken(): ?TokenInterface return $this->token; } - /** - * @return void - */ - public function setToken(TokenInterface $token) + public function setToken(TokenInterface $token): void { $this->token = $token; } @@ -90,10 +87,8 @@ public function __unserialize(array $data): void /** * Message key to be used by the translation component. - * - * @return string */ - public function getMessageKey() + public function getMessageKey(): string { return 'An authentication exception occurred.'; } diff --git a/Exception/CustomUserMessageAccountStatusException.php b/Exception/CustomUserMessageAccountStatusException.php index 829a22cd..84b1c00a 100644 --- a/Exception/CustomUserMessageAccountStatusException.php +++ b/Exception/CustomUserMessageAccountStatusException.php @@ -38,10 +38,8 @@ public function __construct(string $message = '', array $messageData = [], int $ * * @param string $messageKey The message or message key * @param array $messageData Data to be passed into the translator - * - * @return void */ - public function setSafeMessage(string $messageKey, array $messageData = []) + public function setSafeMessage(string $messageKey, array $messageData = []): void { $this->messageKey = $messageKey; $this->messageData = $messageData; diff --git a/Exception/CustomUserMessageAuthenticationException.php b/Exception/CustomUserMessageAuthenticationException.php index 40de92d2..88c5338f 100644 --- a/Exception/CustomUserMessageAuthenticationException.php +++ b/Exception/CustomUserMessageAuthenticationException.php @@ -37,10 +37,8 @@ public function __construct(string $message = '', array $messageData = [], int $ * * @param string $messageKey The message or message key * @param array $messageData Data to be passed into the translator - * - * @return void */ - public function setSafeMessage(string $messageKey, array $messageData = []) + public function setSafeMessage(string $messageKey, array $messageData = []): void { $this->messageKey = $messageKey; $this->messageData = $messageData; diff --git a/Role/RoleHierarchy.php b/Role/RoleHierarchy.php index da094d2b..acc1c251 100644 --- a/Role/RoleHierarchy.php +++ b/Role/RoleHierarchy.php @@ -49,10 +49,7 @@ public function getReachableRoleNames(array $roles): array return array_values(array_unique($reachableRoles)); } - /** - * @return void - */ - protected function buildRoleMap() + protected function buildRoleMap(): void { $this->map = []; foreach ($this->hierarchy as $main => $roles) { diff --git a/User/InMemoryUserChecker.php b/User/InMemoryUserChecker.php index a493b00e..61367c2c 100644 --- a/User/InMemoryUserChecker.php +++ b/User/InMemoryUserChecker.php @@ -20,10 +20,7 @@ */ class InMemoryUserChecker implements UserCheckerInterface { - /** - * @return void - */ - public function checkPreAuth(UserInterface $user) + public function checkPreAuth(UserInterface $user): void { if (!$user instanceof InMemoryUser) { return; @@ -36,10 +33,7 @@ public function checkPreAuth(UserInterface $user) } } - /** - * @return void - */ - public function checkPostAuth(UserInterface $user) + public function checkPostAuth(UserInterface $user): void { } } diff --git a/User/InMemoryUserProvider.php b/User/InMemoryUserProvider.php index 13441bc7..ff5f3595 100644 --- a/User/InMemoryUserProvider.php +++ b/User/InMemoryUserProvider.php @@ -49,10 +49,8 @@ public function __construct(array $users = []) /** * Adds a new User to the provider. - * - * @return void */ - public function createUser(UserInterface $user) + public function createUser(UserInterface $user): void { if (!$user instanceof InMemoryUser) { throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user))); diff --git a/User/UserCheckerInterface.php b/User/UserCheckerInterface.php index 91f21c71..480ba7b5 100644 --- a/User/UserCheckerInterface.php +++ b/User/UserCheckerInterface.php @@ -26,18 +26,14 @@ interface UserCheckerInterface /** * Checks the user account before authentication. * - * @return void - * * @throws AccountStatusException */ - public function checkPreAuth(UserInterface $user); + public function checkPreAuth(UserInterface $user): void; /** * Checks the user account after authentication. * - * @return void - * * @throws AccountStatusException */ - public function checkPostAuth(UserInterface $user); + public function checkPostAuth(UserInterface $user): void; } diff --git a/User/UserInterface.php b/User/UserInterface.php index ef22340a..50f8fb0f 100644 --- a/User/UserInterface.php +++ b/User/UserInterface.php @@ -51,10 +51,8 @@ public function getRoles(): array; * * This is important if, at any given point, sensitive information like * the plain-text password is stored on this object. - * - * @return void */ - public function eraseCredentials(); + public function eraseCredentials(): void; /** * Returns the identifier for this user (e.g. username or email address). diff --git a/User/UserProviderInterface.php b/User/UserProviderInterface.php index ec90d413..0502bfd2 100644 --- a/User/UserProviderInterface.php +++ b/User/UserProviderInterface.php @@ -39,19 +39,15 @@ interface UserProviderInterface * object can just be merged into some internal array of users / identity * map. * - * @return UserInterface - * * @throws UnsupportedUserException if the user is not supported * @throws UserNotFoundException if the user is not found */ - public function refreshUser(UserInterface $user); + public function refreshUser(UserInterface $user): UserInterface; /** * Whether this provider supports the given user class. - * - * @return bool */ - public function supportsClass(string $class); + public function supportsClass(string $class): bool; /** * Loads the user for the given user identifier (e.g. username or email). diff --git a/Validator/Constraints/UserPasswordValidator.php b/Validator/Constraints/UserPasswordValidator.php index 41670b27..3d6c7637 100644 --- a/Validator/Constraints/UserPasswordValidator.php +++ b/Validator/Constraints/UserPasswordValidator.php @@ -31,10 +31,7 @@ public function __construct(TokenStorageInterface $tokenStorage, PasswordHasherF $this->hasherFactory = $hasherFactory; } - /** - * @return void - */ - public function validate(mixed $password, Constraint $constraint) + public function validate(mixed $password, Constraint $constraint): void { if (!$constraint instanceof UserPassword) { throw new UnexpectedTypeException($constraint, UserPassword::class); From ade1448d6adf5b3987614e797685ec43e0f113bd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 5 Jul 2023 17:25:57 +0200 Subject: [PATCH 06/32] [Security] Revert native return types on TokenProviderInterface --- .../RememberMe/TokenProviderInterface.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Authentication/RememberMe/TokenProviderInterface.php b/Authentication/RememberMe/TokenProviderInterface.php index 8be82c26..cf41e0c5 100644 --- a/Authentication/RememberMe/TokenProviderInterface.php +++ b/Authentication/RememberMe/TokenProviderInterface.php @@ -23,24 +23,32 @@ interface TokenProviderInterface /** * Loads the active token for the given series. * + * @return PersistentTokenInterface + * * @throws TokenNotFoundException if the token is not found */ - public function loadTokenBySeries(string $series): PersistentTokenInterface; + public function loadTokenBySeries(string $series); /** * Deletes all tokens belonging to series. + * + * @return void */ - public function deleteTokenBySeries(string $series): void; + public function deleteTokenBySeries(string $series); /** * Updates the token according to this data. * + * @return void + * * @throws TokenNotFoundException if the token is not found */ - public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed): void; + public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed); /** * Creates a new token. + * + * @return void */ - public function createNewToken(PersistentTokenInterface $token): void; + public function createNewToken(PersistentTokenInterface $token); } From 9e130f3a4eddc81e81b860c6f9601feff211553b Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 24 Jul 2023 16:03:38 +0200 Subject: [PATCH 07/32] [Validator] Remove Doctrine annotations support --- Validator/Constraints/UserPassword.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Validator/Constraints/UserPassword.php b/Validator/Constraints/UserPassword.php index b1a340c8..e7b7cd26 100644 --- a/Validator/Constraints/UserPassword.php +++ b/Validator/Constraints/UserPassword.php @@ -13,10 +13,6 @@ use Symfony\Component\Validator\Constraint; -/** - * @Annotation - * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) - */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class UserPassword extends Constraint { From ee0949879d3b05b61c30e710e03f2354ccdd8a91 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 21 Jul 2023 15:36:26 +0200 Subject: [PATCH 08/32] Add types to public and protected properties --- Role/RoleHierarchy.php | 5 +++-- Validator/Constraints/UserPassword.php | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Role/RoleHierarchy.php b/Role/RoleHierarchy.php index acc1c251..15c5750d 100644 --- a/Role/RoleHierarchy.php +++ b/Role/RoleHierarchy.php @@ -18,9 +18,10 @@ */ class RoleHierarchy implements RoleHierarchyInterface { - private array $hierarchy; /** @var array> */ - protected $map; + protected array $map; + + private array $hierarchy; /** * @param array> $hierarchy diff --git a/Validator/Constraints/UserPassword.php b/Validator/Constraints/UserPassword.php index e7b7cd26..6f4024c0 100644 --- a/Validator/Constraints/UserPassword.php +++ b/Validator/Constraints/UserPassword.php @@ -22,8 +22,8 @@ class UserPassword extends Constraint self::INVALID_PASSWORD_ERROR => 'INVALID_PASSWORD_ERROR', ]; - public $message = 'This value should be the user\'s current password.'; - public $service = 'security.validator.user_password'; + public string $message = 'This value should be the user\'s current password.'; + public string $service = 'security.validator.user_password'; public function __construct(array $options = null, string $message = null, string $service = null, array $groups = null, mixed $payload = null) { From 10a13dd18d5cff64ff90e8c0afad9f9fa4895f48 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 5 Aug 2023 11:18:22 +0200 Subject: [PATCH 09/32] Add 2 recently missing return types --- Authentication/RememberMe/InMemoryTokenProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Authentication/RememberMe/InMemoryTokenProvider.php b/Authentication/RememberMe/InMemoryTokenProvider.php index 0aef6a2c..5a1f5865 100644 --- a/Authentication/RememberMe/InMemoryTokenProvider.php +++ b/Authentication/RememberMe/InMemoryTokenProvider.php @@ -31,7 +31,7 @@ public function loadTokenBySeries(string $series): PersistentTokenInterface return $this->tokens[$series]; } - public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed) + public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed): void { if (!isset($this->tokens[$series])) { throw new TokenNotFoundException('No token found.'); From 0aa85ec9a269942b2552ca080e9728d3cc140a85 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Sun, 27 Aug 2023 15:53:12 +0200 Subject: [PATCH 10/32] Remove getUsername methods in tests --- Tests/Authentication/AuthenticationTrustResolverTest.php | 4 ---- Tests/Authentication/Token/Fixtures/CustomUser.php | 5 ----- 2 files changed, 9 deletions(-) diff --git a/Tests/Authentication/AuthenticationTrustResolverTest.php b/Tests/Authentication/AuthenticationTrustResolverTest.php index 02149ce3..3e0a8d50 100644 --- a/Tests/Authentication/AuthenticationTrustResolverTest.php +++ b/Tests/Authentication/AuthenticationTrustResolverTest.php @@ -115,10 +115,6 @@ public function setUser($user): void { } - public function getUsername(): string - { - } - public function getUserIdentifier(): string { } diff --git a/Tests/Authentication/Token/Fixtures/CustomUser.php b/Tests/Authentication/Token/Fixtures/CustomUser.php index 52fea7a3..99302032 100644 --- a/Tests/Authentication/Token/Fixtures/CustomUser.php +++ b/Tests/Authentication/Token/Fixtures/CustomUser.php @@ -17,11 +17,6 @@ public function __construct(string $username, array $roles) $this->roles = $roles; } - public function getUsername(): string - { - return $this->username; - } - public function getUserIdentifier(): string { return $this->username; From e0b8cbdcb2dea1a8a42a97414c74d759f6b7670b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 18 Oct 2023 14:57:55 +0200 Subject: [PATCH 11/32] [7.0] Cleanup legacy code paths --- Authentication/RememberMe/TokenProviderInterface.php | 4 +--- CHANGELOG.md | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Authentication/RememberMe/TokenProviderInterface.php b/Authentication/RememberMe/TokenProviderInterface.php index d2f0c8cb..bfe49015 100644 --- a/Authentication/RememberMe/TokenProviderInterface.php +++ b/Authentication/RememberMe/TokenProviderInterface.php @@ -39,13 +39,11 @@ public function deleteTokenBySeries(string $series); /** * Updates the token according to this data. * - * @param \DateTimeInterface $lastUsed Accepting only DateTime is deprecated since Symfony 6.4 - * * @return void * * @throws TokenNotFoundException if the token is not found */ - public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTime $lastUsed); + public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed); /** * Creates a new token. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a451ccc..47b4a210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * Remove the `Security` class, use `Symfony\Bundle\SecurityBundle\Security` instead * Require explicit argument when calling `TokenStorage::setToken()` + * Change argument `$lastUsed` of `TokenProviderInterface::updateToken()` to accept `DateTimeInterface` 6.4 --- From 7363e581fad8b0037ade4b0c803af7d11fd5066f Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 20 Nov 2023 22:20:58 +0100 Subject: [PATCH 12/32] [Security] remove conflict with symfony/security-guard --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 0bc2c140..51323362 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,6 @@ "conflict": { "symfony/event-dispatcher": "<6.4", "symfony/http-foundation": "<6.4", - "symfony/security-guard": "<6.4", "symfony/ldap": "<6.4", "symfony/validator": "<6.4" }, From 2ba040de8e6d93e07edc7307dc75b42e06137405 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 30 Nov 2023 12:04:23 +0100 Subject: [PATCH 13/32] Update sponsors of Symfony 7.0: Shopware, Sulu and Les-Tilleuls + Sensiolabs for Messenger & SymfonyCasts for Security components --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48ffb0e5..5bb87c3c 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ if (!$accessDecisionManager->decide($token, ['ROLE_ADMIN'])) { Sponsor ------- -The Security component for Symfony 6.4 is [backed][1] by [SymfonyCasts][2]. +The Security component for Symfony 7.0 is [backed][1] by [SymfonyCasts][2]. Learn Symfony faster by watching real projects being built and actively coding along with them. SymfonyCasts bridges that learning gap, bringing you video From aedbe2a4fe792f6a44b965b9f0e461e81ac51d25 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 8 Dec 2023 15:23:08 +0100 Subject: [PATCH 14/32] Fx README files --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5bb87c3c..b7068290 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ so called user providers that hold the users credentials. Getting Started --------------- -``` -$ composer require symfony/security-core +```bash +composer require symfony/security-core ``` ```php From bb53c52b1063ac9bc850ff58d6b58b543766cdc9 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 14 Dec 2023 11:03:37 +0100 Subject: [PATCH 15/32] Set `strict` parameter of `in_array` to true where possible --- Tests/Authorization/TraceableAccessDecisionManagerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Authorization/TraceableAccessDecisionManagerTest.php b/Tests/Authorization/TraceableAccessDecisionManagerTest.php index cefe8dbc..c14ee1fa 100644 --- a/Tests/Authorization/TraceableAccessDecisionManagerTest.php +++ b/Tests/Authorization/TraceableAccessDecisionManagerTest.php @@ -197,7 +197,7 @@ public function testAccessDecisionManagerCalledByVoter() ->expects($this->any()) ->method('vote') ->willReturnCallback(function (TokenInterface $token, $subject, array $attributes) use ($sut, $voter1) { - $vote = \in_array('attr1', $attributes) ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_ABSTAIN; + $vote = \in_array('attr1', $attributes, true) ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_ABSTAIN; $sut->addVoterVote($voter1, $attributes, $vote); return $vote; @@ -207,7 +207,7 @@ public function testAccessDecisionManagerCalledByVoter() ->expects($this->any()) ->method('vote') ->willReturnCallback(function (TokenInterface $token, $subject, array $attributes) use ($sut, $voter2) { - if (\in_array('attr2', $attributes)) { + if (\in_array('attr2', $attributes, true)) { $vote = null == $subject ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_DENIED; } else { $vote = VoterInterface::ACCESS_ABSTAIN; @@ -222,7 +222,7 @@ public function testAccessDecisionManagerCalledByVoter() ->expects($this->any()) ->method('vote') ->willReturnCallback(function (TokenInterface $token, $subject, array $attributes) use ($sut, $voter3) { - if (\in_array('attr2', $attributes) && $subject) { + if (\in_array('attr2', $attributes, true) && $subject) { $vote = $sut->decide($token, $attributes) ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_DENIED; } else { $vote = VoterInterface::ACCESS_ABSTAIN; From afa665fc5657918fbbec885b2ffdcc96e28c1333 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 18 Dec 2023 08:46:12 +0100 Subject: [PATCH 16/32] Code updates --- Authorization/Voter/RoleVoter.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Authorization/Voter/RoleVoter.php b/Authorization/Voter/RoleVoter.php index dbf50478..76de3a32 100644 --- a/Authorization/Voter/RoleVoter.php +++ b/Authorization/Voter/RoleVoter.php @@ -38,10 +38,8 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes): } $result = VoterInterface::ACCESS_DENIED; - foreach ($roles as $role) { - if ($attribute === $role) { - return VoterInterface::ACCESS_GRANTED; - } + if (\in_array($attribute, $roles, true)) { + return VoterInterface::ACCESS_GRANTED; } } From e4f316c4abe3d05aab878086b82162e739b2935a Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 1 Nov 2023 09:14:07 +0100 Subject: [PATCH 17/32] [Tests] Streamline --- .../RememberMe/InMemoryTokenProviderTest.php | 7 ++++--- Tests/Authorization/Voter/VoterTest.php | 3 +-- Tests/User/ChainUserProviderTest.php | 8 ++++++-- Tests/User/InMemoryUserCheckerTest.php | 3 +-- Tests/User/InMemoryUserProviderTest.php | 7 ++++--- .../Constraints/UserPasswordValidatorTestCase.php | 3 ++- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Tests/Authentication/RememberMe/InMemoryTokenProviderTest.php b/Tests/Authentication/RememberMe/InMemoryTokenProviderTest.php index 45fd046a..6fc2ab15 100644 --- a/Tests/Authentication/RememberMe/InMemoryTokenProviderTest.php +++ b/Tests/Authentication/RememberMe/InMemoryTokenProviderTest.php @@ -31,8 +31,7 @@ public function testCreateNewToken() public function testLoadTokenBySeriesThrowsNotFoundException() { $this->expectException(TokenNotFoundException::class); - $provider = new InMemoryTokenProvider(); - $provider->loadTokenBySeries('foo'); + (new InMemoryTokenProvider())->loadTokenBySeries('foo'); } public function testUpdateToken() @@ -50,12 +49,14 @@ public function testUpdateToken() public function testDeleteToken() { - $this->expectException(TokenNotFoundException::class); $provider = new InMemoryTokenProvider(); $token = new PersistentToken('foo', 'foo', 'foo', 'foo', new \DateTimeImmutable()); $provider->createNewToken($token); $provider->deleteTokenBySeries('foo'); + + $this->expectException(TokenNotFoundException::class); + $provider->loadTokenBySeries('foo'); } } diff --git a/Tests/Authorization/Voter/VoterTest.php b/Tests/Authorization/Voter/VoterTest.php index 80c3f4a0..5636340e 100644 --- a/Tests/Authorization/Voter/VoterTest.php +++ b/Tests/Authorization/Voter/VoterTest.php @@ -67,8 +67,7 @@ public function testVoteWithTypeError() { $this->expectException(\TypeError::class); $this->expectExceptionMessage('Should error'); - $voter = new TypeErrorVoterTest_Voter(); - $voter->vote($this->token, new \stdClass(), ['EDIT']); + (new TypeErrorVoterTest_Voter())->vote($this->token, new \stdClass(), ['EDIT']); } } diff --git a/Tests/User/ChainUserProviderTest.php b/Tests/User/ChainUserProviderTest.php index 09227752..90111561 100644 --- a/Tests/User/ChainUserProviderTest.php +++ b/Tests/User/ChainUserProviderTest.php @@ -47,7 +47,6 @@ public function testLoadUserByIdentifier() public function testLoadUserByIdentifierThrowsUserNotFoundException() { - $this->expectException(UserNotFoundException::class); $provider1 = $this->createMock(InMemoryUserProvider::class); $provider1 ->expects($this->once()) @@ -65,6 +64,9 @@ public function testLoadUserByIdentifierThrowsUserNotFoundException() ; $provider = new ChainUserProvider([$provider1, $provider2]); + + $this->expectException(UserNotFoundException::class); + $provider->loadUserByIdentifier('foo'); } @@ -141,7 +143,6 @@ public function testRefreshUserAgain() public function testRefreshUserThrowsUnsupportedUserException() { - $this->expectException(UnsupportedUserException::class); $provider1 = $this->createMock(InMemoryUserProvider::class); $provider1 ->expects($this->once()) @@ -169,6 +170,9 @@ public function testRefreshUserThrowsUnsupportedUserException() ; $provider = new ChainUserProvider([$provider1, $provider2]); + + $this->expectException(UnsupportedUserException::class); + $provider->refreshUser($this->createMock(UserInterface::class)); } diff --git a/Tests/User/InMemoryUserCheckerTest.php b/Tests/User/InMemoryUserCheckerTest.php index 8b01e5f0..25107723 100644 --- a/Tests/User/InMemoryUserCheckerTest.php +++ b/Tests/User/InMemoryUserCheckerTest.php @@ -35,7 +35,6 @@ public function testCheckPostAuthPass() public function testCheckPreAuthDisabled() { $this->expectException(DisabledException::class); - $checker = new InMemoryUserChecker(); - $checker->checkPreAuth(new InMemoryUser('John', 'password', [], false)); + (new InMemoryUserChecker())->checkPreAuth(new InMemoryUser('John', 'password', [], false)); } } diff --git a/Tests/User/InMemoryUserProviderTest.php b/Tests/User/InMemoryUserProviderTest.php index 1a843e4e..98afb3b4 100644 --- a/Tests/User/InMemoryUserProviderTest.php +++ b/Tests/User/InMemoryUserProviderTest.php @@ -62,16 +62,17 @@ public function testCreateUser() public function testCreateUserAlreadyExist() { - $this->expectException(\LogicException::class); $provider = new InMemoryUserProvider(); $provider->createUser(new InMemoryUser('fabien', 'foo')); + + $this->expectException(\LogicException::class); + $provider->createUser(new InMemoryUser('fabien', 'foo')); } public function testLoadUserByIdentifierDoesNotExist() { $this->expectException(UserNotFoundException::class); - $provider = new InMemoryUserProvider(); - $provider->loadUserByIdentifier('fabien'); + (new InMemoryUserProvider())->loadUserByIdentifier('fabien'); } } diff --git a/Tests/Validator/Constraints/UserPasswordValidatorTestCase.php b/Tests/Validator/Constraints/UserPasswordValidatorTestCase.php index ccf556a0..c78f6b5f 100644 --- a/Tests/Validator/Constraints/UserPasswordValidatorTestCase.php +++ b/Tests/Validator/Constraints/UserPasswordValidatorTestCase.php @@ -113,13 +113,14 @@ public static function emptyPasswordData() public function testUserIsNotValid() { - $this->expectException(ConstraintDefinitionException::class); $user = new \stdClass(); $this->tokenStorage = $this->createTokenStorage($user); $this->validator = $this->createValidator(); $this->validator->initialize($this->context); + $this->expectException(ConstraintDefinitionException::class); + $this->validator->validate('secret', new UserPassword()); } From 891b5bdad89d7331747e3501c0dee07000f6906b Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Tue, 2 Jan 2024 15:49:33 +0100 Subject: [PATCH 18/32] CS: trailing commas --- User/OidcUser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/User/OidcUser.php b/User/OidcUser.php index 490a3ec2..bcce363f 100644 --- a/User/OidcUser.php +++ b/User/OidcUser.php @@ -45,7 +45,7 @@ public function __construct( private ?\DateTimeInterface $updatedAt = null, // Additional Claims (https://openid.net/specs/openid-connect-core-1_0.html#AdditionalClaims) - ...$additionalClaims + ...$additionalClaims, ) { if (null === $sub || '' === $sub) { throw new \InvalidArgumentException('The "sub" claim cannot be empty.'); From 918585786b2ebff1d325a1872a12c0d1e3589f90 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 11 Jan 2024 11:01:49 +0100 Subject: [PATCH 19/32] do not mock the RequestStack class --- .../Storage/UsageTrackingTokenStorageTest.php | 37 ++++++------------- composer.json | 2 + 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/Tests/Authentication/Token/Storage/UsageTrackingTokenStorageTest.php b/Tests/Authentication/Token/Storage/UsageTrackingTokenStorageTest.php index 3d7c7904..72e1665a 100644 --- a/Tests/Authentication/Token/Storage/UsageTrackingTokenStorageTest.php +++ b/Tests/Authentication/Token/Storage/UsageTrackingTokenStorageTest.php @@ -13,9 +13,10 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Security\Core\Authentication\Token\NullToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\Storage\UsageTrackingTokenStorage; @@ -25,28 +26,14 @@ class UsageTrackingTokenStorageTest extends TestCase { public function testGetSetToken() { - $sessionAccess = 0; - $sessionLocator = new class(['request_stack' => function () use (&$sessionAccess) { - $session = $this->createMock(SessionInterface::class); - - $request = new Request(); - $request->setSession($session); - $requestStack = $this->getMockBuilder(RequestStack::class)->onlyMethods(['getSession'])->getMock(); - $requestStack->push($request); - $requestStack->expects($this->any())->method('getSession')->willReturnCallback(function () use ($session, &$sessionAccess) { - ++$sessionAccess; - - $session->expects($this->once()) - ->method('getMetadataBag'); - - return $session; - }); - - return $requestStack; - }]) implements ContainerInterface { - use ServiceLocatorTrait; - }; $tokenStorage = new TokenStorage(); + $session = new Session(); + $request = new Request(); + $request->setSession($session); + $requestStack = new RequestStack(); + $requestStack->push($request); + $sessionLocator = new ContainerBuilder(); + $sessionLocator->set('request_stack', $requestStack); $trackingStorage = new UsageTrackingTokenStorage($tokenStorage, $sessionLocator); $this->assertNull($trackingStorage->getToken()); @@ -55,15 +42,15 @@ public function testGetSetToken() $trackingStorage->setToken($token); $this->assertSame($token, $trackingStorage->getToken()); $this->assertSame($token, $tokenStorage->getToken()); - $this->assertSame(0, $sessionAccess); + $this->assertSame(0, $session->getUsageIndex()); $trackingStorage->enableUsageTracking(); $this->assertSame($token, $trackingStorage->getToken()); - $this->assertSame(1, $sessionAccess); + $this->assertSame(1, $session->getUsageIndex()); $trackingStorage->disableUsageTracking(); $this->assertSame($token, $trackingStorage->getToken()); - $this->assertSame(1, $sessionAccess); + $this->assertSame(1, $session->getUsageIndex()); } public function testWithoutMainRequest() diff --git a/composer.json b/composer.json index bb6c4d50..a923768b 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ "psr/container": "^1.1|^2.0", "psr/cache": "^1.0|^2.0|^3.0", "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", "symfony/expression-language": "^6.4|^7.0", "symfony/http-foundation": "^6.4|^7.0", @@ -35,6 +36,7 @@ "psr/log": "^1|^2|^3" }, "conflict": { + "symfony/dependency-injection": "<6.4", "symfony/event-dispatcher": "<6.4", "symfony/http-foundation": "<6.4", "symfony/ldap": "<6.4", From 220301f8a7cdb0b11873aa242644a6f98f893fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sun, 31 Mar 2024 15:15:18 +0200 Subject: [PATCH 20/32] Remove unnecessary empty usages --- Authentication/RememberMe/PersistentToken.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Authentication/RememberMe/PersistentToken.php b/Authentication/RememberMe/PersistentToken.php index f473ccb7..c1f1e1a7 100644 --- a/Authentication/RememberMe/PersistentToken.php +++ b/Authentication/RememberMe/PersistentToken.php @@ -26,16 +26,16 @@ final class PersistentToken implements PersistentTokenInterface public function __construct(string $class, string $userIdentifier, string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed) { - if (empty($class)) { + if (!$class) { throw new \InvalidArgumentException('$class must not be empty.'); } if ('' === $userIdentifier) { throw new \InvalidArgumentException('$userIdentifier must not be empty.'); } - if (empty($series)) { + if (!$series) { throw new \InvalidArgumentException('$series must not be empty.'); } - if (empty($tokenValue)) { + if (!$tokenValue) { throw new \InvalidArgumentException('$tokenValue must not be empty.'); } From 74717b37d89469ce9206ea830e3effd2c1e75afe Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 2 May 2024 13:36:26 +0200 Subject: [PATCH 21/32] [Security] SymfonyCasts is backing the security components for v7.1, thanks to them! \o/ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7068290..fc50dcc6 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ if (!$accessDecisionManager->decide($token, ['ROLE_ADMIN'])) { Sponsor ------- -The Security component for Symfony 7.0 is [backed][1] by [SymfonyCasts][2]. +The Security component for Symfony 7.1 is [backed][1] by [SymfonyCasts][2]. Learn Symfony faster by watching real projects being built and actively coding along with them. SymfonyCasts bridges that learning gap, bringing you video From 74ebf9b36c60ec3881c7dcdd3d0ee17cfca0a84b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 May 2024 11:22:57 +0200 Subject: [PATCH 22/32] [Security] Deprecate argument $secret of RememberMeToken and RememberMeAuthenticator --- Authentication/Token/RememberMeToken.php | 20 +++++++++++-------- CHANGELOG.md | 4 ++++ .../AuthenticationTrustResolverTest.php | 2 +- .../Token/RememberMeTokenTest.php | 18 ++++++++--------- .../Authorization/ExpressionLanguageTest.php | 2 +- .../Voter/AuthenticatedVoterTest.php | 2 +- composer.json | 1 + 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Authentication/Token/RememberMeToken.php b/Authentication/Token/RememberMeToken.php index ad218f1b..643c40d4 100644 --- a/Authentication/Token/RememberMeToken.php +++ b/Authentication/Token/RememberMeToken.php @@ -21,20 +21,19 @@ */ class RememberMeToken extends AbstractToken { - private string $secret; + private ?string $secret = null; private string $firewallName; /** - * @param string $secret A secret used to make sure the token is created by the app and not by a malicious client - * * @throws \InvalidArgumentException */ - public function __construct(UserInterface $user, string $firewallName, #[\SensitiveParameter] string $secret) + public function __construct(UserInterface $user, string $firewallName) { parent::__construct($user->getRoles()); - if (!$secret) { - throw new InvalidArgumentException('A non-empty secret is required.'); + if (\func_num_args() > 2) { + trigger_deprecation('symfony/security-core', '7.2', 'The "$secret" argument of "%s()" is deprecated.', __METHOD__); + $this->secret = func_get_arg(2); } if (!$firewallName) { @@ -42,7 +41,6 @@ public function __construct(UserInterface $user, string $firewallName, #[\Sensit } $this->firewallName = $firewallName; - $this->secret = $secret; $this->setUser($user); } @@ -52,13 +50,19 @@ public function getFirewallName(): string return $this->firewallName; } + /** + * @deprecated since Symfony 7.2 + */ public function getSecret(): string { - return $this->secret; + trigger_deprecation('symfony/security-core', '7.2', 'The "%s()" method is deprecated.', __METHOD__); + + return $this->secret ??= base64_encode(random_bytes(8)); } public function __serialize(): array { + // $this->firewallName should be kept at index 1 for compatibility with payloads generated before Symfony 8 return [$this->secret, $this->firewallName, parent::__serialize()]; } diff --git a/CHANGELOG.md b/CHANGELOG.md index 47b4a210..208f0d48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +7.2 +--- + + * Deprecate argument `$secret` of `RememberMeToken` 7.0 --- diff --git a/Tests/Authentication/AuthenticationTrustResolverTest.php b/Tests/Authentication/AuthenticationTrustResolverTest.php index 3e0a8d50..fc559983 100644 --- a/Tests/Authentication/AuthenticationTrustResolverTest.php +++ b/Tests/Authentication/AuthenticationTrustResolverTest.php @@ -72,7 +72,7 @@ protected function getRememberMeToken() { $user = new InMemoryUser('wouter', '', ['ROLE_USER']); - return new RememberMeToken($user, 'main', 'secret'); + return new RememberMeToken($user, 'main'); } } diff --git a/Tests/Authentication/Token/RememberMeTokenTest.php b/Tests/Authentication/Token/RememberMeTokenTest.php index a63d481b..b0cdbaf1 100644 --- a/Tests/Authentication/Token/RememberMeTokenTest.php +++ b/Tests/Authentication/Token/RememberMeTokenTest.php @@ -20,22 +20,22 @@ class RememberMeTokenTest extends TestCase public function testConstructor() { $user = $this->getUser(); - $token = new RememberMeToken($user, 'fookey', 'foo'); + $token = new RememberMeToken($user, 'fookey'); $this->assertEquals('fookey', $token->getFirewallName()); - $this->assertEquals('foo', $token->getSecret()); $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); $this->assertSame($user, $token->getUser()); } - public function testConstructorSecretCannotBeEmptyString() + /** + * @group legacy + */ + public function testSecret() { - $this->expectException(\InvalidArgumentException::class); - new RememberMeToken( - $this->getUser(), - '', - '' - ); + $user = $this->getUser(); + $token = new RememberMeToken($user, 'fookey', 'foo'); + + $this->assertEquals('foo', $token->getSecret()); } protected function getUser($roles = ['ROLE_FOO']) diff --git a/Tests/Authorization/ExpressionLanguageTest.php b/Tests/Authorization/ExpressionLanguageTest.php index 8cc4810a..1a4db41e 100644 --- a/Tests/Authorization/ExpressionLanguageTest.php +++ b/Tests/Authorization/ExpressionLanguageTest.php @@ -50,7 +50,7 @@ public static function provider() $user = new InMemoryUser('username', 'password', $roles); $noToken = null; - $rememberMeToken = new RememberMeToken($user, 'firewall-name', 'firewall'); + $rememberMeToken = new RememberMeToken($user, 'firewall-name'); $usernamePasswordToken = new UsernamePasswordToken($user, 'firewall-name', $roles); return [ diff --git a/Tests/Authorization/Voter/AuthenticatedVoterTest.php b/Tests/Authorization/Voter/AuthenticatedVoterTest.php index 88544c08..3a3b9d4e 100644 --- a/Tests/Authorization/Voter/AuthenticatedVoterTest.php +++ b/Tests/Authorization/Voter/AuthenticatedVoterTest.php @@ -101,7 +101,7 @@ public function getCredentials() } if ('remembered' === $authenticated) { - return new RememberMeToken($user, 'foo', 'bar'); + return new RememberMeToken($user, 'foo'); } if ('impersonated' === $authenticated) { diff --git a/composer.json b/composer.json index a923768b..0aaff1e3 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", "symfony/password-hasher": "^6.4|^7.0" From 8acc2fbaa06386de128a2a843a30728660c105c4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 3 Jun 2024 09:09:05 +0200 Subject: [PATCH 23/32] use constructor property promotion --- .../RememberMe/CacheTokenVerifier.php | 14 +++++-------- Authentication/RememberMe/PersistentToken.php | 17 +++++++-------- .../Token/PreAuthenticatedToken.php | 10 ++++----- Authentication/Token/RememberMeToken.php | 9 ++++---- .../Storage/UsageTrackingTokenStorage.php | 10 ++++----- Authentication/Token/SwitchUserToken.php | 11 ++++++---- .../Token/UsernamePasswordToken.php | 10 ++++----- Authorization/AccessDecisionManager.php | 8 +++---- .../Strategy/AffirmativeStrategy.php | 8 +++---- Authorization/Strategy/ConsensusStrategy.php | 11 ++++------ Authorization/Strategy/PriorityStrategy.php | 8 +++---- Authorization/Strategy/UnanimousStrategy.php | 8 +++---- .../TraceableAccessDecisionManager.php | 8 +++---- Authorization/Voter/AuthenticatedVoter.php | 8 +++---- Authorization/Voter/ExpressionVoter.php | 17 ++++++--------- Authorization/Voter/RoleHierarchyVoter.php | 10 ++++----- Authorization/Voter/RoleVoter.php | 8 +++---- Authorization/Voter/TraceableVoter.php | 11 ++++------ Event/AuthenticationEvent.php | 10 ++++----- Event/VoteEvent.php | 17 ++++++--------- Exception/LazyResponseException.php | 8 +++---- ...nyLoginAttemptsAuthenticationException.php | 8 +++---- Role/RoleHierarchy.php | 9 +++----- Signature/ExpiredSignatureStorage.php | 11 ++++------ Signature/SignatureHasher.php | 21 +++++++------------ Test/AccessDecisionStrategyTestCase.php | 8 +++---- User/ChainUserProvider.php | 8 +++---- User/InMemoryUser.php | 14 ++++++------- .../Constraints/UserPasswordValidator.php | 11 ++++------ 29 files changed, 123 insertions(+), 188 deletions(-) diff --git a/Authentication/RememberMe/CacheTokenVerifier.php b/Authentication/RememberMe/CacheTokenVerifier.php index e4f1362a..3930ac8d 100644 --- a/Authentication/RememberMe/CacheTokenVerifier.php +++ b/Authentication/RememberMe/CacheTokenVerifier.php @@ -18,21 +18,17 @@ */ class CacheTokenVerifier implements TokenVerifierInterface { - private CacheItemPoolInterface $cache; - private int $outdatedTokenTtl; - private string $cacheKeyPrefix; - /** * @param int $outdatedTokenTtl How long the outdated token should still be considered valid. Defaults * to 60, which matches how often the PersistentRememberMeHandler will at * most refresh tokens. Increasing to more than that is not recommended, * but you may use a lower value. */ - public function __construct(CacheItemPoolInterface $cache, int $outdatedTokenTtl = 60, string $cacheKeyPrefix = 'rememberme-stale-') - { - $this->cache = $cache; - $this->outdatedTokenTtl = $outdatedTokenTtl; - $this->cacheKeyPrefix = $cacheKeyPrefix; + public function __construct( + private CacheItemPoolInterface $cache, + private int $outdatedTokenTtl = 60, + private string $cacheKeyPrefix = 'rememberme-stale-', + ) { } public function verifyToken(PersistentTokenInterface $token, #[\SensitiveParameter] string $tokenValue): bool diff --git a/Authentication/RememberMe/PersistentToken.php b/Authentication/RememberMe/PersistentToken.php index c1f1e1a7..0f391c23 100644 --- a/Authentication/RememberMe/PersistentToken.php +++ b/Authentication/RememberMe/PersistentToken.php @@ -18,14 +18,15 @@ */ final class PersistentToken implements PersistentTokenInterface { - private string $class; - private string $userIdentifier; - private string $series; - private string $tokenValue; private \DateTimeImmutable $lastUsed; - public function __construct(string $class, string $userIdentifier, string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed) - { + public function __construct( + private string $class, + private string $userIdentifier, + private string $series, + #[\SensitiveParameter] private string $tokenValue, + \DateTimeInterface $lastUsed, + ) { if (!$class) { throw new \InvalidArgumentException('$class must not be empty.'); } @@ -39,10 +40,6 @@ public function __construct(string $class, string $userIdentifier, string $serie throw new \InvalidArgumentException('$tokenValue must not be empty.'); } - $this->class = $class; - $this->userIdentifier = $userIdentifier; - $this->series = $series; - $this->tokenValue = $tokenValue; $this->lastUsed = \DateTimeImmutable::createFromInterface($lastUsed); } diff --git a/Authentication/Token/PreAuthenticatedToken.php b/Authentication/Token/PreAuthenticatedToken.php index a216d4c1..5c092404 100644 --- a/Authentication/Token/PreAuthenticatedToken.php +++ b/Authentication/Token/PreAuthenticatedToken.php @@ -20,13 +20,14 @@ */ class PreAuthenticatedToken extends AbstractToken { - private string $firewallName; - /** * @param string[] $roles */ - public function __construct(UserInterface $user, string $firewallName, array $roles = []) - { + public function __construct( + UserInterface $user, + private string $firewallName, + array $roles = [], + ) { parent::__construct($roles); if ('' === $firewallName) { @@ -34,7 +35,6 @@ public function __construct(UserInterface $user, string $firewallName, array $ro } $this->setUser($user); - $this->firewallName = $firewallName; } public function getFirewallName(): string diff --git a/Authentication/Token/RememberMeToken.php b/Authentication/Token/RememberMeToken.php index 643c40d4..dfbe20ec 100644 --- a/Authentication/Token/RememberMeToken.php +++ b/Authentication/Token/RememberMeToken.php @@ -22,13 +22,14 @@ class RememberMeToken extends AbstractToken { private ?string $secret = null; - private string $firewallName; /** * @throws \InvalidArgumentException */ - public function __construct(UserInterface $user, string $firewallName) - { + public function __construct( + UserInterface $user, + private string $firewallName, + ) { parent::__construct($user->getRoles()); if (\func_num_args() > 2) { @@ -40,8 +41,6 @@ public function __construct(UserInterface $user, string $firewallName) throw new InvalidArgumentException('$firewallName must not be empty.'); } - $this->firewallName = $firewallName; - $this->setUser($user); } diff --git a/Authentication/Token/Storage/UsageTrackingTokenStorage.php b/Authentication/Token/Storage/UsageTrackingTokenStorage.php index 8a4069e7..4255491d 100644 --- a/Authentication/Token/Storage/UsageTrackingTokenStorage.php +++ b/Authentication/Token/Storage/UsageTrackingTokenStorage.php @@ -24,14 +24,12 @@ */ final class UsageTrackingTokenStorage implements TokenStorageInterface, ServiceSubscriberInterface { - private TokenStorageInterface $storage; - private ContainerInterface $container; private bool $enableUsageTracking = false; - public function __construct(TokenStorageInterface $storage, ContainerInterface $container) - { - $this->storage = $storage; - $this->container = $container; + public function __construct( + private TokenStorageInterface $storage, + private ContainerInterface $container, + ) { } public function getToken(): ?TokenInterface diff --git a/Authentication/Token/SwitchUserToken.php b/Authentication/Token/SwitchUserToken.php index fb632a61..c4e69766 100644 --- a/Authentication/Token/SwitchUserToken.php +++ b/Authentication/Token/SwitchUserToken.php @@ -20,7 +20,6 @@ */ class SwitchUserToken extends UsernamePasswordToken { - private TokenInterface $originalToken; private ?string $originatedFromUri = null; /** @@ -29,11 +28,15 @@ class SwitchUserToken extends UsernamePasswordToken * * @throws \InvalidArgumentException */ - public function __construct(UserInterface $user, string $firewallName, array $roles, TokenInterface $originalToken, ?string $originatedFromUri = null) - { + public function __construct( + UserInterface $user, + string $firewallName, + array $roles, + private TokenInterface $originalToken, + ?string $originatedFromUri = null, + ) { parent::__construct($user, $firewallName, $roles); - $this->originalToken = $originalToken; $this->originatedFromUri = $originatedFromUri; } diff --git a/Authentication/Token/UsernamePasswordToken.php b/Authentication/Token/UsernamePasswordToken.php index 74e24a21..40beb003 100644 --- a/Authentication/Token/UsernamePasswordToken.php +++ b/Authentication/Token/UsernamePasswordToken.php @@ -20,10 +20,11 @@ */ class UsernamePasswordToken extends AbstractToken { - private string $firewallName; - - public function __construct(UserInterface $user, string $firewallName, array $roles = []) - { + public function __construct( + UserInterface $user, + private string $firewallName, + array $roles = [], + ) { parent::__construct($roles); if ('' === $firewallName) { @@ -31,7 +32,6 @@ public function __construct(UserInterface $user, string $firewallName, array $ro } $this->setUser($user); - $this->firewallName = $firewallName; } public function getFirewallName(): string diff --git a/Authorization/AccessDecisionManager.php b/Authorization/AccessDecisionManager.php index 4a56f943..10969acb 100644 --- a/Authorization/AccessDecisionManager.php +++ b/Authorization/AccessDecisionManager.php @@ -32,7 +32,6 @@ final class AccessDecisionManager implements AccessDecisionManagerInterface VoterInterface::ACCESS_ABSTAIN => true, ]; - private iterable $voters; private array $votersCacheAttributes = []; private array $votersCacheObject = []; private AccessDecisionStrategyInterface $strategy; @@ -40,9 +39,10 @@ final class AccessDecisionManager implements AccessDecisionManagerInterface /** * @param iterable $voters An array or an iterator of VoterInterface instances */ - public function __construct(iterable $voters = [], ?AccessDecisionStrategyInterface $strategy = null) - { - $this->voters = $voters; + public function __construct( + private iterable $voters = [], + ?AccessDecisionStrategyInterface $strategy = null, + ) { $this->strategy = $strategy ?? new AffirmativeStrategy(); } diff --git a/Authorization/Strategy/AffirmativeStrategy.php b/Authorization/Strategy/AffirmativeStrategy.php index ecd74b20..fb316fd3 100644 --- a/Authorization/Strategy/AffirmativeStrategy.php +++ b/Authorization/Strategy/AffirmativeStrategy.php @@ -24,11 +24,9 @@ */ final class AffirmativeStrategy implements AccessDecisionStrategyInterface, \Stringable { - private bool $allowIfAllAbstainDecisions; - - public function __construct(bool $allowIfAllAbstainDecisions = false) - { - $this->allowIfAllAbstainDecisions = $allowIfAllAbstainDecisions; + public function __construct( + private bool $allowIfAllAbstainDecisions = false, + ) { } public function decide(\Traversable $results): bool diff --git a/Authorization/Strategy/ConsensusStrategy.php b/Authorization/Strategy/ConsensusStrategy.php index 489b3428..bff56513 100644 --- a/Authorization/Strategy/ConsensusStrategy.php +++ b/Authorization/Strategy/ConsensusStrategy.php @@ -32,13 +32,10 @@ */ final class ConsensusStrategy implements AccessDecisionStrategyInterface, \Stringable { - private bool $allowIfAllAbstainDecisions; - private bool $allowIfEqualGrantedDeniedDecisions; - - public function __construct(bool $allowIfAllAbstainDecisions = false, bool $allowIfEqualGrantedDeniedDecisions = true) - { - $this->allowIfAllAbstainDecisions = $allowIfAllAbstainDecisions; - $this->allowIfEqualGrantedDeniedDecisions = $allowIfEqualGrantedDeniedDecisions; + public function __construct( + private bool $allowIfAllAbstainDecisions = false, + private bool $allowIfEqualGrantedDeniedDecisions = true, + ) { } public function decide(\Traversable $results): bool diff --git a/Authorization/Strategy/PriorityStrategy.php b/Authorization/Strategy/PriorityStrategy.php index 9599950c..d7f566ad 100644 --- a/Authorization/Strategy/PriorityStrategy.php +++ b/Authorization/Strategy/PriorityStrategy.php @@ -25,11 +25,9 @@ */ final class PriorityStrategy implements AccessDecisionStrategyInterface, \Stringable { - private bool $allowIfAllAbstainDecisions; - - public function __construct(bool $allowIfAllAbstainDecisions = false) - { - $this->allowIfAllAbstainDecisions = $allowIfAllAbstainDecisions; + public function __construct( + private bool $allowIfAllAbstainDecisions = false, + ) { } public function decide(\Traversable $results): bool diff --git a/Authorization/Strategy/UnanimousStrategy.php b/Authorization/Strategy/UnanimousStrategy.php index 1f3b85c5..d47d8994 100644 --- a/Authorization/Strategy/UnanimousStrategy.php +++ b/Authorization/Strategy/UnanimousStrategy.php @@ -24,11 +24,9 @@ */ final class UnanimousStrategy implements AccessDecisionStrategyInterface, \Stringable { - private bool $allowIfAllAbstainDecisions; - - public function __construct(bool $allowIfAllAbstainDecisions = false) - { - $this->allowIfAllAbstainDecisions = $allowIfAllAbstainDecisions; + public function __construct( + private bool $allowIfAllAbstainDecisions = false, + ) { } public function decide(\Traversable $results): bool diff --git a/Authorization/TraceableAccessDecisionManager.php b/Authorization/TraceableAccessDecisionManager.php index cb44dce4..17db5461 100644 --- a/Authorization/TraceableAccessDecisionManager.php +++ b/Authorization/TraceableAccessDecisionManager.php @@ -25,17 +25,15 @@ */ class TraceableAccessDecisionManager implements AccessDecisionManagerInterface { - private AccessDecisionManagerInterface $manager; private ?AccessDecisionStrategyInterface $strategy = null; /** @var iterable */ private iterable $voters = []; private array $decisionLog = []; // All decision logs private array $currentLog = []; // Logs being filled in - public function __construct(AccessDecisionManagerInterface $manager) - { - $this->manager = $manager; - + public function __construct( + private AccessDecisionManagerInterface $manager, + ) { // The strategy and voters are stored in a private properties of the decorated service if (property_exists($manager, 'strategy')) { $reflection = new \ReflectionProperty($manager::class, 'strategy'); diff --git a/Authorization/Voter/AuthenticatedVoter.php b/Authorization/Voter/AuthenticatedVoter.php index d7b2b224..a0011868 100644 --- a/Authorization/Voter/AuthenticatedVoter.php +++ b/Authorization/Voter/AuthenticatedVoter.php @@ -33,11 +33,9 @@ class AuthenticatedVoter implements CacheableVoterInterface public const IS_REMEMBERED = 'IS_REMEMBERED'; public const PUBLIC_ACCESS = 'PUBLIC_ACCESS'; - private AuthenticationTrustResolverInterface $authenticationTrustResolver; - - public function __construct(AuthenticationTrustResolverInterface $authenticationTrustResolver) - { - $this->authenticationTrustResolver = $authenticationTrustResolver; + public function __construct( + private AuthenticationTrustResolverInterface $authenticationTrustResolver, + ) { } public function vote(TokenInterface $token, mixed $subject, array $attributes): int diff --git a/Authorization/Voter/ExpressionVoter.php b/Authorization/Voter/ExpressionVoter.php index 6de9c954..bab32830 100644 --- a/Authorization/Voter/ExpressionVoter.php +++ b/Authorization/Voter/ExpressionVoter.php @@ -26,17 +26,12 @@ */ class ExpressionVoter implements CacheableVoterInterface { - private ExpressionLanguage $expressionLanguage; - private AuthenticationTrustResolverInterface $trustResolver; - private AuthorizationCheckerInterface $authChecker; - private ?RoleHierarchyInterface $roleHierarchy; - - public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, AuthorizationCheckerInterface $authChecker, ?RoleHierarchyInterface $roleHierarchy = null) - { - $this->expressionLanguage = $expressionLanguage; - $this->trustResolver = $trustResolver; - $this->authChecker = $authChecker; - $this->roleHierarchy = $roleHierarchy; + public function __construct( + private ExpressionLanguage $expressionLanguage, + private AuthenticationTrustResolverInterface $trustResolver, + private AuthorizationCheckerInterface $authChecker, + private ?RoleHierarchyInterface $roleHierarchy = null, + ) { } public function supportsAttribute(string $attribute): bool diff --git a/Authorization/Voter/RoleHierarchyVoter.php b/Authorization/Voter/RoleHierarchyVoter.php index 3535ca11..110faa03 100644 --- a/Authorization/Voter/RoleHierarchyVoter.php +++ b/Authorization/Voter/RoleHierarchyVoter.php @@ -22,12 +22,10 @@ */ class RoleHierarchyVoter extends RoleVoter { - private RoleHierarchyInterface $roleHierarchy; - - public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefix = 'ROLE_') - { - $this->roleHierarchy = $roleHierarchy; - + public function __construct( + private RoleHierarchyInterface $roleHierarchy, + string $prefix = 'ROLE_', + ) { parent::__construct($prefix); } diff --git a/Authorization/Voter/RoleVoter.php b/Authorization/Voter/RoleVoter.php index 76de3a32..3c65fb63 100644 --- a/Authorization/Voter/RoleVoter.php +++ b/Authorization/Voter/RoleVoter.php @@ -20,11 +20,9 @@ */ class RoleVoter implements CacheableVoterInterface { - private string $prefix; - - public function __construct(string $prefix = 'ROLE_') - { - $this->prefix = $prefix; + public function __construct( + private string $prefix = 'ROLE_', + ) { } public function vote(TokenInterface $token, mixed $subject, array $attributes): int diff --git a/Authorization/Voter/TraceableVoter.php b/Authorization/Voter/TraceableVoter.php index 412bb976..1abc7c70 100644 --- a/Authorization/Voter/TraceableVoter.php +++ b/Authorization/Voter/TraceableVoter.php @@ -24,13 +24,10 @@ */ class TraceableVoter implements CacheableVoterInterface { - private VoterInterface $voter; - private EventDispatcherInterface $eventDispatcher; - - public function __construct(VoterInterface $voter, EventDispatcherInterface $eventDispatcher) - { - $this->voter = $voter; - $this->eventDispatcher = $eventDispatcher; + public function __construct( + private VoterInterface $voter, + private EventDispatcherInterface $eventDispatcher, + ) { } public function vote(TokenInterface $token, mixed $subject, array $attributes): int diff --git a/Event/AuthenticationEvent.php b/Event/AuthenticationEvent.php index 6fca50d4..f1683558 100644 --- a/Event/AuthenticationEvent.php +++ b/Event/AuthenticationEvent.php @@ -21,15 +21,13 @@ */ class AuthenticationEvent extends Event { - private TokenInterface $authenticationToken; - - public function __construct(TokenInterface $token) - { - $this->authenticationToken = $token; + public function __construct( + private TokenInterface $token, + ) { } public function getAuthenticationToken(): TokenInterface { - return $this->authenticationToken; + return $this->token; } } diff --git a/Event/VoteEvent.php b/Event/VoteEvent.php index 1b1d6a33..edc66b36 100644 --- a/Event/VoteEvent.php +++ b/Event/VoteEvent.php @@ -23,17 +23,12 @@ */ final class VoteEvent extends Event { - private VoterInterface $voter; - private mixed $subject; - private array $attributes; - private int $vote; - - public function __construct(VoterInterface $voter, mixed $subject, array $attributes, int $vote) - { - $this->voter = $voter; - $this->subject = $subject; - $this->attributes = $attributes; - $this->vote = $vote; + public function __construct( + private VoterInterface $voter, + private mixed $subject, + private array $attributes, + private int $vote, + ) { } public function getVoter(): VoterInterface diff --git a/Exception/LazyResponseException.php b/Exception/LazyResponseException.php index e26a3347..a354e68e 100644 --- a/Exception/LazyResponseException.php +++ b/Exception/LazyResponseException.php @@ -20,11 +20,9 @@ */ class LazyResponseException extends \Exception implements ExceptionInterface { - private Response $response; - - public function __construct(Response $response) - { - $this->response = $response; + public function __construct( + private Response $response, + ) { } public function getResponse(): Response diff --git a/Exception/TooManyLoginAttemptsAuthenticationException.php b/Exception/TooManyLoginAttemptsAuthenticationException.php index da1a1a7a..7bb74d64 100644 --- a/Exception/TooManyLoginAttemptsAuthenticationException.php +++ b/Exception/TooManyLoginAttemptsAuthenticationException.php @@ -19,11 +19,9 @@ */ class TooManyLoginAttemptsAuthenticationException extends AuthenticationException { - private ?int $threshold; - - public function __construct(?int $threshold = null) - { - $this->threshold = $threshold; + public function __construct( + private ?int $threshold = null, + ) { } public function getMessageData(): array diff --git a/Role/RoleHierarchy.php b/Role/RoleHierarchy.php index 15c5750d..a2a58457 100644 --- a/Role/RoleHierarchy.php +++ b/Role/RoleHierarchy.php @@ -21,15 +21,12 @@ class RoleHierarchy implements RoleHierarchyInterface /** @var array> */ protected array $map; - private array $hierarchy; - /** * @param array> $hierarchy */ - public function __construct(array $hierarchy) - { - $this->hierarchy = $hierarchy; - + public function __construct( + private array $hierarchy, + ) { $this->buildRoleMap(); } diff --git a/Signature/ExpiredSignatureStorage.php b/Signature/ExpiredSignatureStorage.php index 20803b97..62026644 100644 --- a/Signature/ExpiredSignatureStorage.php +++ b/Signature/ExpiredSignatureStorage.php @@ -18,13 +18,10 @@ */ final class ExpiredSignatureStorage { - private CacheItemPoolInterface $cache; - private int $lifetime; - - public function __construct(CacheItemPoolInterface $cache, int $lifetime) - { - $this->cache = $cache; - $this->lifetime = $lifetime; + public function __construct( + private CacheItemPoolInterface $cache, + private int $lifetime, + ) { } public function countUsages(string $hash): int diff --git a/Signature/SignatureHasher.php b/Signature/SignatureHasher.php index 3f86fce0..b38a449c 100644 --- a/Signature/SignatureHasher.php +++ b/Signature/SignatureHasher.php @@ -25,28 +25,21 @@ */ class SignatureHasher { - private PropertyAccessorInterface $propertyAccessor; - private array $signatureProperties; - private string $secret; - private ?ExpiredSignatureStorage $expiredSignaturesStorage; - private ?int $maxUses; - /** * @param array $signatureProperties Properties of the User; the hash is invalidated if these properties change * @param ExpiredSignatureStorage|null $expiredSignaturesStorage If provided, secures a sequence of hashes that are expired * @param int|null $maxUses Used together with $expiredSignatureStorage to allow a maximum usage of a hash */ - public function __construct(PropertyAccessorInterface $propertyAccessor, array $signatureProperties, #[\SensitiveParameter] string $secret, ?ExpiredSignatureStorage $expiredSignaturesStorage = null, ?int $maxUses = null) - { + public function __construct( + private PropertyAccessorInterface $propertyAccessor, + private array $signatureProperties, + #[\SensitiveParameter] private string $secret, + private ?ExpiredSignatureStorage $expiredSignaturesStorage = null, + private ?int $maxUses = null, + ) { if (!$secret) { throw new InvalidArgumentException('A non-empty secret is required.'); } - - $this->propertyAccessor = $propertyAccessor; - $this->signatureProperties = $signatureProperties; - $this->secret = $secret; - $this->expiredSignaturesStorage = $expiredSignaturesStorage; - $this->maxUses = $maxUses; } /** diff --git a/Test/AccessDecisionStrategyTestCase.php b/Test/AccessDecisionStrategyTestCase.php index bf2a2b9a..85e9fea8 100644 --- a/Test/AccessDecisionStrategyTestCase.php +++ b/Test/AccessDecisionStrategyTestCase.php @@ -64,11 +64,9 @@ final protected static function getVoters(int $grants, int $denies, int $abstain final protected static function getVoter(int $vote): VoterInterface { return new class($vote) implements VoterInterface { - private int $vote; - - public function __construct(int $vote) - { - $this->vote = $vote; + public function __construct( + private int $vote, + ) { } public function vote(TokenInterface $token, $subject, array $attributes): int diff --git a/User/ChainUserProvider.php b/User/ChainUserProvider.php index cef93a2d..f4329e88 100644 --- a/User/ChainUserProvider.php +++ b/User/ChainUserProvider.php @@ -26,14 +26,12 @@ */ class ChainUserProvider implements UserProviderInterface, PasswordUpgraderInterface { - private iterable $providers; - /** * @param iterable $providers */ - public function __construct(iterable $providers) - { - $this->providers = $providers; + public function __construct( + private iterable $providers, + ) { } /** diff --git a/User/InMemoryUser.php b/User/InMemoryUser.php index c319e1f9..5840d0bb 100644 --- a/User/InMemoryUser.php +++ b/User/InMemoryUser.php @@ -22,20 +22,18 @@ final class InMemoryUser implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface, \Stringable { private string $username; - private ?string $password; - private bool $enabled; - private array $roles; - public function __construct(?string $username, ?string $password, array $roles = [], bool $enabled = true) - { + public function __construct( + ?string $username, + private ?string $password, + private array $roles = [], + private bool $enabled = true, + ) { if ('' === $username || null === $username) { throw new \InvalidArgumentException('The username cannot be empty.'); } $this->username = $username; - $this->password = $password; - $this->enabled = $enabled; - $this->roles = $roles; } public function __toString(): string diff --git a/Validator/Constraints/UserPasswordValidator.php b/Validator/Constraints/UserPasswordValidator.php index 3d6c7637..c3869824 100644 --- a/Validator/Constraints/UserPasswordValidator.php +++ b/Validator/Constraints/UserPasswordValidator.php @@ -22,13 +22,10 @@ class UserPasswordValidator extends ConstraintValidator { - private TokenStorageInterface $tokenStorage; - private PasswordHasherFactoryInterface $hasherFactory; - - public function __construct(TokenStorageInterface $tokenStorage, PasswordHasherFactoryInterface $hasherFactory) - { - $this->tokenStorage = $tokenStorage; - $this->hasherFactory = $hasherFactory; + public function __construct( + private TokenStorageInterface $tokenStorage, + private PasswordHasherFactoryInterface $hasherFactory, + ) { } public function validate(mixed $password, Constraint $constraint): void From e70f73a3c359bb09d77e624579f5d0282bb25f19 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 20 Jun 2024 17:52:34 +0200 Subject: [PATCH 24/32] Prefix all sprintf() calls --- Authentication/Token/AbstractToken.php | 4 ++-- Authorization/AccessDecisionManager.php | 4 ++-- Authorization/ExpressionLanguage.php | 2 +- Authorization/ExpressionLanguageProvider.php | 2 +- Signature/SignatureHasher.php | 4 ++-- Tests/Resources/TranslationFilesTest.php | 4 ++-- User/ChainUserProvider.php | 6 +++--- User/InMemoryUserProvider.php | 6 +++--- User/MissingUserProvider.php | 2 +- Validator/Constraints/UserPasswordValidator.php | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Authentication/Token/AbstractToken.php b/Authentication/Token/AbstractToken.php index 36d64766..67d992ce 100644 --- a/Authentication/Token/AbstractToken.php +++ b/Authentication/Token/AbstractToken.php @@ -125,7 +125,7 @@ public function hasAttribute(string $name): bool public function getAttribute(string $name): mixed { if (!\array_key_exists($name, $this->attributes)) { - throw new \InvalidArgumentException(sprintf('This token has no "%s" attribute.', $name)); + throw new \InvalidArgumentException(\sprintf('This token has no "%s" attribute.', $name)); } return $this->attributes[$name]; @@ -146,7 +146,7 @@ public function __toString(): string $roles[] = $role; } - return sprintf('%s(user="%s", roles="%s")', $class, $this->getUserIdentifier(), implode(', ', $roles)); + return \sprintf('%s(user="%s", roles="%s")', $class, $this->getUserIdentifier(), implode(', ', $roles)); } /** diff --git a/Authorization/AccessDecisionManager.php b/Authorization/AccessDecisionManager.php index 10969acb..3e42c4bf 100644 --- a/Authorization/AccessDecisionManager.php +++ b/Authorization/AccessDecisionManager.php @@ -53,7 +53,7 @@ public function decide(TokenInterface $token, array $attributes, mixed $object = { // Special case for AccessListener, do not remove the right side of the condition before 6.0 if (\count($attributes) > 1 && !$allowMultipleAttributes) { - throw new InvalidArgumentException(sprintf('Passing more than one Security attribute to "%s()" is not supported.', __METHOD__)); + throw new InvalidArgumentException(\sprintf('Passing more than one Security attribute to "%s()" is not supported.', __METHOD__)); } return $this->strategy->decide( @@ -69,7 +69,7 @@ private function collectResults(TokenInterface $token, array $attributes, mixed foreach ($this->getVoters($attributes, $object) as $voter) { $result = $voter->vote($token, $object, $attributes); if (!\is_int($result) || !(self::VALID_VOTES[$result] ?? false)) { - throw new \LogicException(sprintf('"%s::vote()" must return one of "%s" constants ("ACCESS_GRANTED", "ACCESS_DENIED" or "ACCESS_ABSTAIN"), "%s" returned.', get_debug_type($voter), VoterInterface::class, var_export($result, true))); + throw new \LogicException(\sprintf('"%s::vote()" must return one of "%s" constants ("ACCESS_GRANTED", "ACCESS_DENIED" or "ACCESS_ABSTAIN"), "%s" returned.', get_debug_type($voter), VoterInterface::class, var_export($result, true))); } yield $result; diff --git a/Authorization/ExpressionLanguage.php b/Authorization/ExpressionLanguage.php index a48d8148..846d2cf6 100644 --- a/Authorization/ExpressionLanguage.php +++ b/Authorization/ExpressionLanguage.php @@ -15,7 +15,7 @@ use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage; if (!class_exists(BaseExpressionLanguage::class)) { - throw new \LogicException(sprintf('The "%s" class requires the "ExpressionLanguage" component. Try running "composer require symfony/expression-language".', ExpressionLanguage::class)); + throw new \LogicException(\sprintf('The "%s" class requires the "ExpressionLanguage" component. Try running "composer require symfony/expression-language".', ExpressionLanguage::class)); } else { // Help opcache.preload discover always-needed symbols class_exists(ExpressionLanguageProvider::class); diff --git a/Authorization/ExpressionLanguageProvider.php b/Authorization/ExpressionLanguageProvider.php index d3e2dac0..2e558c21 100644 --- a/Authorization/ExpressionLanguageProvider.php +++ b/Authorization/ExpressionLanguageProvider.php @@ -28,7 +28,7 @@ public function getFunctions(): array new ExpressionFunction('is_fully_authenticated', fn () => '$token && $auth_checker->isGranted("IS_AUTHENTICATED_FULLY")', fn (array $variables) => $variables['token'] && $variables['auth_checker']->isGranted('IS_AUTHENTICATED_FULLY')), - new ExpressionFunction('is_granted', fn ($attributes, $object = 'null') => sprintf('$auth_checker->isGranted(%s, %s)', $attributes, $object), fn (array $variables, $attributes, $object = null) => $variables['auth_checker']->isGranted($attributes, $object)), + new ExpressionFunction('is_granted', fn ($attributes, $object = 'null') => \sprintf('$auth_checker->isGranted(%s, %s)', $attributes, $object), fn (array $variables, $attributes, $object = null) => $variables['auth_checker']->isGranted($attributes, $object)), new ExpressionFunction('is_remember_me', fn () => '$token && $auth_checker->isGranted("IS_REMEMBERED")', fn (array $variables) => $variables['token'] && $variables['auth_checker']->isGranted('IS_REMEMBERED')), ]; diff --git a/Signature/SignatureHasher.php b/Signature/SignatureHasher.php index b38a449c..903f5b34 100644 --- a/Signature/SignatureHasher.php +++ b/Signature/SignatureHasher.php @@ -87,7 +87,7 @@ public function verifySignatureHash(UserInterface $user, int $expires, string $h if ($this->expiredSignaturesStorage && $this->maxUses) { if ($this->expiredSignaturesStorage->countUsages($hash) >= $this->maxUses) { - throw new ExpiredSignatureException(sprintf('Signature can only be used "%d" times.', $this->maxUses)); + throw new ExpiredSignatureException(\sprintf('Signature can only be used "%d" times.', $this->maxUses)); } $this->expiredSignaturesStorage->incrementUsages($hash); @@ -111,7 +111,7 @@ public function computeSignatureHash(UserInterface $user, int $expires): string } if (!\is_scalar($value) && !$value instanceof \Stringable) { - throw new \InvalidArgumentException(sprintf('The property path "%s" on the user object "%s" must return a value that can be cast to a string, but "%s" was returned.', $property, $user::class, get_debug_type($value))); + throw new \InvalidArgumentException(\sprintf('The property path "%s" on the user object "%s" must return a value that can be cast to a string, but "%s" was returned.', $property, $user::class, get_debug_type($value))); } hash_update($fieldsHash, ':'.base64_encode($value)); } diff --git a/Tests/Resources/TranslationFilesTest.php b/Tests/Resources/TranslationFilesTest.php index 6bd9a21d..695cdd98 100644 --- a/Tests/Resources/TranslationFilesTest.php +++ b/Tests/Resources/TranslationFilesTest.php @@ -26,7 +26,7 @@ public function testTranslationFileIsValid($filePath) $errors = XliffUtils::validateSchema($document); - $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + $this->assertCount(0, $errors, \sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } /** @@ -39,7 +39,7 @@ public function testTranslationFileIsValidWithoutEntityLoader($filePath) $errors = XliffUtils::validateSchema($document); - $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + $this->assertCount(0, $errors, \sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } public static function provideTranslationFiles() diff --git a/User/ChainUserProvider.php b/User/ChainUserProvider.php index f4329e88..484d0d47 100644 --- a/User/ChainUserProvider.php +++ b/User/ChainUserProvider.php @@ -56,7 +56,7 @@ public function loadUserByIdentifier(string $identifier): UserInterface } } - $ex = new UserNotFoundException(sprintf('There is no user with identifier "%s".', $identifier)); + $ex = new UserNotFoundException(\sprintf('There is no user with identifier "%s".', $identifier)); $ex->setUserIdentifier($identifier); throw $ex; } @@ -82,11 +82,11 @@ public function refreshUser(UserInterface $user): UserInterface if ($supportedUserFound) { $username = $user->getUserIdentifier(); - $e = new UserNotFoundException(sprintf('There is no user with name "%s".', $username)); + $e = new UserNotFoundException(\sprintf('There is no user with name "%s".', $username)); $e->setUserIdentifier($username); throw $e; } else { - throw new UnsupportedUserException(sprintf('There is no user provider for user "%s". Shouldn\'t the "supportsClass()" method of your user provider return true for this classname?', get_debug_type($user))); + throw new UnsupportedUserException(\sprintf('There is no user provider for user "%s". Shouldn\'t the "supportsClass()" method of your user provider return true for this classname?', get_debug_type($user))); } } diff --git a/User/InMemoryUserProvider.php b/User/InMemoryUserProvider.php index 04bf682a..db6267a5 100644 --- a/User/InMemoryUserProvider.php +++ b/User/InMemoryUserProvider.php @@ -55,7 +55,7 @@ public function __construct(array $users = []) public function createUser(UserInterface $user): void { if (!$user instanceof InMemoryUser) { - throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user))); + throw new UnsupportedUserException(\sprintf('Instances of "%s" are not supported.', get_debug_type($user))); } $userIdentifier = strtolower($user->getUserIdentifier()); @@ -76,7 +76,7 @@ public function loadUserByIdentifier(string $identifier): UserInterface public function refreshUser(UserInterface $user): UserInterface { if (!$user instanceof InMemoryUser) { - throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user))); + throw new UnsupportedUserException(\sprintf('Instances of "%s" are not supported.', get_debug_type($user))); } $storedUser = $this->getUser($user->getUserIdentifier()); @@ -98,7 +98,7 @@ public function supportsClass(string $class): bool private function getUser(string $username): InMemoryUser { if (!isset($this->users[strtolower($username)])) { - $ex = new UserNotFoundException(sprintf('Username "%s" does not exist.', $username)); + $ex = new UserNotFoundException(\sprintf('Username "%s" does not exist.', $username)); $ex->setUserIdentifier($username); throw $ex; diff --git a/User/MissingUserProvider.php b/User/MissingUserProvider.php index cf6102aa..9869259a 100644 --- a/User/MissingUserProvider.php +++ b/User/MissingUserProvider.php @@ -28,7 +28,7 @@ class MissingUserProvider implements UserProviderInterface */ public function __construct(string $firewall) { - throw new InvalidConfigurationException(sprintf('"%s" firewall requires a user provider but none was defined.', $firewall)); + throw new InvalidConfigurationException(\sprintf('"%s" firewall requires a user provider but none was defined.', $firewall)); } public function loadUserByUsername(string $username): UserInterface diff --git a/Validator/Constraints/UserPasswordValidator.php b/Validator/Constraints/UserPasswordValidator.php index c3869824..6c9bdef9 100644 --- a/Validator/Constraints/UserPasswordValidator.php +++ b/Validator/Constraints/UserPasswordValidator.php @@ -49,7 +49,7 @@ public function validate(mixed $password, Constraint $constraint): void $user = $this->tokenStorage->getToken()->getUser(); if (!$user instanceof PasswordAuthenticatedUserInterface) { - throw new ConstraintDefinitionException(sprintf('The "%s" class must implement the "%s" interface.', PasswordAuthenticatedUserInterface::class, get_debug_type($user))); + throw new ConstraintDefinitionException(\sprintf('The "%s" class must implement the "%s" interface.', PasswordAuthenticatedUserInterface::class, get_debug_type($user))); } $hasher = $this->hasherFactory->getPasswordHasher($user); From 40cbdcaad146cd431686dddaf5231f13579f1d00 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 6 Jul 2024 09:57:16 +0200 Subject: [PATCH 25/32] Update .gitattributes --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 84c7add0..14c3c359 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore From 138cfe23ea2e991f3c9999c077779dcdce03e0f6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 19 Jul 2024 09:42:17 +0200 Subject: [PATCH 26/32] pass the current token to the checkPostAuth() method of user checkers --- CHANGELOG.md | 1 + User/ChainUserChecker.php | 12 ++++++++++-- User/UserCheckerInterface.php | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 208f0d48..ac99a3c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.2 --- + * Add `$token` argument to `UserCheckerInterface::checkPostAuth()` * Deprecate argument `$secret` of `RememberMeToken` 7.0 diff --git a/User/ChainUserChecker.php b/User/ChainUserChecker.php index f889d35d..67fd76b9 100644 --- a/User/ChainUserChecker.php +++ b/User/ChainUserChecker.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Core\User; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + final class ChainUserChecker implements UserCheckerInterface { /** @@ -27,10 +29,16 @@ public function checkPreAuth(UserInterface $user): void } } - public function checkPostAuth(UserInterface $user): void + public function checkPostAuth(UserInterface $user /*, TokenInterface $token*/): void { + $token = 1 < \func_num_args() ? func_get_arg(1) : null; + foreach ($this->checkers as $checker) { - $checker->checkPostAuth($user); + if ($token instanceof TokenInterface) { + $checker->checkPostAuth($user, $token); + } else { + $checker->checkPostAuth($user); + } } } } diff --git a/User/UserCheckerInterface.php b/User/UserCheckerInterface.php index 480ba7b5..2dc748aa 100644 --- a/User/UserCheckerInterface.php +++ b/User/UserCheckerInterface.php @@ -35,5 +35,5 @@ public function checkPreAuth(UserInterface $user): void; * * @throws AccountStatusException */ - public function checkPostAuth(UserInterface $user): void; + public function checkPostAuth(UserInterface $user /*, TokenInterface $token*/): void; } From 9b1348ac4bc9f25b6d9ccfd7e5e6b3af1cf78c0b Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 31 Jul 2024 16:13:26 +0200 Subject: [PATCH 27/32] Remove unused code and unnecessary `else` branches --- User/ChainUserProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/User/ChainUserProvider.php b/User/ChainUserProvider.php index 484d0d47..21e2e618 100644 --- a/User/ChainUserProvider.php +++ b/User/ChainUserProvider.php @@ -85,9 +85,9 @@ public function refreshUser(UserInterface $user): UserInterface $e = new UserNotFoundException(\sprintf('There is no user with name "%s".', $username)); $e->setUserIdentifier($username); throw $e; - } else { - throw new UnsupportedUserException(\sprintf('There is no user provider for user "%s". Shouldn\'t the "supportsClass()" method of your user provider return true for this classname?', get_debug_type($user))); } + + throw new UnsupportedUserException(\sprintf('There is no user provider for user "%s". Shouldn\'t the "supportsClass()" method of your user provider return true for this classname?', get_debug_type($user))); } public function supportsClass(string $class): bool From f0267ab90e6edb18ec982ad481c867c7fb3375a9 Mon Sep 17 00:00:00 2001 From: Roy de Vos Burchart Date: Thu, 1 Aug 2024 17:21:17 +0200 Subject: [PATCH 28/32] Code style change in `@PER-CS2.0` affecting `@Symfony` (parentheses for anonymous classes) --- Tests/Authorization/AccessDecisionManagerTest.php | 2 +- Tests/Authorization/Voter/AuthenticatedVoterTest.php | 2 +- Tests/Authorization/Voter/VoterTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Authorization/AccessDecisionManagerTest.php b/Tests/Authorization/AccessDecisionManagerTest.php index b06a7a79..f0a49788 100644 --- a/Tests/Authorization/AccessDecisionManagerTest.php +++ b/Tests/Authorization/AccessDecisionManagerTest.php @@ -39,7 +39,7 @@ public function testVoterCalls() $this->getUnexpectedVoter(), ]; - $strategy = new class() implements AccessDecisionStrategyInterface { + $strategy = new class implements AccessDecisionStrategyInterface { public function decide(\Traversable $results): bool { $i = 0; diff --git a/Tests/Authorization/Voter/AuthenticatedVoterTest.php b/Tests/Authorization/Voter/AuthenticatedVoterTest.php index 3a3b9d4e..ed894b3a 100644 --- a/Tests/Authorization/Voter/AuthenticatedVoterTest.php +++ b/Tests/Authorization/Voter/AuthenticatedVoterTest.php @@ -90,7 +90,7 @@ protected function getToken($authenticated) $user = new InMemoryUser('wouter', '', ['ROLE_USER']); if ('fully' === $authenticated) { - $token = new class() extends AbstractToken { + $token = new class extends AbstractToken { public function getCredentials() { } diff --git a/Tests/Authorization/Voter/VoterTest.php b/Tests/Authorization/Voter/VoterTest.php index 5636340e..602c61ab 100644 --- a/Tests/Authorization/Voter/VoterTest.php +++ b/Tests/Authorization/Voter/VoterTest.php @@ -41,7 +41,7 @@ public static function getTests(): array [$voter, ['DELETE'], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'], - [$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, new class() {}, 'ACCESS_ABSTAIN if class is not supported'], + [$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, new class {}, 'ACCESS_ABSTAIN if class is not supported'], [$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'], From a32dd8b58706d9d5be2ceeb2873276d600235a88 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 29 Jul 2024 09:33:48 +0200 Subject: [PATCH 29/32] Remove useless code --- User/InMemoryUser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/User/InMemoryUser.php b/User/InMemoryUser.php index 5840d0bb..b14bc077 100644 --- a/User/InMemoryUser.php +++ b/User/InMemoryUser.php @@ -88,8 +88,8 @@ public function isEqualTo(UserInterface $user): bool return false; } - $currentRoles = array_map('strval', (array) $this->getRoles()); - $newRoles = array_map('strval', (array) $user->getRoles()); + $currentRoles = array_map('strval', $this->getRoles()); + $newRoles = array_map('strval', $user->getRoles()); $rolesChanged = \count($currentRoles) !== \count($newRoles) || \count($currentRoles) !== \count(array_intersect($currentRoles, $newRoles)); if ($rolesChanged) { return false; From 0d94fd9669fe990d23d7d27ecb1e8448a025870c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Wed, 14 Aug 2024 08:46:31 +0200 Subject: [PATCH 30/32] Deprecate empty user identifier --- CHANGELOG.md | 1 + User/UserInterface.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac99a3c0..5dd5ef38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add `$token` argument to `UserCheckerInterface::checkPostAuth()` * Deprecate argument `$secret` of `RememberMeToken` + * Deprecate returning an empty string in `UserInterface::getUserIdentifier()` 7.0 --- diff --git a/User/UserInterface.php b/User/UserInterface.php index 50f8fb0f..e6078399 100644 --- a/User/UserInterface.php +++ b/User/UserInterface.php @@ -56,6 +56,8 @@ public function eraseCredentials(): void; /** * Returns the identifier for this user (e.g. username or email address). + * + * @return non-empty-string */ public function getUserIdentifier(): string; } From 2acef5cfd7cc6697d4618cdd9eb363eb5ab713b2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Aug 2024 17:35:30 +0200 Subject: [PATCH 31/32] Use Stringable whenever possible --- Authorization/TraceableAccessDecisionManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Authorization/TraceableAccessDecisionManager.php b/Authorization/TraceableAccessDecisionManager.php index 17db5461..0b82eb3a 100644 --- a/Authorization/TraceableAccessDecisionManager.php +++ b/Authorization/TraceableAccessDecisionManager.php @@ -85,7 +85,7 @@ public function getStrategy(): string if (null === $this->strategy) { return '-'; } - if (method_exists($this->strategy, '__toString')) { + if ($this->strategy instanceof \Stringable) { return (string) $this->strategy; } From c563eafb17f8332faa9d600a82b7d732f22d3ae6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 5 Sep 2024 11:40:18 +0200 Subject: [PATCH 32/32] make test case classes compatible with PHPUnit 10+ --- CHANGELOG.md | 1 + Test/AccessDecisionStrategyTestCase.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dd5ef38..7cf09c70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.2 --- + * Make `AccessDecisionStrategyTestCase` compatible with PHPUnit 10+ * Add `$token` argument to `UserCheckerInterface::checkPostAuth()` * Deprecate argument `$secret` of `RememberMeToken` * Deprecate returning an empty string in `UserInterface::getUserIdentifier()` diff --git a/Test/AccessDecisionStrategyTestCase.php b/Test/AccessDecisionStrategyTestCase.php index 85e9fea8..792e7779 100644 --- a/Test/AccessDecisionStrategyTestCase.php +++ b/Test/AccessDecisionStrategyTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Core\Test; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; @@ -29,6 +30,7 @@ abstract class AccessDecisionStrategyTestCase extends TestCase * * @param VoterInterface[] $voters */ + #[DataProvider('provideStrategyTests')] final public function testDecide(AccessDecisionStrategyInterface $strategy, array $voters, bool $expected) { $token = $this->createMock(TokenInterface::class);