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

Skip to content

Commit 2000e06

Browse files
committed
Added support for lazy firewalls
1 parent ebd1f71 commit 2000e06

File tree

7 files changed

+88
-65
lines changed

7 files changed

+88
-65
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,6 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
440440
->setDefinition('security.firewall.authenticator.'.$id, new ChildDefinition('security.firewall.authenticator'))
441441
->replaceArgument(2, new Reference('security.firewall.authenticator.'.$id.'.locator'))
442442
->replaceArgument(3, $id)
443-
->addTag('kernel.event_listener', ['event' => KernelEvents::REQUEST])
444443
;
445444

446445
$listeners[] = new Reference('security.firewall.authenticator.'.$id);

src/Symfony/Bundle/SecurityBundle/EventListener/LazyAuthenticatorManagerListener.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,39 @@
2626
*/
2727
class LazyAuthenticatorManagerListener extends AuthenticatorManagerListener
2828
{
29-
private $guardLocator;
29+
private $authenticatorLocator;
3030

3131
public function __construct(
3232
AuthenticationManagerInterface $authenticationManager,
3333
AuthenticatorHandler $authenticatorHandler,
34-
ServiceLocator $guardLocator,
34+
ServiceLocator $authenticatorLocator,
3535
string $providerKey,
3636
EventDispatcherInterface $eventDispatcher,
3737
?LoggerInterface $logger = null
3838
) {
3939
parent::__construct($authenticationManager, $authenticatorHandler, [], $providerKey, $eventDispatcher, $logger);
4040

41-
$this->guardLocator = $guardLocator;
41+
$this->authenticatorLocator = $authenticatorLocator;
4242
}
4343

4444
protected function getSupportingAuthenticators(Request $request): array
4545
{
46-
$guardAuthenticators = [];
47-
foreach ($this->guardLocator->getProvidedServices() as $key => $type) {
48-
$guardAuthenticator = $this->guardLocator->get($key);
46+
$authenticators = [];
47+
$lazy = true;
48+
foreach ($this->authenticatorLocator->getProvidedServices() as $key => $type) {
49+
$authenticator = $this->authenticatorLocator->get($key);
4950
if (null !== $this->logger) {
50-
$this->logger->debug('Checking support on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
51+
$this->logger->debug('Checking support on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($authenticator)]);
5152
}
5253

53-
if ($guardAuthenticator->supports($request)) {
54-
$guardAuthenticators[$key] = $guardAuthenticator;
54+
if (false !== $supports = $authenticator->supports($request)) {
55+
$authenticators[$key] = $authenticator;
56+
$lazy = $lazy && null === $supports;
5557
} elseif (null !== $this->logger) {
56-
$this->logger->debug('Guard authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
58+
$this->logger->debug('Guard authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($authenticator)]);
5759
}
5860
}
5961

60-
return $guardAuthenticators;
62+
return [$authenticators, $lazy];
6163
}
6264
}

src/Symfony/Bundle/SecurityBundle/Resources/config/authenticators.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
class="Symfony\Component\Security\Http\Authenticator\AnonymousAuthenticator"
8181
abstract="true">
8282
<argument /> <!-- secret -->
83-
<argument type="service" id="security.token_storage" />
83+
<argument type="service" id="security.untracked_token_storage" />
8484
</service>
8585
</services>
8686
</container>

src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636
*/
3737
class GuardAuthenticationListener extends AbstractListener
3838
{
39-
use AuthenticatorManagerListenerTrait;
40-
4139
private $guardHandler;
4240
private $authenticationManager;
4341
private $providerKey;
@@ -77,7 +75,20 @@ public function supports(Request $request): ?bool
7775
$this->logger->debug('Checking for guard authentication credentials.', $context);
7876
}
7977

80-
$guardAuthenticators = $this->getSupportingAuthenticators($request);
78+
79+
$guardAuthenticators = [];
80+
foreach ($this->authenticators as $key => $authenticator) {
81+
if (null !== $this->logger) {
82+
$this->logger->debug('Checking support on authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($authenticator)]);
83+
}
84+
85+
if ($authenticator->supports($request)) {
86+
$guardAuthenticators[$key] = $authenticator;
87+
} elseif (null !== $this->logger) {
88+
$this->logger->debug('Authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($authenticator)]);
89+
}
90+
}
91+
8192
if (!$guardAuthenticators) {
8293
return false;
8394
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public function __construct(string $secret, TokenStorageInterface $tokenStorage)
4141
public function supports(Request $request): ?bool
4242
{
4343
// do not overwrite already stored tokens (i.e. from the session)
44-
return null === $this->tokenStorage->getToken();
44+
// the `null` return value indicates that this authenticator supports lazy firewalls
45+
return null === $this->tokenStorage->getToken() ? null : false;
4546
}
4647

4748
public function getCredentials(Request $request)

src/Symfony/Component/Security/Http/Firewall/AuthenticatorManagerListener.php

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

1414
use Psr\Log\LoggerInterface;
1515
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
16+
use Symfony\Component\HttpFoundation\Request;
1617
use Symfony\Component\HttpFoundation\Response;
1718
use Symfony\Component\HttpKernel\Event\RequestEvent;
1819
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
@@ -30,10 +31,8 @@
3031
*
3132
* @experimental in 5.1
3233
*/
33-
class AuthenticatorManagerListener
34+
class AuthenticatorManagerListener extends AbstractListener
3435
{
35-
use AuthenticatorManagerListenerTrait;
36-
3736
private $authenticationManager;
3837
private $authenticatorHandler;
3938
private $authenticators;
@@ -54,15 +53,58 @@ public function __construct(AuthenticationManagerInterface $authenticationManage
5453
$this->eventDispatcher = $eventDispatcher;
5554
}
5655

57-
public function __invoke(RequestEvent $requestEvent)
56+
public function supports(Request $request): ?bool
5857
{
59-
$request = $requestEvent->getRequest();
60-
$authenticators = $this->getSupportingAuthenticators($request);
58+
if (null !== $this->logger) {
59+
$context = ['firewall_key' => $this->providerKey];
60+
61+
if ($this->authenticators instanceof \Countable || \is_array($this->authenticators)) {
62+
$context['authenticators'] = \count($this->authenticators);
63+
}
64+
65+
$this->logger->debug('Checking for guard authentication credentials.', $context);
66+
}
67+
68+
[$authenticators, $lazy] = $this->getSupportingAuthenticators($request);
69+
if (!$authenticators) {
70+
return false;
71+
}
72+
73+
$request->attributes->set('_guard_authenticators', $authenticators);
74+
75+
return $lazy ? null : true;
76+
}
77+
78+
public function authenticate(RequestEvent $event)
79+
{
80+
$request = $event->getRequest();
81+
$authenticators = $request->attributes->get('_guard_authenticators');
82+
$request->attributes->remove('_guard_authenticators');
6183
if (!$authenticators) {
6284
return;
6385
}
6486

65-
$this->executeAuthenticators($authenticators, $requestEvent);
87+
$this->executeAuthenticators($authenticators, $event);
88+
}
89+
90+
protected function getSupportingAuthenticators(Request $request): array
91+
{
92+
$authenticators = [];
93+
$lazy = true;
94+
foreach ($this->authenticators as $key => $authenticator) {
95+
if (null !== $this->logger) {
96+
$this->logger->debug('Checking support on authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($authenticator)]);
97+
}
98+
99+
if (false !== $supports = $authenticator->supports($request)) {
100+
$authenticators[$key] = $authenticator;
101+
$lazy = $lazy && null === $supports;
102+
} elseif (null !== $this->logger) {
103+
$this->logger->debug('Authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($authenticator)]);
104+
}
105+
}
106+
107+
return [$authenticators, $lazy];
66108
}
67109

68110
/**
@@ -71,6 +113,15 @@ public function __invoke(RequestEvent $requestEvent)
71113
protected function executeAuthenticators(array $authenticators, RequestEvent $event): void
72114
{
73115
foreach ($authenticators as $key => $authenticator) {
116+
// recheck if the authenticator still supports the listener. support() is called
117+
// eagerly (before token storage is initialized), whereas authenticate() is called
118+
// lazily (after initialization). This is important for e.g. the AnonymousAuthenticator
119+
// as its support is relying on the (initialized) token in the TokenStorage.
120+
if (false === $authenticator->supports($event->getRequest())) {
121+
$this->logger->debug('Skipping the "{authenticator}" authenticator as it did not support the request.', ['authenticator' => \get_class($authenticator)]);
122+
continue;
123+
}
124+
74125
$this->executeAuthenticator($key, $authenticator, $event);
75126

76127
if ($event->hasResponse()) {

src/Symfony/Component/Security/Http/Firewall/AuthenticatorManagerListenerTrait.php

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)