Skip to content

Commit 1d04928

Browse files
[Security] make TokenInterface::getUser() nullable to tell about unauthenticated tokens
1 parent fb30f91 commit 1d04928

File tree

11 files changed

+47
-56
lines changed

11 files changed

+47
-56
lines changed

Authentication/AuthenticationProviderManager.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function authenticate(TokenInterface $token)
111111
}
112112

113113
// @deprecated since Symfony 5.3
114-
if ($user = $result->getUser() instanceof UserInterface && !method_exists($result->getUser(), 'getUserIdentifier')) {
114+
if ($result->getUser() instanceof UserInterface && !method_exists($result->getUser(), 'getUserIdentifier')) {
115115
trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "getUserIdentifier(): string" in user class "%s" is deprecated. This method will replace "getUsername()" in Symfony 6.0.', get_debug_type($result->getUser()));
116116
}
117117

Authentication/AuthenticationTrustResolver.php

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\Security\Core\Authentication;
1313

1414
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
15-
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1615
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
1716
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1817

@@ -25,9 +24,9 @@ class AuthenticationTrustResolver implements AuthenticationTrustResolverInterfac
2524
{
2625
public function isAuthenticated(TokenInterface $token = null): bool
2726
{
28-
return null !== $token && !$token instanceof NullToken
27+
return $token && $token->getUser()
2928
// @deprecated since Symfony 5.4, TokenInterface::isAuthenticated() and AnonymousToken no longer exists in 6.0
30-
&& !$token instanceof AnonymousToken && $token->isAuthenticated(false);
29+
&& !$token instanceof AnonymousToken && (!method_exists($token, 'isAuthenticated') || $token->isAuthenticated(false));
3130
}
3231

3332
/**
@@ -39,34 +38,22 @@ public function isAnonymous(TokenInterface $token = null/*, $deprecation = true*
3938
trigger_deprecation('symfony/security-core', '5.4', 'The "%s()" method is deprecated, use "isAuthenticated()" or "isFullFledged()" if you want to check if the request is (fully) authenticated.', __METHOD__);
4039
}
4140

42-
if (null === $token) {
43-
return false;
44-
}
45-
46-
return $token instanceof AnonymousToken || $token instanceof NullToken;
41+
return $token && !$this->isAuthenticated($token);
4742
}
4843

4944
/**
5045
* {@inheritdoc}
5146
*/
5247
public function isRememberMe(TokenInterface $token = null)
5348
{
54-
if (null === $token) {
55-
return false;
56-
}
57-
58-
return $token instanceof RememberMeToken;
49+
return $token && $token instanceof RememberMeToken;
5950
}
6051

6152
/**
6253
* {@inheritdoc}
6354
*/
6455
public function isFullFledged(TokenInterface $token = null)
6556
{
66-
if (null === $token) {
67-
return false;
68-
}
69-
70-
return !$this->isAnonymous($token, false) && !$this->isRememberMe($token);
57+
return $token && !$this->isAnonymous($token, false) && !$this->isRememberMe($token);
7158
}
7259
}

Authentication/Token/AbstractToken.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public function setUser($user)
141141
public function isAuthenticated()
142142
{
143143
if (1 > \func_num_args() || func_get_arg(0)) {
144-
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated. In version 6.0, security tokens won\'t have an "authenticated" flag anymore and will always be considered authenticated.', __METHOD__);
144+
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated, return null from "getUser()" instead when a token is not authenticated.', __METHOD__);
145145
}
146146

147147
return $this->authenticated;
@@ -153,7 +153,7 @@ public function isAuthenticated()
153153
public function setAuthenticated(bool $authenticated)
154154
{
155155
if (2 > \func_num_args() || func_get_arg(1)) {
156-
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated. In version 6.0, security tokens won\'t have an "authenticated" state anymore and will always be considered as authenticated.', __METHOD__);
156+
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated', __METHOD__);
157157
}
158158

159159
$this->authenticated = $authenticated;

Authentication/Token/NullToken.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function getUserIdentifier(): string
5959
public function isAuthenticated()
6060
{
6161
if (0 === \func_num_args() || func_get_arg(0)) {
62-
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated. In version 6.0, security tokens won\'t have an "authenticated" flag anymore and will always be considered authenticated.', __METHOD__);
62+
trigger_deprecation('symfony/security-core', '5.4', 'Method "%s()" is deprecated, return null from "getUser()" instead when a token is not authenticated.', __METHOD__);
6363
}
6464

6565
return true;

Authentication/Token/TokenInterface.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function getCredentials();
5151
/**
5252
* Returns a user representation.
5353
*
54-
* @return UserInterface
54+
* @return UserInterface|null
5555
*
5656
* @see AbstractToken::setUser()
5757
*/
@@ -71,14 +71,14 @@ public function setUser($user);
7171
*
7272
* @return bool true if the token has been authenticated, false otherwise
7373
*
74-
* @deprecated since Symfony 5.4. In 6.0, security tokens will always be considered authenticated
74+
* @deprecated since Symfony 5.4, return null from "getUser()" instead when a token is not authenticated
7575
*/
7676
public function isAuthenticated();
7777

7878
/**
7979
* Sets the authenticated flag.
8080
*
81-
* @deprecated since Symfony 5.4. In 6.0, security tokens will always be considered authenticated
81+
* @deprecated since Symfony 5.4
8282
*/
8383
public function setAuthenticated(bool $isAuthenticated);
8484

Authorization/AuthorizationChecker.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ public function __construct(TokenStorageInterface $tokenStorage, /*AccessDecisio
6767
*/
6868
final public function isGranted($attribute, $subject = null): bool
6969
{
70-
if (null === ($token = $this->tokenStorage->getToken())) {
70+
$token = $this->tokenStorage->getToken();
71+
72+
if (!$token || !$token->getUser()) {
7173
if ($this->exceptionOnNoToken) {
7274
throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
7375
}
@@ -78,7 +80,7 @@ final public function isGranted($attribute, $subject = null): bool
7880
// @deprecated since Symfony 5.4
7981
if ($this->alwaysAuthenticate || !$authenticated = $token->isAuthenticated(false)) {
8082
if (!($authenticated ?? true)) {
81-
trigger_deprecation('symfony/core', '5.4', 'Returning false from "%s()" is deprecated and won\'t have any effect in Symfony 6.0 as security tokens will always be considered authenticated.');
83+
trigger_deprecation('symfony/core', '5.4', 'Returning false from "%s()" is deprecated, return null from "getUser()" instead.');
8284
}
8385
$this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token));
8486
}

Authorization/Voter/AuthenticatedVoter.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\Security\Core\Authorization\Voter;
1313

1414
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
15-
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1615
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
1716
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1817

@@ -96,7 +95,7 @@ public function vote(TokenInterface $token, $subject, array $attributes)
9695
if (self::IS_AUTHENTICATED === $attribute
9796
&& (method_exists($this->authenticationTrustResolver, 'isAuthenticated')
9897
? $this->authenticationTrustResolver->isAuthenticated($token)
99-
: (null !== $token && !$token instanceof NullToken))) {
98+
: ($token && $token->getUser()))) {
10099
return VoterInterface::ACCESS_GRANTED;
101100
}
102101

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ CHANGELOG
1717
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the
1818
`$exceptionOnNoToken` argument to `false` of `AuthorizationChecker`
1919
* Deprecate methods `TokenInterface::isAuthenticated()` and `setAuthenticated`,
20-
tokens will always be considered authenticated in 6.0
20+
return null from "getUser()" instead when a token is not authenticated
2121

2222
5.3
2323
---

Security.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,8 @@ public function getUser(): ?UserInterface
4242
}
4343

4444
$user = $token->getUser();
45-
// @deprecated since 5.4, $user will always be a UserInterface instance
46-
if (!\is_object($user)) {
47-
return null;
48-
}
4945

50-
// @deprecated since 5.4, $user will always be a UserInterface instance
46+
// @deprecated since Symfony 5.4, $user will always be a UserInterface instance
5147
if (!$user instanceof UserInterface) {
5248
return null;
5349
}

Tests/Authentication/AuthenticationTrustResolverTest.php

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
1818
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1919
use Symfony\Component\Security\Core\User\InMemoryUser;
20-
use Symfony\Component\Security\Core\User\User;
2120
use Symfony\Component\Security\Core\User\UserInterface;
2221

2322
class AuthenticationTrustResolverTest extends TestCase
@@ -29,7 +28,6 @@ public function testIsAnonymous()
2928
{
3029
$resolver = new AuthenticationTrustResolver();
3130
$this->assertFalse($resolver->isAnonymous(null));
32-
$this->assertFalse($resolver->isAnonymous($this->getToken()));
3331
$this->assertFalse($resolver->isAnonymous($this->getRememberMeToken()));
3432
$this->assertFalse($resolver->isAnonymous(new FakeCustomToken()));
3533
}
@@ -39,7 +37,6 @@ public function testIsRememberMe()
3937
$resolver = new AuthenticationTrustResolver();
4038

4139
$this->assertFalse($resolver->isRememberMe(null));
42-
$this->assertFalse($resolver->isRememberMe($this->getToken()));
4340
$this->assertFalse($resolver->isRememberMe(new FakeCustomToken()));
4441
$this->assertTrue($resolver->isRememberMe(new RealCustomRememberMeToken()));
4542
$this->assertTrue($resolver->isRememberMe($this->getRememberMeToken()));
@@ -52,7 +49,6 @@ public function testisFullFledged()
5249
$this->assertFalse($resolver->isFullFledged(null));
5350
$this->assertFalse($resolver->isFullFledged($this->getRememberMeToken()));
5451
$this->assertFalse($resolver->isFullFledged(new RealCustomRememberMeToken()));
55-
$this->assertTrue($resolver->isFullFledged($this->getToken()));
5652
$this->assertTrue($resolver->isFullFledged(new FakeCustomToken()));
5753
}
5854

@@ -72,7 +68,7 @@ public function testIsAnonymousWithClassAsConstructorButStillExtending()
7268
$resolver = $this->getResolver();
7369

7470
$this->assertFalse($resolver->isAnonymous(null));
75-
$this->assertFalse($resolver->isAnonymous($this->getToken()));
71+
$this->assertFalse($resolver->isAnonymous(new FakeCustomToken()));
7672
$this->assertFalse($resolver->isAnonymous($this->getRememberMeToken()));
7773
}
7874

@@ -81,7 +77,7 @@ public function testIsRememberMeWithClassAsConstructorButStillExtending()
8177
$resolver = $this->getResolver();
8278

8379
$this->assertFalse($resolver->isRememberMe(null));
84-
$this->assertFalse($resolver->isRememberMe($this->getToken()));
80+
$this->assertFalse($resolver->isRememberMe(new FakeCustomToken()));
8581
$this->assertTrue($resolver->isRememberMe($this->getRememberMeToken()));
8682
$this->assertTrue($resolver->isRememberMe(new RealCustomRememberMeToken()));
8783
}
@@ -93,7 +89,7 @@ public function testisFullFledgedWithClassAsConstructorButStillExtending()
9389
$this->assertFalse($resolver->isFullFledged(null));
9490
$this->assertFalse($resolver->isFullFledged($this->getRememberMeToken()));
9591
$this->assertFalse($resolver->isFullFledged(new RealCustomRememberMeToken()));
96-
$this->assertTrue($resolver->isFullFledged($this->getToken()));
92+
$this->assertTrue($resolver->isFullFledged(new FakeCustomToken()));
9793
}
9894

9995
/**
@@ -112,11 +108,6 @@ public function testLegacy()
112108
$this->assertFalse($resolver->isFullFledged($this->getRealCustomAnonymousToken()));
113109
}
114110

115-
protected function getToken()
116-
{
117-
return $this->createMock(TokenInterface::class);
118-
}
119-
120111
protected function getAnonymousToken()
121112
{
122113
return new AnonymousToken('secret', 'anon.');
@@ -133,7 +124,7 @@ public function __construct()
133124

134125
protected function getRememberMeToken()
135126
{
136-
$user = class_exists(InMemoryUser::class) ? new InMemoryUser('wouter', '', ['ROLE_USER']) : new User('wouter', '', ['ROLE_USER']);
127+
$user = new InMemoryUser('wouter', '', ['ROLE_USER']);
137128

138129
return new RememberMeToken($user, 'main', 'secret');
139130
}
@@ -179,6 +170,7 @@ public function getCredentials()
179170

180171
public function getUser(): UserInterface
181172
{
173+
return new InMemoryUser('wouter', '', ['ROLE_USER']);
182174
}
183175

184176
public function setUser($user)

0 commit comments

Comments
 (0)