Skip to content

Commit 9782b52

Browse files
committed
Added support for lazy firewalls
1 parent 0898969 commit 9782b52

File tree

3 files changed

+60
-49
lines changed

3 files changed

+60
-49
lines changed

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)

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()) {

Firewall/AuthenticatorManagerListenerTrait.php

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

0 commit comments

Comments
 (0)