Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d8e5aff

Browse filesBrowse files
committed
Removed AnonymousToken from the authenticator system
* Anonymous users are actual to unauthenticated users, both are now represented by no token * Added a PUBLIC_ACCESS Security attribute to be used in access_control * Deprecated "anonymous: lazy" in favor of "lazy: true"
1 parent c30d6f9 commit d8e5aff
Copy full SHA for d8e5aff

File tree

14 files changed

+142
-158
lines changed
Filter options

14 files changed

+142
-158
lines changed

‎UPGRADE-5.1.md

Copy file name to clipboardExpand all lines: UPGRADE-5.1.md
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ Routing
112112
SecurityBundle
113113
--------------
114114

115+
* Deprecated `anonymous: lazy` in favor of `lazy: true`
116+
117+
*Before*
118+
```yaml
119+
security:
120+
firewalls:
121+
main:
122+
anonymous: lazy
123+
```
124+
125+
*After*
126+
```yaml
127+
security:
128+
firewalls:
129+
main:
130+
anonymous: true
131+
lazy: true
132+
```
115133
* Marked the `AbstractFactory`, `AnonymousFactory`, `FormLoginFactory`, `FormLoginLdapFactory`, `GuardAuthenticationFactory`,
116134
`HttpBasicFactory`, `HttpBasicLdapFactory`, `JsonLoginFactory`, `JsonLoginLdapFactory`, `RememberMeFactory`, `RemoteUserFactory`
117135
and `X509Factory` as `@internal`. Instead of extending these classes, create your own implementation based on

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
197197
->scalarNode('entry_point')->end()
198198
->scalarNode('provider')->end()
199199
->booleanNode('stateless')->defaultFalse()->end()
200+
->booleanNode('lazy')->defaultFalse()->end()
200201
->scalarNode('context')->cannotBeEmpty()->end()
201202
->arrayNode('logout')
202203
->treatTrueLike([])

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AnonymousFactory.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AnonymousFactory.php
+3-11Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
1313

1414
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
15+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
1516
use Symfony\Component\DependencyInjection\ChildDefinition;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\DependencyInjection\Parameter;
@@ -46,16 +47,7 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider,
4647

4748
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
4849
{
49-
if (null === $config['secret']) {
50-
$config['secret'] = new Parameter('container.build_hash');
51-
}
52-
53-
$authenticatorId = 'security.authenticator.anonymous.'.$firewallName;
54-
$container
55-
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.anonymous'))
56-
->replaceArgument(0, $config['secret']);
57-
58-
return $authenticatorId;
50+
throw new InvalidConfigurationException(sprintf('The authenticator manager no longer has "anonymous" security. Please remove this option under the "%s" firewall'.($config['lazy'] ? ' and add "lazy: true"' : '').'.', $firewallName));
5951
}
6052

6153
public function getPosition()
@@ -76,7 +68,7 @@ public function addConfiguration(NodeDefinition $builder)
7668
->then(function ($v) { return ['lazy' => true]; })
7769
->end()
7870
->children()
79-
->booleanNode('lazy')->defaultFalse()->end()
71+
->booleanNode('lazy')->defaultFalse()->setDeprecated('symfony/security-bundle', '5.1', 'Using "anonymous: lazy" to make the firewall lazy is deprecated, use "lazy: true" instead.')->end()
8072
->scalarNode('secret')->defaultNull()->end()
8173
->end()
8274
;

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ public function load(array $configs, ContainerBuilder $container)
111111

112112
if ($this->authenticatorManagerEnabled = $config['enable_authenticator_manager']) {
113113
$loader->load('security_authenticator.xml');
114+
115+
// The authenticator system no longer has anonymous tokens. This makes sure AccessListener
116+
// and AuthorizationChecker do not throw AuthenticationCredentialsNotFoundException when no
117+
// token is available in the token storage.
118+
$container->getDefinition('security.access_listener')->setArgument(4, false);
119+
$container->getDefinition('security.authorization_checker')->setArgument(4, false);
120+
$container->getDefinition('security.authorization_checker')->setArgument(5, false);
114121
} else {
115122
$loader->load('security_legacy.xml');
116123
}
@@ -268,7 +275,8 @@ private function createFirewalls(array $config, ContainerBuilder $container)
268275
list($matcher, $listeners, $exceptionListener, $logoutListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId);
269276

270277
$contextId = 'security.firewall.map.context.'.$name;
271-
$context = new ChildDefinition($firewall['stateless'] || empty($firewall['anonymous']['lazy']) ? 'security.firewall.context' : 'security.firewall.lazy_context');
278+
$isLazy = !$firewall['stateless'] && (!empty($firewall['anonymous']['lazy']) || $firewall['lazy']);
279+
$context = new ChildDefinition($isLazy ? 'security.firewall.lazy_context' : 'security.firewall.context');
272280
$context = $container->setDefinition($contextId, $context);
273281
$context
274282
->replaceArgument(0, new IteratorArgument($listeners))

‎src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.xml
-7Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,6 @@
111111
<argument type="service" id="property_accessor" on-invalid="null" />
112112
</service>
113113

114-
<service id="security.authenticator.anonymous"
115-
class="Symfony\Component\Security\Http\Authenticator\AnonymousAuthenticator"
116-
abstract="true">
117-
<argument type="abstract">secret</argument>
118-
<argument type="service" id="security.untracked_token_storage" />
119-
</service>
120-
121114
<service id="security.authenticator.remember_me"
122115
class="Symfony\Component\Security\Http\Authenticator\RememberMeAuthenticator"
123116
abstract="true">

‎src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/Guarded/config.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/Guarded/config.yml
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ security:
2626
firewalls:
2727
secure:
2828
pattern: ^/
29-
anonymous: lazy
29+
anonymous: ~
30+
lazy: true
3031
stateless: false
3132
guard:
3233
authenticators:

‎src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ security:
2727
check_path: /login_check
2828
default_target_path: /profile
2929
logout: ~
30-
anonymous: lazy
30+
anonymous: ~
31+
lazy: true
3132

3233
# This firewall is here just to check its the logout functionality
3334
second_area:

‎src/Symfony/Component/Security/Core/Authorization/AuthorizationChecker.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/AuthorizationChecker.php
+9-3Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,30 @@ class AuthorizationChecker implements AuthorizationCheckerInterface
2929
private $accessDecisionManager;
3030
private $authenticationManager;
3131
private $alwaysAuthenticate;
32+
private $exceptionOnNoToken;
3233

33-
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, bool $alwaysAuthenticate = false)
34+
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, bool $alwaysAuthenticate = false, bool $exceptionOnNoToken = true)
3435
{
3536
$this->tokenStorage = $tokenStorage;
3637
$this->authenticationManager = $authenticationManager;
3738
$this->accessDecisionManager = $accessDecisionManager;
3839
$this->alwaysAuthenticate = $alwaysAuthenticate;
40+
$this->exceptionOnNoToken = $exceptionOnNoToken;
3941
}
4042

4143
/**
4244
* {@inheritdoc}
4345
*
44-
* @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token
46+
* @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token and $exceptionOnNoToken is set to true
4547
*/
4648
final public function isGranted($attribute, $subject = null): bool
4749
{
4850
if (null === ($token = $this->tokenStorage->getToken())) {
49-
throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
51+
if ($this->exceptionOnNoToken) {
52+
throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
53+
}
54+
55+
return false;
5056
}
5157

5258
if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {

‎src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ public function testVoteWithoutAuthenticationToken()
7373
$this->authorizationChecker->isGranted('ROLE_FOO');
7474
}
7575

76+
public function testVoteWithoutAuthenticationTokenAndExceptionOnNoTokenIsFalse()
77+
{
78+
$authorizationChecker = new AuthorizationChecker($this->tokenStorage, $this->authenticationManager, $this->accessDecisionManager, false, false);
79+
80+
$this->assertFalse($authorizationChecker->isGranted('ROLE_FOO'));
81+
}
82+
7683
/**
7784
* @dataProvider isGrantedProvider
7885
*/

‎src/Symfony/Component/Security/Http/Authenticator/AnonymousAuthenticator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/Authenticator/AnonymousAuthenticator.php
-67Lines changed: 0 additions & 67 deletions
This file was deleted.

‎src/Symfony/Component/Security/Http/Firewall/AccessListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/Firewall/AccessListener.php
+38-11Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,21 @@
3131
*/
3232
class AccessListener extends AbstractListener
3333
{
34+
const PUBLIC_ACCESS = 'PUBLIC_ACCESS';
35+
3436
private $tokenStorage;
3537
private $accessDecisionManager;
3638
private $map;
3739
private $authManager;
40+
private $exceptionOnNoToken;
3841

39-
public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager)
42+
public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager, bool $exceptionOnNoToken = true)
4043
{
4144
$this->tokenStorage = $tokenStorage;
4245
$this->accessDecisionManager = $accessDecisionManager;
4346
$this->map = $map;
4447
$this->authManager = $authManager;
48+
$this->exceptionOnNoToken = $exceptionOnNoToken;
4549
}
4650

4751
/**
@@ -52,18 +56,18 @@ public function supports(Request $request): ?bool
5256
[$attributes] = $this->map->getPatterns($request);
5357
$request->attributes->set('_access_control_attributes', $attributes);
5458

55-
return $attributes && [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] !== $attributes ? true : null;
59+
return $attributes && ([AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] !== $attributes && [self::PUBLIC_ACCESS] !== $attributes) ? true : null;
5660
}
5761

5862
/**
5963
* Handles access authorization.
6064
*
6165
* @throws AccessDeniedException
62-
* @throws AuthenticationCredentialsNotFoundException
66+
* @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token and $exceptionOnNoToken is set to true
6367
*/
6468
public function authenticate(RequestEvent $event)
6569
{
66-
if (!$event instanceof LazyResponseEvent && null === $token = $this->tokenStorage->getToken()) {
70+
if (!$event instanceof LazyResponseEvent && null === ($token = $this->tokenStorage->getToken()) && $this->exceptionOnNoToken) {
6771
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
6872
}
6973

@@ -76,8 +80,26 @@ public function authenticate(RequestEvent $event)
7680
return;
7781
}
7882

79-
if ($event instanceof LazyResponseEvent && null === $token = $this->tokenStorage->getToken()) {
80-
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
83+
if ($event instanceof LazyResponseEvent) {
84+
$token = $this->tokenStorage->getToken();
85+
}
86+
87+
if (null === $token) {
88+
if ($this->exceptionOnNoToken) {
89+
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
90+
}
91+
92+
if ([AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes) {
93+
trigger_deprecation('symfony/security-http', '5.1', 'Using "IS_AUTHENTICATED_ANONYMOUSLY" in your access_control rules when using the authenticator Security system is deprecated, use "PUBLIC_ACCESS" instead.');
94+
95+
return;
96+
}
97+
98+
if ([self::PUBLIC_ACCESS] === $attributes) {
99+
return;
100+
}
101+
102+
throw $this->createAccessDeniedException($request, $attributes);
81103
}
82104

83105
if (!$token->isAuthenticated()) {
@@ -86,11 +108,16 @@ public function authenticate(RequestEvent $event)
86108
}
87109

88110
if (!$this->accessDecisionManager->decide($token, $attributes, $request, true)) {
89-
$exception = new AccessDeniedException();
90-
$exception->setAttributes($attributes);
91-
$exception->setSubject($request);
92-
93-
throw $exception;
111+
throw $this->createAccessDeniedException($request, $attributes);
94112
}
95113
}
114+
115+
private function createAccessDeniedException(Request $request, array $attributes)
116+
{
117+
$exception = new AccessDeniedException();
118+
$exception->setAttributes($attributes);
119+
$exception->setSubject($request);
120+
121+
return $exception;
122+
}
96123
}

‎src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ private function handleAccessDeniedException(ExceptionEvent $event, AccessDenied
144144

145145
try {
146146
$insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception);
147-
$insufficientAuthenticationException->setToken($token);
147+
if (null !== $token) {
148+
$insufficientAuthenticationException->setToken($token);
149+
}
148150

149151
$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
150152
} catch (\Exception $e) {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.