Skip to content

Commit 5a4acb3

Browse files
committed
[Security] Deprecate remaining anonymous checks
1 parent cc4cc00 commit 5a4acb3

File tree

8 files changed

+95
-18
lines changed

8 files changed

+95
-18
lines changed

Authentication/AuthenticationTrustResolver.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,22 @@
2323
*/
2424
class AuthenticationTrustResolver implements AuthenticationTrustResolverInterface
2525
{
26+
public function isAuthenticated(TokenInterface $token = null): bool
27+
{
28+
return null !== $token && !$token instanceof NullToken
29+
// @deprecated since Symfony 5.4, TokenInterface::isAuthenticated() and AnonymousToken no longer exists in 6.0
30+
&& !$token instanceof AnonymousToken && $token->isAuthenticated(false);
31+
}
32+
2633
/**
2734
* {@inheritdoc}
2835
*/
29-
public function isAnonymous(TokenInterface $token = null)
36+
public function isAnonymous(TokenInterface $token = null/*, $deprecation = true*/)
3037
{
38+
if (1 === \func_num_args() || false !== func_get_arg(1)) {
39+
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__);
40+
}
41+
3142
if (null === $token) {
3243
return false;
3344
}
@@ -56,6 +67,6 @@ public function isFullFledged(TokenInterface $token = null)
5667
return false;
5768
}
5869

59-
return !$this->isAnonymous($token) && !$this->isRememberMe($token);
70+
return !$this->isAnonymous($token, false) && !$this->isRememberMe($token);
6071
}
6172
}

Authentication/AuthenticationTrustResolverInterface.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* Interface for resolving the authentication status of a given token.
1818
*
1919
* @author Johannes M. Schmitt <[email protected]>
20+
*
21+
* @method bool isAuthenticated(TokenInterface $token = null)
2022
*/
2123
interface AuthenticationTrustResolverInterface
2224
{
@@ -27,6 +29,8 @@ interface AuthenticationTrustResolverInterface
2729
* If null is passed, the method must return false.
2830
*
2931
* @return bool
32+
*
33+
* @deprecated since Symfony 5.4, use !isAuthenticated() instead
3034
*/
3135
public function isAnonymous(TokenInterface $token = null);
3236

Authorization/ExpressionLanguageProvider.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
1515
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
16+
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
1617

1718
/**
1819
* Define some ExpressionLanguage functions.
@@ -25,15 +26,18 @@ public function getFunctions()
2526
{
2627
return [
2728
new ExpressionFunction('is_anonymous', function () {
28-
return '$token && $auth_checker->isGranted("IS_ANONYMOUS")';
29+
return 'trigger_deprecation("symfony/security-core", "5.4", "The \"is_anonymous()\" expression function is deprecated.") || ($token && $auth_checker->isGranted("IS_ANONYMOUS"))';
2930
}, function (array $variables) {
31+
trigger_deprecation('symfony/security-core', '5.4', 'The "is_anonymous()" expression function is deprecated.');
32+
3033
return $variables['token'] && $variables['auth_checker']->isGranted('IS_ANONYMOUS');
3134
}),
3235

36+
// @deprecated remove the ternary and always use IS_AUTHENTICATED in 6.0
3337
new ExpressionFunction('is_authenticated', function () {
34-
return '$token && !$auth_checker->isGranted("IS_ANONYMOUS")';
38+
return 'defined("'.AuthenticatedVoter::class.'::IS_AUTHENTICATED") ? $auth_checker->isGranted("IS_AUTHENTICATED") : ($token && !$auth_checker->isGranted("IS_ANONYMOUS"))';
3539
}, function (array $variables) {
36-
return $variables['token'] && !$variables['auth_checker']->isGranted('IS_ANONYMOUS');
40+
return \defined(AuthenticatedVoter::class.'::IS_AUTHENTICATED') ? $variables['auth_checker']->isGranted('IS_AUTHENTICATED') : ($variables['token'] && !$variables['auth_checker']->isGranted('IS_ANONYMOUS'));
3741
}),
3842

3943
new ExpressionFunction('is_fully_authenticated', function () {

Authorization/Voter/AuthenticatedVoter.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
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;
1516
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
1617
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1718

1819
/**
1920
* AuthenticatedVoter votes if an attribute like IS_AUTHENTICATED_FULLY,
20-
* IS_AUTHENTICATED_REMEMBERED, or IS_AUTHENTICATED_ANONYMOUSLY is present.
21+
* IS_AUTHENTICATED_REMEMBERED, IS_AUTHENTICATED is present.
2122
*
2223
* This list is most restrictive to least restrictive checking.
2324
*
@@ -28,8 +29,15 @@ class AuthenticatedVoter implements VoterInterface
2829
{
2930
public const IS_AUTHENTICATED_FULLY = 'IS_AUTHENTICATED_FULLY';
3031
public const IS_AUTHENTICATED_REMEMBERED = 'IS_AUTHENTICATED_REMEMBERED';
32+
/**
33+
* @deprecated since Symfony 5.4
34+
*/
3135
public const IS_AUTHENTICATED_ANONYMOUSLY = 'IS_AUTHENTICATED_ANONYMOUSLY';
36+
/**
37+
* @deprecated since Symfony 5.4
38+
*/
3239
public const IS_ANONYMOUS = 'IS_ANONYMOUS';
40+
public const IS_AUTHENTICATED = 'IS_AUTHENTICATED';
3341
public const IS_IMPERSONATOR = 'IS_IMPERSONATOR';
3442
public const IS_REMEMBERED = 'IS_REMEMBERED';
3543
public const PUBLIC_ACCESS = 'PUBLIC_ACCESS';
@@ -55,6 +63,7 @@ public function vote(TokenInterface $token, $subject, array $attributes)
5563
if (null === $attribute || (self::IS_AUTHENTICATED_FULLY !== $attribute
5664
&& self::IS_AUTHENTICATED_REMEMBERED !== $attribute
5765
&& self::IS_AUTHENTICATED_ANONYMOUSLY !== $attribute
66+
&& self::IS_AUTHENTICATED !== $attribute
5867
&& self::IS_ANONYMOUS !== $attribute
5968
&& self::IS_IMPERSONATOR !== $attribute
6069
&& self::IS_REMEMBERED !== $attribute)) {
@@ -78,6 +87,16 @@ public function vote(TokenInterface $token, $subject, array $attributes)
7887
&& ($this->authenticationTrustResolver->isAnonymous($token)
7988
|| $this->authenticationTrustResolver->isRememberMe($token)
8089
|| $this->authenticationTrustResolver->isFullFledged($token))) {
90+
trigger_deprecation('symfony/security-core', '5.4', 'The "IS_AUTHENTICATED_ANONYMOUSLY" security attribute is deprecated, use "IS_AUTHENTICATED" or "IS_AUTHENTICATED_FULLY" instead if you want to check if the request is (fully) authenticated.');
91+
92+
return VoterInterface::ACCESS_GRANTED;
93+
}
94+
95+
// @deprecated $this->authenticationTrustResolver must implement isAuthenticated() in 6.0
96+
if (self::IS_AUTHENTICATED === $attribute
97+
&& (method_exists($this->authenticationTrustResolver, 'isAuthenticated')
98+
? $this->authenticationTrustResolver->isAuthenticated($token)
99+
: (null !== $token && !$token instanceof NullToken))) {
81100
return VoterInterface::ACCESS_GRANTED;
82101
}
83102

@@ -86,6 +105,8 @@ public function vote(TokenInterface $token, $subject, array $attributes)
86105
}
87106

88107
if (self::IS_ANONYMOUS === $attribute && $this->authenticationTrustResolver->isAnonymous($token)) {
108+
trigger_deprecation('symfony/security-core', '5.4', 'The "IS_ANONYMOUSLY" security attribute is deprecated, anonymous no longer exists in version 6.');
109+
89110
return VoterInterface::ACCESS_GRANTED;
90111
}
91112

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ CHANGELOG
77
* Deprecate `AnonymousToken`, as the related authenticator was deprecated in 5.3
88
* Deprecate `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
99
* Deprecate returning `string|\Stringable` from `Token::getUser()` (it must return a `UserInterface`)
10+
* Deprecate `AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY` and `AuthenticatedVoter::IS_ANONYMOUS`,
11+
use `AuthenticatedVoter::IS_AUTHENTICATED_FULLY` or `AuthenticatedVoter::IS_AUTHENTICATED` instead.
12+
* Deprecate `AuthenticationTrustResolverInterface::isAnonymous()` and the `is_anonymous()` expression
13+
function as anonymous no longer exists in version 6, use the `isFullFledged()` or the new
14+
`isAuthenticated()` instead if you want to check if the request is (fully) authenticated.
1015
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor
1116
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the
1217
`$exceptionOnNoToken` argument to `false` of `AuthorizationChecker`

Tests/Authentication/AuthenticationTrustResolverTest.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
1717
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
1818
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
19+
use Symfony\Component\Security\Core\User\InMemoryUser;
20+
use Symfony\Component\Security\Core\User\User;
1921

2022
class AuthenticationTrustResolverTest extends TestCase
2123
{
24+
/**
25+
* @group legacy
26+
*/
2227
public function testIsAnonymous()
2328
{
2429
$resolver = new AuthenticationTrustResolver();
@@ -50,6 +55,17 @@ public function testisFullFledged()
5055
$this->assertTrue($resolver->isFullFledged(new FakeCustomToken()));
5156
}
5257

58+
public function testIsAuthenticated()
59+
{
60+
$resolver = new AuthenticationTrustResolver();
61+
$this->assertFalse($resolver->isAuthenticated(null));
62+
$this->assertTrue($resolver->isAuthenticated($this->getRememberMeToken()));
63+
$this->assertTrue($resolver->isAuthenticated(new FakeCustomToken()));
64+
}
65+
66+
/**
67+
* @group legacy
68+
*/
5369
public function testIsAnonymousWithClassAsConstructorButStillExtending()
5470
{
5571
$resolver = $this->getResolver();
@@ -102,7 +118,7 @@ protected function getToken()
102118

103119
protected function getAnonymousToken()
104120
{
105-
return $this->getMockBuilder(AnonymousToken::class)->setConstructorArgs(['', ''])->getMock();
121+
return new AnonymousToken('secret', 'anon.');
106122
}
107123

108124
private function getRealCustomAnonymousToken()
@@ -116,7 +132,9 @@ public function __construct()
116132

117133
protected function getRememberMeToken()
118134
{
119-
return $this->getMockBuilder(RememberMeToken::class)->setMethods(['setPersistent'])->disableOriginalConstructor()->getMock();
135+
$user = class_exists(InMemoryUser::class) ? new InMemoryUser('wouter', '', ['ROLE_USER']) : new User('wouter', '', ['ROLE_USER']);
136+
137+
return new RememberMeToken($user, 'main', 'secret');
120138
}
121139

122140
protected function getResolver()
@@ -176,6 +194,7 @@ public function getUserIdentifier(): string
176194

177195
public function isAuthenticated(): bool
178196
{
197+
return true;
179198
}
180199

181200
public function setAuthenticated(bool $isAuthenticated)

Tests/Authorization/ExpressionLanguageTest.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class ExpressionLanguageTest extends TestCase
2828
{
2929
/**
3030
* @dataProvider provider
31-
* @dataProvider legacyProvider
3231
*/
3332
public function testIsAuthenticated($token, $expression, $result)
3433
{
@@ -56,19 +55,16 @@ public function provider()
5655
$usernamePasswordToken = new UsernamePasswordToken($user, 'firewall-name', $roles);
5756

5857
return [
59-
[$noToken, 'is_anonymous()', false],
6058
[$noToken, 'is_authenticated()', false],
6159
[$noToken, 'is_fully_authenticated()', false],
6260
[$noToken, 'is_remember_me()', false],
6361

64-
[$rememberMeToken, 'is_anonymous()', false],
6562
[$rememberMeToken, 'is_authenticated()', true],
6663
[$rememberMeToken, 'is_fully_authenticated()', false],
6764
[$rememberMeToken, 'is_remember_me()', true],
6865
[$rememberMeToken, "is_granted('ROLE_FOO')", false],
6966
[$rememberMeToken, "is_granted('ROLE_USER')", true],
7067

71-
[$usernamePasswordToken, 'is_anonymous()', false],
7268
[$usernamePasswordToken, 'is_authenticated()', true],
7369
[$usernamePasswordToken, 'is_fully_authenticated()', true],
7470
[$usernamePasswordToken, 'is_remember_me()', false],
@@ -77,11 +73,22 @@ public function provider()
7773
];
7874
}
7975

76+
/**
77+
* @dataProvider legacyProvider
78+
* @group legacy
79+
*/
80+
public function testLegacyIsAuthenticated($token, $expression, $result)
81+
{
82+
$this->testIsAuthenticated($token, $expression, $result);
83+
}
84+
8085
/**
8186
* @group legacy
8287
*/
8388
public function legacyProvider()
8489
{
90+
$roles = ['ROLE_USER', 'ROLE_ADMIN'];
91+
$user = new InMemoryUser('username', 'password', $roles);
8592
$anonymousToken = new AnonymousToken('firewall', 'anon.');
8693

8794
return [
@@ -90,6 +97,10 @@ public function legacyProvider()
9097
[$anonymousToken, 'is_fully_authenticated()', false],
9198
[$anonymousToken, 'is_remember_me()', false],
9299
[$anonymousToken, "is_granted('ROLE_USER')", false],
100+
101+
[null, 'is_anonymous()', false],
102+
[new RememberMeToken($user, 'firewall-name', 'firewall'), 'is_anonymous()', false],
103+
[new UsernamePasswordToken($user, 'firewall-name', $roles), 'is_anonymous()', false],
93104
];
94105
}
95106
}

Tests/Authorization/Voter/AuthenticatedVoterTest.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,12 @@ public function getVoteTests()
4040
['remembered', [], VoterInterface::ACCESS_ABSTAIN],
4141
['remembered', ['FOO'], VoterInterface::ACCESS_ABSTAIN],
4242

43-
['fully', ['IS_AUTHENTICATED_ANONYMOUSLY'], VoterInterface::ACCESS_GRANTED],
44-
['remembered', ['IS_AUTHENTICATED_ANONYMOUSLY'], VoterInterface::ACCESS_GRANTED],
45-
4643
['fully', ['IS_AUTHENTICATED_REMEMBERED'], VoterInterface::ACCESS_GRANTED],
4744
['remembered', ['IS_AUTHENTICATED_REMEMBERED'], VoterInterface::ACCESS_GRANTED],
4845

4946
['fully', ['IS_AUTHENTICATED_FULLY'], VoterInterface::ACCESS_GRANTED],
5047
['remembered', ['IS_AUTHENTICATED_FULLY'], VoterInterface::ACCESS_DENIED],
5148

52-
['fully', ['IS_ANONYMOUS'], VoterInterface::ACCESS_DENIED],
53-
['remembered', ['IS_ANONYMOUS'], VoterInterface::ACCESS_DENIED],
54-
5549
['fully', ['IS_IMPERSONATOR'], VoterInterface::ACCESS_DENIED],
5650
['remembered', ['IS_IMPERSONATOR'], VoterInterface::ACCESS_DENIED],
5751
['impersonated', ['IS_IMPERSONATOR'], VoterInterface::ACCESS_GRANTED],
@@ -77,6 +71,14 @@ public function getLegacyVoteTests()
7771
['anonymously', ['IS_AUTHENTICATED_FULLY'], VoterInterface::ACCESS_DENIED],
7872
['anonymously', ['IS_ANONYMOUS'], VoterInterface::ACCESS_GRANTED],
7973
['anonymously', ['IS_IMPERSONATOR'], VoterInterface::ACCESS_DENIED],
74+
75+
['fully', ['IS_ANONYMOUS'], VoterInterface::ACCESS_DENIED],
76+
['remembered', ['IS_ANONYMOUS'], VoterInterface::ACCESS_DENIED],
77+
['anonymously', ['IS_ANONYMOUS'], VoterInterface::ACCESS_GRANTED],
78+
79+
['fully', ['IS_AUTHENTICATED_ANONYMOUSLY'], VoterInterface::ACCESS_GRANTED],
80+
['remembered', ['IS_AUTHENTICATED_ANONYMOUSLY'], VoterInterface::ACCESS_GRANTED],
81+
['anonymously', ['IS_AUTHENTICATED_ANONYMOUSLY'], VoterInterface::ACCESS_GRANTED],
8082
];
8183
}
8284

0 commit comments

Comments
 (0)