Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 44b843a

Browse files
wouterjfabpot
authored andcommitted
[Security] Deprecate AnonymousToken, non-UserInterface users, and token credentials
1 parent 1d19615 commit 44b843a

File tree

47 files changed

+347
-130
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+347
-130
lines changed

UPGRADE-5.4.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ SecurityBundle
5959
Security
6060
--------
6161

62-
* Deprecate the `$authManager` argument of `AccessListener`
63-
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor
62+
* Deprecate `AnonymousToken`, as the related authenticator was deprecated in 5.3
63+
* Deprecate `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
64+
* Deprecate not returning an `UserInterface` from `Token::getUser()`
65+
* Deprecate the `$authManager` argument of `AccessListener`, the argument will be removed
66+
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor, the argument will be removed
6467
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the
6568
`$exceptionOnNoToken argument to `false` of `AuthorizationChecker` (this is the default
6669
behavior when using `enable_authenticator_manager: true`)

UPGRADE-6.0.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ Routing
207207
Security
208208
--------
209209

210+
* Remove `AnonymousToken`
211+
* Remove `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
212+
* Restrict the return type of `Token::getUser()` to `UserInterface` (removing `string|\Stringable`)
210213
* Remove the 4th and 5th argument of `AuthorizationChecker`
211214
* Remove the 5th argument of `AccessListener`
212215
* Remove class `User`, use `InMemoryUser` or your own implementation instead.

src/Symfony/Bridge/Monolog/Tests/Processor/SwitchUserTokenProcessorTest.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1717
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
1818
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
19+
use Symfony\Component\Security\Core\User\InMemoryUser;
20+
use Symfony\Component\Security\Core\User\User;
1921

2022
/**
2123
* Tests the SwitchUserTokenProcessor.
@@ -26,8 +28,13 @@ class SwitchUserTokenProcessorTest extends TestCase
2628
{
2729
public function testProcessor()
2830
{
29-
$originalToken = new UsernamePasswordToken('original_user', 'password', 'provider', ['ROLE_SUPER_ADMIN']);
30-
$switchUserToken = new SwitchUserToken('user', 'passsword', 'provider', ['ROLE_USER'], $originalToken);
31+
if (class_exists(InMemoryUser::class)) {
32+
$originalToken = new UsernamePasswordToken(new InMemoryUser('original_user', 'password', ['ROLE_SUPER_ADMIN']), 'provider', ['ROLE_SUPER_ADMIN']);
33+
$switchUserToken = new SwitchUserToken(new InMemoryUser('user', 'passsword', ['ROLE_USER']), 'provider', ['ROLE_USER'], $originalToken);
34+
} else {
35+
$originalToken = new UsernamePasswordToken(new User('original_user', 'password', ['ROLE_SUPER_ADMIN']), null, 'provider', ['ROLE_SUPER_ADMIN']);
36+
$switchUserToken = new SwitchUserToken(new User('user', 'passsword', ['ROLE_USER']), null, 'provider', ['ROLE_USER'], $originalToken);
37+
}
3138
$tokenStorage = $this->createMock(TokenStorageInterface::class);
3239
$tokenStorage->method('getToken')->willReturn($switchUserToken);
3340

src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Bridge\Monolog\Processor\TokenProcessor;
1616
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1717
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
18+
use Symfony\Component\Security\Core\User\InMemoryUser;
1819

1920
/**
2021
* Tests the TokenProcessor.
@@ -23,6 +24,9 @@
2324
*/
2425
class TokenProcessorTest extends TestCase
2526
{
27+
/**
28+
* @group legacy
29+
*/
2630
public function testLegacyProcessor()
2731
{
2832
if (method_exists(UsernamePasswordToken::class, 'getUserIdentifier')) {
@@ -48,7 +52,7 @@ public function testProcessor()
4852
$this->markTestSkipped('This test requires symfony/security-core 5.3+');
4953
}
5054

51-
$token = new UsernamePasswordToken('user', 'password', 'provider', ['ROLE_USER']);
55+
$token = new UsernamePasswordToken(new InMemoryUser('user', 'password', ['ROLE_USER']), 'provider', ['ROLE_USER']);
5256
$tokenStorage = $this->createMock(TokenStorageInterface::class);
5357
$tokenStorage->method('getToken')->willReturn($token);
5458

src/Symfony/Bridge/Twig/AppVariable.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public function getUser()
8484

8585
$user = $token->getUser();
8686

87+
// @deprecated since 5.4, $user will always be a UserInterface instance
8788
return \is_object($user) ? $user : null;
8889
}
8990

src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ protected function getDoctrine(): ManagerRegistry
395395
/**
396396
* Get a user from the Security Token Storage.
397397
*
398-
* @return UserInterface|object|null
398+
* @return UserInterface|null
399399
*
400400
* @throws \LogicException If SecurityBundle is not available
401401
*
@@ -411,6 +411,7 @@ protected function getUser()
411411
return null;
412412
}
413413

414+
// @deprecated since 5.4, $user will always be a UserInterface instance
414415
if (!\is_object($user = $token->getUser())) {
415416
// e.g. anonymous authentication
416417
return null;

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,17 @@ public function testForward()
138138
public function testGetUser()
139139
{
140140
$user = new InMemoryUser('user', 'pass');
141-
$token = new UsernamePasswordToken($user, 'pass', 'default', ['ROLE_USER']);
141+
$token = new UsernamePasswordToken($user, 'default', ['ROLE_USER']);
142142

143143
$controller = $this->createController();
144144
$controller->setContainer($this->getContainerWithTokenStorage($token));
145145

146146
$this->assertSame($controller->getUser(), $user);
147147
}
148148

149+
/**
150+
* @group legacy
151+
*/
149152
public function testGetUserAnonymousUserConvertedToNull()
150153
{
151154
$token = new AnonymousToken('default', 'anon.');

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"symfony/notifier": "^5.3|^6.0",
5454
"symfony/process": "^4.4|^5.0|^6.0",
5555
"symfony/rate-limiter": "^5.2|^6.0",
56-
"symfony/security-bundle": "^5.3|^6.0",
56+
"symfony/security-bundle": "^5.4|^6.0",
5757
"symfony/serializer": "^5.4|^6.0",
5858
"symfony/stopwatch": "^4.4|^5.0|^6.0",
5959
"symfony/string": "^5.0|^6.0",
@@ -89,7 +89,6 @@
8989
"symfony/property-access": "<5.3",
9090
"symfony/serializer": "<5.2",
9191
"symfony/security-csrf": "<5.3",
92-
"symfony/security-core": "<5.3",
9392
"symfony/stopwatch": "<4.4",
9493
"symfony/translation": "<5.3",
9594
"symfony/twig-bridge": "<4.4",

src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter;
3030
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
3131
use Symfony\Component\Security\Core\Role\RoleHierarchy;
32+
use Symfony\Component\Security\Core\User\InMemoryUser;
3233
use Symfony\Component\Security\Http\FirewallMapInterface;
3334
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
3435
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
@@ -78,7 +79,7 @@ public function testCollectWhenAuthenticationTokenIsNull()
7879
public function testCollectAuthenticationTokenAndRoles(array $roles, array $normalizedRoles, array $inheritedRoles)
7980
{
8081
$tokenStorage = new TokenStorage();
81-
$tokenStorage->setToken(new UsernamePasswordToken('hhamon', 'P4$$w0rD', 'provider', $roles));
82+
$tokenStorage->setToken(new UsernamePasswordToken(new InMemoryUser('hhamon', 'P4$$w0rD', $roles), 'provider', $roles));
8283

8384
$collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null, true);
8485
$collector->collect(new Request(), new Response());
@@ -99,10 +100,10 @@ public function testCollectAuthenticationTokenAndRoles(array $roles, array $norm
99100

100101
public function testCollectSwitchUserToken()
101102
{
102-
$adminToken = new UsernamePasswordToken('yceruto', 'P4$$w0rD', 'provider', ['ROLE_ADMIN']);
103+
$adminToken = new UsernamePasswordToken(new InMemoryUser('yceruto', 'P4$$w0rD', ['ROLE_ADMIN']), 'provider', ['ROLE_ADMIN']);
103104

104105
$tokenStorage = new TokenStorage();
105-
$tokenStorage->setToken(new SwitchUserToken('hhamon', 'P4$$w0rD', 'provider', ['ROLE_USER', 'ROLE_PREVIOUS_ADMIN'], $adminToken));
106+
$tokenStorage->setToken(new SwitchUserToken(new InMemoryUser('hhamon', 'P4$$w0rD', ['ROLE_USER', 'ROLE_PREVIOUS_ADMIN']), 'provider', ['ROLE_USER', 'ROLE_PREVIOUS_ADMIN'], $adminToken));
106107

107108
$collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null, true);
108109
$collector->collect(new Request(), new Response());

src/Symfony/Bundle/SecurityBundle/Tests/Functional/MissingUserProviderTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public function testUserProviderIsNeeded()
2828
]);
2929
}
3030

31+
/**
32+
* @group legacy
33+
*/
3134
public function testLegacyUserProviderIsNeeded()
3235
{
3336
$client = $this->createClient(['test_case' => 'MissingUserProvider', 'root_config' => 'config.yml', 'debug' => true]);

src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function testServiceIsFunctional()
2727

2828
// put a token into the storage so the final calls can function
2929
$user = new InMemoryUser('foo', 'pass');
30-
$token = new UsernamePasswordToken($user, '', 'provider', ['ROLE_USER']);
30+
$token = new UsernamePasswordToken($user, 'provider', ['ROLE_USER']);
3131
$container->get('functional.test.security.token_storage')->setToken($token);
3232

3333
$security = $container->get('functional_test.security.helper');
@@ -105,7 +105,7 @@ public function testLegacyServiceIsFunctional()
105105

106106
// put a token into the storage so the final calls can function
107107
$user = new InMemoryUser('foo', 'pass');
108-
$token = new UsernamePasswordToken($user, '', 'provider', ['ROLE_USER']);
108+
$token = new UsernamePasswordToken($user, 'provider', ['ROLE_USER']);
109109
$container->get('functional.test.security.token_storage')->setToken($token);
110110

111111
$security = $container->get('functional_test.security.helper');

src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ public function setUser($user)
9999
throw new \InvalidArgumentException('$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string.');
100100
}
101101

102+
if (!$user instanceof UserInterface) {
103+
trigger_deprecation('symfony/security-core', '5.4', 'Using an object that is not an instance of "%s" as $user in "%s" is deprecated.', UserInterface::class, static::class);
104+
}
105+
102106
// @deprecated since Symfony 5.4, remove the whole block if/elseif/else block in 6.0
103107
if (1 < \func_num_args() && !func_get_arg(1)) {
104108
// ContextListener checks if the user has changed on its own and calls `setAuthenticated()` subsequently,

src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* AnonymousToken represents an anonymous token.
1818
*
1919
* @author Fabien Potencier <[email protected]>
20+
*
21+
* @deprecated since 5.4, anonymous is now represented by the absence of a token
2022
*/
2123
class AnonymousToken extends AbstractToken
2224
{
@@ -29,6 +31,8 @@ class AnonymousToken extends AbstractToken
2931
*/
3032
public function __construct(string $secret, $user, array $roles = [])
3133
{
34+
trigger_deprecation('symfony/security-core', '5.4', 'The "%s" class is deprecated.', __CLASS__);
35+
3236
parent::__construct($roles);
3337

3438
$this->secret = $secret;

src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,28 @@ class PreAuthenticatedToken extends AbstractToken
2424
private $firewallName;
2525

2626
/**
27-
* @param string|\Stringable|UserInterface $user
28-
* @param mixed $credentials
29-
* @param string[] $roles
27+
* @param UserInterface $user
28+
* @param string $firewallName
29+
* @param string[] $roles
3030
*/
31-
public function __construct($user, $credentials, string $firewallName, array $roles = [])
31+
public function __construct($user, /*string*/ $firewallName, /*array*/ $roles = [])
3232
{
33+
if (\is_string($roles)) {
34+
trigger_deprecation('symfony/security-core', '5.4', 'Argument $credentials of "%s()" is deprecated.', __METHOD__);
35+
36+
$credentials = $firewallName;
37+
$firewallName = $roles;
38+
$roles = \func_num_args() > 3 ? func_get_arg(3) : [];
39+
}
40+
3341
parent::__construct($roles);
3442

3543
if ('' === $firewallName) {
3644
throw new \InvalidArgumentException('$firewallName must not be empty.');
3745
}
3846

3947
$this->setUser($user);
40-
$this->credentials = $credentials;
48+
$this->credentials = $credentials ?? null;
4149
$this->firewallName = $firewallName;
4250

4351
if ($roles) {
@@ -55,7 +63,7 @@ public function __construct($user, $credentials, string $firewallName, array $ro
5563
public function getProviderKey()
5664
{
5765
if (1 !== \func_num_args() || true !== func_get_arg(0)) {
58-
trigger_deprecation('symfony/security-core', '5.2', 'Method "%s" is deprecated, use "getFirewallName()" instead.', __METHOD__);
66+
trigger_deprecation('symfony/security-core', '5.2', 'Method "%s()" is deprecated, use "getFirewallName()" instead.', __METHOD__);
5967
}
6068

6169
return $this->firewallName;
@@ -71,6 +79,8 @@ public function getFirewallName(): string
7179
*/
7280
public function getCredentials()
7381
{
82+
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
83+
7484
return $this->credentials;
7585
}
7686

src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function setAuthenticated(bool $authenticated)
6969
public function getProviderKey()
7070
{
7171
if (1 !== \func_num_args() || true !== func_get_arg(0)) {
72-
trigger_deprecation('symfony/security-core', '5.2', 'Method "%s" is deprecated, use "getFirewallName()" instead.', __METHOD__);
72+
trigger_deprecation('symfony/security-core', '5.2', 'Method "%s()" is deprecated, use "getFirewallName()" instead.', __METHOD__);
7373
}
7474

7575
return $this->firewallName;
@@ -95,6 +95,8 @@ public function getSecret()
9595
*/
9696
public function getCredentials()
9797
{
98+
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
99+
98100
return '';
99101
}
100102

src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Security\Core\Authentication\Token;
1313

14+
use Symfony\Component\Security\Core\User\UserInterface;
15+
1416
/**
1517
* Token representing a user who temporarily impersonates another one.
1618
*
@@ -22,15 +24,29 @@ class SwitchUserToken extends UsernamePasswordToken
2224
private $originatedFromUri;
2325

2426
/**
25-
* @param string|object $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method
26-
* @param mixed $credentials This usually is the password of the user
27+
* @param UserInterface $user
2728
* @param string|null $originatedFromUri The URI where was the user at the switch
2829
*
2930
* @throws \InvalidArgumentException
3031
*/
31-
public function __construct($user, $credentials, string $firewallName, array $roles, TokenInterface $originalToken, string $originatedFromUri = null)
32+
public function __construct($user, /*string*/ $firewallName, /*array*/ $roles, /*TokenInterface*/ $originalToken, /*string*/ $originatedFromUri = null)
3233
{
33-
parent::__construct($user, $credentials, $firewallName, $roles);
34+
if (\is_string($roles)) {
35+
// @deprecated since 5.4, deprecation is triggered by UsernamePasswordToken::__construct()
36+
$credentials = $firewallName;
37+
$firewallName = $roles;
38+
$roles = $originalToken;
39+
$originalToken = $originatedFromUri;
40+
$originatedFromUri = \func_num_args() > 5 ? func_get_arg(5) : null;
41+
42+
parent::__construct($user, $credentials, $firewallName, $roles);
43+
} else {
44+
parent::__construct($user, $firewallName, $roles);
45+
}
46+
47+
if (!$originalToken instanceof TokenInterface) {
48+
throw new \TypeError(sprintf('Argument $originalToken of "%s" must be an instance of "%s", "%s" given.', __METHOD__, TokenInterface::class, get_debug_type($originalToken)));
49+
}
3450

3551
$this->originalToken = $originalToken;
3652
$this->originatedFromUri = $originatedFromUri;

src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,24 @@ public function getRoleNames(): array;
4343
* Returns the user credentials.
4444
*
4545
* @return mixed The user credentials
46+
*
47+
* @deprecated since 5.4
4648
*/
4749
public function getCredentials();
4850

4951
/**
5052
* Returns a user representation.
5153
*
52-
* @return string|\Stringable|UserInterface
54+
* @return UserInterface
5355
*
5456
* @see AbstractToken::setUser()
5557
*/
5658
public function getUser();
5759

5860
/**
59-
* Sets the user in the token.
60-
*
61-
* The user can be a UserInterface instance, or an object implementing
62-
* a __toString method or the username as a regular string.
61+
* Sets the authenticated user in the token.
6362
*
64-
* @param string|\Stringable|UserInterface $user
63+
* @param UserInterface $user
6564
*
6665
* @throws \InvalidArgumentException
6766
*/

0 commit comments

Comments
 (0)