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

Skip to content

Commit 016074c

Browse files
committed
feature #42510 [Security] Deprecate remaining anonymous checks (wouterj)
This PR was merged into the 5.4 branch. Discussion ---------- [Security] Deprecate remaining anonymous checks | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | yes | Tickets | Ref #41613 | License | MIT | Doc PR | tbd Deprecates the remaining checks for anonymous found in #41613. It's WIP because the tests are failing until #42423 is merged and this PR is rebased (didn't update one test to avoid merge conflicts). Besides this, it also introduced `IS_AUTHENTICATED` and `AuthenticationTrustResolver::isAutenticated()`. Previously, `IS_AUTHENTICATED_ANONYMOUSLY` was considered to be the "bottom type" for authenticated requests. As this is no longer true, `IS_AUTHENTICATED_REMEMBERME` is now the new "bottom type". I suggest we use an explicit bottom type (the ones introduced) instead to avoid another such update if we change something with remember me. It's also more clear on the exact intent of the check. Commits ------- e3aca7f [Security] Deprecate remaining anonymous checks
2 parents 76a7fe7 + e3aca7f commit 016074c

File tree

18 files changed

+158
-27
lines changed

18 files changed

+158
-27
lines changed

UPGRADE-5.4.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,30 @@ Security
6262
* Deprecate `AnonymousToken`, as the related authenticator was deprecated in 5.3
6363
* Deprecate `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
6464
* Deprecate not returning an `UserInterface` from `Token::getUser()`
65+
* Deprecate `AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY` and `AuthenticatedVoter::IS_ANONYMOUS`,
66+
use `AuthenticatedVoter::PUBLIC_ACCESS` instead.
67+
68+
Before:
69+
```yaml
70+
# config/packages/security.yaml
71+
security:
72+
# ...
73+
access_control:
74+
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
75+
```
76+
77+
After:
78+
```yaml
79+
# config/packages/security.yaml
80+
security:
81+
# ...
82+
access_control:
83+
- { path: ^/login, roles: PUBLIC_ACCESS }
84+
```
85+
86+
* Deprecate `AuthenticationTrustResolverInterface::isAnonymous()` and the `is_anonymous()` expression function
87+
as anonymous no longer exists in version 6, use the `isFullFledged()` or the new `isAuthenticated()` instead
88+
if you want to check if the request is (fully) authenticated.
6589
* Deprecate the `$authManager` argument of `AccessListener`, the argument will be removed
6690
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor, the argument will be removed
6791
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the

UPGRADE-6.0.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,30 @@ Security
210210
* Remove `AnonymousToken`
211211
* Remove `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
212212
* Restrict the return type of `Token::getUser()` to `UserInterface` (removing `string|\Stringable`)
213+
* Remove `AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY` and `AuthenticatedVoter::IS_ANONYMOUS`,
214+
use `AuthenticatedVoter::PUBLIC_ACCESS` instead.
215+
216+
Before:
217+
```yaml
218+
# config/packages/security.yaml
219+
security:
220+
# ...
221+
access_control:
222+
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
223+
```
224+
225+
After:
226+
```yaml
227+
# config/packages/security.yaml
228+
security:
229+
# ...
230+
access_control:
231+
- { path: ^/login, roles: PUBLIC_ACCESS }
232+
```
233+
234+
* Remove `AuthenticationTrustResolverInterface::isAnonymous()` and the `is_anonymous()` expression function
235+
as anonymous no longer exists in version 6, use the `isFullFledged()` or the new `isAuthenticated()` instead
236+
if you want to check if the request is (fully) authenticated.
213237
* Remove the 4th and 5th argument of `AuthorizationChecker`
214238
* Remove the 5th argument of `AccessListener`
215239
* Remove class `User`, use `InMemoryUser` or your own implementation instead.

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
5.4
55
---
66

7+
* Deprecate `FirewallConfig::allowsAnonymous()` and the `allows_anonymous` from the data collector data, there will be no anonymous concept as of version 6.
78
* Deprecate not setting `$authenticatorManagerEnabled` to `true` in `SecurityDataCollector` and `DebugFirewallCommand`
89
* Deprecate `SecurityFactoryInterface` and `SecurityExtension::addSecurityListenerFactory()` in favor of
910
`AuthenticatorFactoryInterface` and `SecurityExtension::addAuthenticatorFactory()`

src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public function collect(Request $request, Response $response, \Throwable $except
184184
if (null !== $firewallConfig) {
185185
$this->data['firewall'] = [
186186
'name' => $firewallConfig->getName(),
187-
'allows_anonymous' => $firewallConfig->allowsAnonymous(),
187+
'allows_anonymous' => $this->authenticatorManagerEnabled ? false : $firewallConfig->allowsAnonymous(),
188188
'request_matcher' => $firewallConfig->getRequestMatcher(),
189189
'security_enabled' => $firewallConfig->isSecurityEnabled(),
190190
'stateless' => $firewallConfig->isStateless(),

src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,13 @@ public function isSecurityEnabled(): bool
6464
return $this->securityEnabled;
6565
}
6666

67+
/**
68+
* @deprecated since Symfony 5.4
69+
*/
6770
public function allowsAnonymous(): bool
6871
{
72+
trigger_deprecation('symfony/security-bundle', '5.4', 'The "%s()" method is deprecated.', __METHOD__);
73+
6974
return \in_array('anonymous', $this->listeners, true);
7075
}
7176

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ public function testGetFirewall()
141141
$collected = $collector->getFirewall();
142142

143143
$this->assertSame($firewallConfig->getName(), $collected['name']);
144-
$this->assertSame($firewallConfig->allowsAnonymous(), $collected['allows_anonymous']);
145144
$this->assertSame($firewallConfig->getRequestMatcher(), $collected['request_matcher']);
146145
$this->assertSame($firewallConfig->isSecurityEnabled(), $collected['security_enabled']);
147146
$this->assertSame($firewallConfig->isStateless(), $collected['stateless']);

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/base_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ security:
5353
- { path: ^/secured-by-one-env-placeholder-and-one-real-ip$, ips: ['%env(APP_IP)%', 198.51.100.0], roles: IS_AUTHENTICATED_ANONYMOUSLY }
5454
- { path: ^/secured-by-one-env-placeholder-multiple-ips-and-one-real-ip$, ips: ['%env(APP_IPS)%', 198.51.100.0], roles: IS_AUTHENTICATED_ANONYMOUSLY }
5555
- { path: ^/highly_protected_resource$, roles: IS_ADMIN }
56-
- { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and request.headers.get('user-agent') matches '/Firefox/i') or is_granted('ROLE_USER')" }
56+
- { path: ^/protected-via-expression$, allow_if: "(!is_authenticated() and request.headers.get('user-agent') matches '/Firefox/i') or is_granted('ROLE_USER')" }
5757
- { path: .*, roles: IS_AUTHENTICATED_FULLY }

src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class FirewallConfigTest extends TestCase
1818
{
1919
public function testGetters()
2020
{
21-
$listeners = ['logout', 'remember_me', 'anonymous'];
21+
$listeners = ['logout', 'remember_me'];
2222
$options = [
2323
'request_matcher' => 'foo_request_matcher',
2424
'security' => false,
@@ -57,7 +57,6 @@ public function testGetters()
5757
$this->assertSame($options['access_denied_handler'], $config->getAccessDeniedHandler());
5858
$this->assertSame($options['access_denied_url'], $config->getAccessDeniedUrl());
5959
$this->assertSame($options['user_checker'], $config->getUserChecker());
60-
$this->assertTrue($config->allowsAnonymous());
6160
$this->assertSame($listeners, $config->getListeners());
6261
$this->assertSame($options['switch_user'], $config->getSwitchUser());
6362
}

src/Symfony/Component/Security/Core/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
}

src/Symfony/Component/Security/Core/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

src/Symfony/Component/Security/Core/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 () {

src/Symfony/Component/Security/Core/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

src/Symfony/Component/Security/Core/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`

src/Symfony/Component/Security/Core/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)

0 commit comments

Comments
 (0)