8000 Added GuardManagerListener · symfony/symfony@526f756 · GitHub
[go: up one dir, main page]

Skip to content

Commit 526f756

Browse files
committed
Added GuardManagerListener
This replaces all individual authentication listeners when guard authentication manager is enabled.
1 parent a172bac commit 526f756

File tree

6 files changed

+314
-122
lines changed

6 files changed

+314
-122
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,24 @@ private function createFirewalls(array $config, ContainerBuilder $container)
264264
// add authentication providers to authentication manager
265265
$authenticationProviders = array_map(function ($id) {
266266
return new Reference($id);
267-
}, array_values(array_unique($authenticationProviders)));
267+
}, array_unique($authenticationProviders));
268268
$authenticationManagerId = 'security.authentication.manager.provider';
269269
if ($this->guardAuthenticationManagerEnabled) {
270270
$authenticationManagerId = 'security.authentication.manager.guard';
271271
$container->setAlias('security.authentication.manager', new Alias($authenticationManagerId));
272+
273+
// guard authentication manager listener
274+
$container
275+
->setDefinition('security.firewall.guard.'.$name.'locator', new ChildDefinition('security.firewall.guard.locator'))
276+
->setArguments([$authenticationProviders])
277+
->addTag('container.service_locator')
278+
;
279+
$container
280+
->setDefinition('security.firewall.guard.'.$name, new ChildDefinition('security.firewall.guard'))
281+
->replaceArgument(2, new Reference('security.firewall.guard.'.$name.'locator'))
282+
->replaceArgument(3, $name)
283+
->addTag('kernel.event_listener', ['event' => KernelEvents::REQUEST])
284+
;
272285
}
273286
$container
274287
->getDefinition($authenticationManagerId)
@@ -498,7 +511,7 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri
498511
list($provider, $listenerId, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
499512

500513
$listeners[] = new Reference($listenerId);
501-
$authenticationProviders[] = $provider;
514+
$authenticationProviders[$id.'_'.$key] = $provider;
502515
}
503516
$hasListeners = true;
504517
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\EventListener;
13+
14+
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\DependencyInjection\ServiceLocator;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
18+
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
19+
use Symfony\Component\Security\Http\Firewall\GuardManagerListener;
20+
21+
/**
22+
* @author Wouter de Jong <wouter@wouterj.nl>
23+
*/
24+
class LazyGuardManagerListener extends GuardManagerListener
25+
{
26+
private $guardLocator;
27+
28+
public function __construct(
29+
AuthenticationManagerInterface $authenticationManager,
30+
GuardAuthenticatorHandler $guardHandler,
31+
ServiceLocator $guardLocator,
32+
string $providerKey,
33+
?LoggerInterface $logger = null
34+
) {
35+
parent::__construct($authenticationManager, $guardHandler, [], $providerKey, $logger);
36+
37+
$this->guardLocator = $guardLocator;
38+
}
39+
40+
protected function getSupportingGuardAuthenticators(Request $request): array
41+
{
42+
$guardAuthenticators = [];
43+
foreach ($this->guardLocator->getProvidedServices() as $key => $type) {
44+
$guardAuthenticator = $this->guardLocator->get($key);
45+
if (null !== $this->logger) {
46+
$this->logger->debug('Checking support on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
47+
}
48+
49+
if ($guardAuthenticator->supports($request)) {
50+
$guardAuthenticators[$key] = $guardAuthenticator;
51+
} elseif (null !== $this->logger) {
52+
$this->logger->debug('Guard authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
53+
}
54+
}
55+
56+
return $guardAuthenticators;
57+
}
58+
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
55

66
<services>
7+
<service id="security.firewall.guard.locator"
8+
class="Symfony\Component\DependencyInjection\ServiceLocator"
9+
abstract="true" />
10+
11+
<service id="security.firewall.guard"
12+
class="Symfony\Bundle\SecurityBundle\EventListener\LazyGuardManagerListener"
13+
abstract="true">
14+
<tag name="monolog.logger" channel="security" />
15+
<argument type="service" id="security.authentication.manager"/>
16+
<argument type="service" id="security.authentication.guard_handler"/>
17+
<argument/> <!-- guard authenticator locator -->
18+
<argument/> <!-- provider key -->
19+
<argument type="service" id="logger" on-invalid="null" />
20+
</service>
21+
722
<service id="security.authenticator.http_basic"
823
class="Symfony\Component\Security\Core\Authentication\Authenticator\HttpBasicAuthenticator"
924
abstract="true">

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

Lines changed: 8 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
*/
3535
class GuardAuthenticationListener extends AbstractListener
3636
{
37+
use GuardAuthenticatorListenerTrait;
38+
3739
private $guardHandler;
3840
private $authenticationManager;
3941
private $providerKey;
@@ -73,20 +75,7 @@ public function supports(Request $request): ?bool
7375
$this->logger->debug('Checking for guard authentication credentials.', $context);
7476
}
7577

76-
$guardAuthenticators = [];
77-
78-
foreach ($this->guardAuthenticators as $key => $guardAuthenticator) {
79-
if (null !== $this->logger) {
80-
$this->logger->debug('Checking support on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
81-
}
82-
83-
if ($guardAuthenticator->supports($request)) {
84-
$guardAuthenticators[$key] = $guardAuthenticator;
85-
} elseif (null !== $this->logger) {
86-
$this->logger->debug('Guard authenticator does not support the request.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
87-
}
88-
}
89-
78+
$guardAuthenticators = $this->getSupportingGuardAuthenticators($request);
9079
if (!$guardAuthenticators) {
9180
return false;
9281
}
@@ -105,86 +94,7 @@ public function authenticate(RequestEvent $event)
10594
$guardAuthenticators = $request->attributes->get('_guard_authenticators');
10695
$request->attributes->remove('_guard_authenticators');
10796

108-
foreach ($guardAuthenticators as $key => $guardAuthenticator) {
109-
// get a key that's unique to *this* guard authenticator
110-
F987 // this MUST be the same as GuardAuthenticationProvider
111-
$uniqueGuardKey = $this->providerKey.'_'.$key;
112-
113-
$this->executeGuardAuthenticator($uniqueGuardKey, $guardAuthenticator, $event);
114-
115-
if ($event->hasResponse()) {
116-
if (null !== $this->logger) {
117-
$this->logger->debug('The "{authenticator}" authenticator set the response. Any later authenticator will not be called', ['authenticator' => \get_class($guardAuthenticator)]);
118-
}
119-
120-
break;
121-
}
122-
}
123-
}
124-
125-
private function executeGuardAuthenticator(string $uniqueGuardKey, AuthenticatorInterface $guardAuthenticator, RequestEvent $event)
126-
{
127-
$request = $event->getRequest();
128-
try {
129-
if (null !== $this->logger) {
130-
$this->logger->debug('Calling getCredentials() on guard authenticator.', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
131-
}
132-
133-
// allow the authenticator to fetch authentication info from the request
134-
$credentials = $guardAuthenticator->getCredentials($request);
135-
136-
if (null === $credentials) {
137-
throw new \UnexpectedValueException(sprintf('The return value of "%1$s::getCredentials()" must not be null. Return false from "%1$s::supports()" instead.', get_debug_type($guardAuthenticator)));
138-
}
139-
140-
// create a token with the unique key, so that the provider knows which authenticator to use
141-
$token = new PreAuthenticationGuardToken($credentials, $uniqueGuardKey);
142-
143-
if (null !== $this->logger) {
144-
$this->logger->debug('Passing guard token information to the GuardAuthenticationProvider', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
145-
}
146-
// pass the token into the AuthenticationManager system
147-
// this indirectly calls GuardAuthenticationProvider::authenticate()
148-
$token = $this->authenticationManager->authenticate($token);
149-
150-
if (null !== $this->logger) {
151-
$this->logger->info('Guard authentication successful!', ['token' => < 1241 span class=pl-c1>$token, 'authenticator' => \get_class($guardAuthenticator)]);
152-
}
153-
154-
// sets the token on the token storage, etc
155-
$this->guardHandler->authenticateWithToken($token, $request, $this->providerKey);
156-
} catch (AuthenticationException $e) {
157-
// oh no! Authentication failed!
158-
159-
if (null !== $this->logger) {
160-
$this->logger->info('Guard authentication failed.', ['exception' => $e, 'authenticator' => \get_class($guardAuthenticator)]);
161-
}
162-
163-
$response = $this->guardHandler->handleAuthenticationFailure($e, $request, $guardAuthenticator, $this->providerKey);
164-
165-
if ($response instanceof Response) {
166-
$event->setResponse($response);
167-
}
168-
169-
return;
170-
}
171-
172-
// success!
173-
$response = $this->guardHandler->handleAuthenticationSuccess($token, $request, $guardAuthenticator, $this->providerKey);
174-
if ($response instanceof Response) {
175-
if (null !== $this->logger) {
176-
$this->logger->debug('Guard authenticator set success response.', ['response' => $response, 'authenticator' => \get_class($guardAuthenticator)]);
177-
}
178-
179-
$event->setResponse($response);
180-
} else {
181-
if (null !== $this->logger) {
182-
$this->logger->debug('Guard authenticator set no success response: request continues.', ['authenticator' => \get_class($guardAuthenticator)]);
183-
}
184-
}
185-
186-
// attempt to trigger the remember me functionality
187-
$this->triggerRememberMe($guardAuthenticator, $request, $token, $response);
97+
$this->executeGuardAuthenticators($guardAuthenticators, $event);
18898
}
18999

190100
/**
@@ -195,32 +105,10 @@ public function setRememberMeServices(RememberMeServicesInterface $rememberMeSer
195105
$this->rememberMeServices = $rememberMeServices;
196106
}
197107

198-
/**
199-
* Checks to see if remember me is supported in the authenticator and
200-
* on the firewall. If it is, the RememberMeServicesInterface is notified.
201-
*/
202-
private function triggerRememberMe(AuthenticatorInterface $guardAuthenticator, Request $request, TokenInterface $token, Response $response = null)
108+
protected function getGuardKey(string $key): string
203109
{
204-
if (null === $this->rememberMeServices) {
205-
if (null !== $this->logger) {
206-
$this->logger->debug('Remember me skipped: it is not configured for the firewall.', ['authenticator' => \get_class($guardAuthenticator)]);
207-
}
208-
209-
return;
210-
}
211-
212-
if (!$guardAuthenticator->supportsRememberMe()) {
213-
if (null !== $this->logger) {
214-
$this->logger->debug('Remember me skipped: your authenticator does not support it.', ['authenticator' => \get_class($guardAuthenticator)]);
215-
}
216-
217-
return;
218-
}
219-
220-
if (!$response instanceof Response) {
221-
throw new \LogicException(sprintf('"%s::onAuthenticationSuccess()" *must* return a Response if you want to use the remember me functionality. Return a Response, or set remember_me to false under the guard configuration.', get_debug_type($guardAuthenticator)));
222-
}
223-
224-
$this->rememberMeServices->loginSuccess($request, $response, $token);
110+
// get a key that's unique to *this* guard authenticator
111+
// this MUST be the same as GuardAuthenticationProvider
112+
return $this->providerKey.'_'.$key;
225113
}
226114
}

0 commit comments

Comments
 (0)
0