Skip to content

Commit d01376f

Browse files
wouterjfabpot
authored andcommitted
[Security] Deprecate AnonymousToken, non-UserInterface users, and token credentials
1 parent 0b11b63 commit d01376f

21 files changed

+264
-89
lines changed

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,

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;

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

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

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;

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
*/

Authentication/Token/UsernamePasswordToken.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,29 @@ class UsernamePasswordToken extends AbstractToken
2424
private $firewallName;
2525

2626
/**
27-
* @param string|\Stringable|UserInterface $user The username (like a nickname, email address, etc.) or a UserInterface instance
28-
* @param mixed $credentials
29-
* @param string[] $roles
27+
* @param UserInterface $user
28+
* @param string[] $roles
3029
*
3130
* @throws \InvalidArgumentException
3231
*/
33-
public function __construct($user, $credentials, string $firewallName, array $roles = [])
32+
public function __construct($user, /*string*/ $firewallName, /*array*/ $roles = [])
3433
{
34+
if (\is_string($roles)) {
35+
trigger_deprecation('symfony/security-core', '5.4', 'The $credentials argument of "%s" is deprecated.', static::class.'::__construct');
36+
37+
$credentials = $firewallName;
38+
$firewallName = $roles;
39+
$roles = \func_num_args() > 3 ? func_get_arg(3) : [];
40+
}
41+
3542
parent::__construct($roles);
3643

3744
if ('' === $firewallName) {
3845
throw new \InvalidArgumentException('$firewallName must not be empty.');
3946
}
4047

4148
$this->setUser($user);
42-
$this->credentials = $credentials;
49+
$this->credentials = $credentials ?? null;
4350
$this->firewallName = $firewallName;
4451

4552
parent::setAuthenticated(\count($roles) > 0, false);
@@ -62,6 +69,8 @@ public function setAuthenticated(bool $isAuthenticated)
6269
*/
6370
public function getCredentials()
6471
{
72+
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s" is deprecated.', __METHOD__);
73+
6574
return $this->credentials;
6675
}
6776

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ CHANGELOG
44
5.4
55
---
66

7+
* Deprecate `AnonymousToken`, as the related authenticator was deprecated in 5.3
8+
* Deprecate `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
9+
* Deprecate returning `string|\Stringable` from `Token::getUser()` (it must return a `UserInterface`)
710
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor
811
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the
912
`$exceptionOnNoToken` argument to `false` of `AuthorizationChecker`

Security.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ public function getUser(): ?UserInterface
4242
}
4343

4444
$user = $token->getUser();
45+
// @deprecated since 5.4, $user will always be a UserInterface instance
4546
if (!\is_object($user)) {
4647
return null;
4748
}
4849

50+
// @deprecated since 5.4, $user will always be a UserInterface instance
4951
if (!$user instanceof UserInterface) {
5052
return null;
5153
}

Tests/Authentication/AuthenticationTrustResolverTest.php

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ public function testIsAnonymous()
2626
$this->assertFalse($resolver->isAnonymous($this->getToken()));
2727
$this->assertFalse($resolver->isAnonymous($this->getRememberMeToken()));
2828
$this->assertFalse($resolver->isAnonymous(new FakeCustomToken()));
29-
$this->assertTrue($resolver->isAnonymous(new RealCustomAnonymousToken()));
30-
$this->assertTrue($resolver->isAnonymous($this->getAnonymousToken()));
3129
}
3230

3331
public function testIsRememberMe()
@@ -36,7 +34,6 @@ public function testIsRememberMe()
3634

3735
$this->assertFalse($resolver->isRememberMe(null));
3836
$this->assertFalse($resolver->isRememberMe($this->getToken()));
39-
$this->assertFalse($resolver->isRememberMe($this->getAnonymousToken()));
4037
$this->assertFalse($resolver->isRememberMe(new FakeCustomToken()));
4138
$this->assertTrue($resolver->isRememberMe(new RealCustomRememberMeToken()));
4239
$this->assertTrue($resolver->isRememberMe($this->getRememberMeToken()));
@@ -47,9 +44,7 @@ public function testisFullFledged()
4744
$resolver = new AuthenticationTrustResolver();
4845

4946
$this->assertFalse($resolver->isFullFledged(null));
50-
$this->assertFalse($resolver->isFullFledged($this->getAnonymousToken()));
5147
$this->assertFalse($resolver->isFullFledged($this->getRememberMeToken()));
52-
$this->assertFalse($resolver->isFullFledged(new RealCustomAnonymousToken()));
5348
$this->assertFalse($resolver->isFullFledged(new RealCustomRememberMeToken()));
5449
$this->assertTrue($resolver->isFullFledged($this->getToken()));
5550
$this->assertTrue($resolver->isFullFledged(new FakeCustomToken()));
@@ -62,8 +57,6 @@ public function testIsAnonymousWithClassAsConstructorButStillExtending()
6257
$this->assertFalse($resolver->isAnonymous(null));
6358
$this->assertFalse($resolver->isAnonymous($this->getToken()));
6459
$this->assertFalse($resolver->isAnonymous($this->getRememberMeToken()));
65-
$this->assertTrue($resolver->isAnonymous($this->getAnonymousToken()));
66-
$this->assertTrue($resolver->isAnonymous(new RealCustomAnonymousToken()));
6760
}
6861

6962
public function testIsRememberMeWithClassAsConstructorButStillExtending()
@@ -72,7 +65,6 @@ public function testIsRememberMeWithClassAsConstructorButStillExtending()
7265

7366
$this->assertFalse($resolver->isRememberMe(null));
7467
$this->assertFalse($resolver->isRememberMe($this->getToken()));
75-
$this->assertFalse($resolver->isRememberMe($this->getAnonymousToken()));
7668
$this->assertTrue($resolver->isRememberMe($this->getRememberMeToken()));
7769
$this->assertTrue($resolver->isRememberMe(new RealCustomRememberMeToken()));
7870
}
@@ -82,13 +74,27 @@ public function testisFullFledgedWithClassAsConstructorButStillExtending()
8274
$resolver = $this->getResolver();
8375

8476
$this->assertFalse($resolver->isFullFledged(null));
85-
$this->assertFalse($resolver->isFullFledged($this->getAnonymousToken()));
8677
$this->assertFalse($resolver->isFullFledged($this->getRememberMeToken()));
87-
$this->assertFalse($resolver->isFullFledged(new RealCustomAnonymousToken()));
8878
$this->assertFalse($resolver->isFullFledged(new RealCustomRememberMeToken()));
8979
$this->assertTrue($resolver->isFullFledged($this->getToken()));
9080
}
9181

82+
/**
83+
* @group legacy
84+
*/
85+
public function testLegacy()
86+
{
87+
$resolver = $this->getResolver();
88+
89+
$this->assertTrue($resolver->isAnonymous($this->getAnonymousToken()));
90+
$this->assertTrue($resolver->isAnonymous($this->getRealCustomAnonymousToken()));
91+
92+
$this->assertFalse($resolver->isRememberMe($this->getAnonymousToken()));
93+
94+
$this->assertFalse($resolver->isFullFledged($this->getAnonymousToken()));
95+
$this->assertFalse($resolver->isFullFledged($this->getRealCustomAnonymousToken()));
96+
}
97+
9298
protected function getToken()
9399
{
94100
return $this->createMock(TokenInterface::class);
@@ -99,6 +105,15 @@ protected function getAnonymousToken()
99105
return $this->getMockBuilder(AnonymousToken::class)->setConstructorArgs(['', ''])->getMock();
100106
}
101107

108+
private function getRealCustomAnonymousToken()
109+
{
110+
return new class() extends AnonymousToken {
111+
public function __construct()
112+
{
113+
}
114+
};
115+
}
116+
102117
protected function getRememberMeToken()
103118
{
104119
return $this->getMockBuilder(RememberMeToken::class)->setMethods(['setPersistent'])->disableOriginalConstructor()->getMock();
@@ -192,13 +207,6 @@ public function setAttribute(string $name, $value)
192207
}
193208
}
194209

195-
class RealCustomAnonymousToken extends AnonymousToken
196-
{
197-
public function __construct()
198-
{
199-
}
200-
}
201-
202210
class RealCustomRememberMeToken extends RememberMeToken
203211
{
204212
public function __construct()

0 commit comments

Comments
 (0)