Use the firewall event dispatcher

This commit is contained in:
Wouter de Jong 2020-04-04 17:37:52 +02:00
parent 95edc806a1
commit 7ef6a7ab03
6 changed files with 26 additions and 38 deletions

View File

@ -218,9 +218,8 @@ class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactor
{ {
$container $container
->setDefinition('security.listener.remember_me.'.$id, new ChildDefinition('security.listener.remember_me')) ->setDefinition('security.listener.remember_me.'.$id, new ChildDefinition('security.listener.remember_me'))
->addTag('kernel.event_subscriber') ->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$id])
->replaceArgument(0, new Reference($rememberMeServicesId)) ->replaceArgument(0, new Reference($rememberMeServicesId))
->replaceArgument(1, $id)
; ;
$container $container

View File

@ -156,8 +156,11 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
->replaceArgument(2, $this->statelessFirewallKeys); ->replaceArgument(2, $this->statelessFirewallKeys);
if ($this->authenticatorManagerEnabled) { if ($this->authenticatorManagerEnabled) {
$container->getDefinition(SessionListener::class) foreach ($this->statelessFirewallKeys as $statelessFirewallId) {
->replaceArgument(1, $this->statelessFirewallKeys); $container
->setDefinition('security.listener.session.'.$statelessFirewallId, new ChildDefinition('security.listener.session'))
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$statelessFirewallId]);
}
} }
if ($config['encoders']) { if ($config['encoders']) {
@ -446,6 +449,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
$container $container
->setDefinition($managerId = 'security.authenticator.manager.'.$id, new ChildDefinition('security.authenticator.manager')) ->setDefinition($managerId = 'security.authenticator.manager.'.$id, new ChildDefinition('security.authenticator.manager'))
->replaceArgument(0, $authenticators) ->replaceArgument(0, $authenticators)
->replaceArgument(2, new Reference($firewallEventDispatcherId))
->replaceArgument(3, $id) ->replaceArgument(3, $id)
->addTag('monolog.logger', ['channel' => 'security']) ->addTag('monolog.logger', ['channel' => 'security'])
; ;

View File

@ -12,7 +12,10 @@
namespace Symfony\Bundle\SecurityBundle\EventListener; namespace Symfony\Bundle\SecurityBundle\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\LoginFailureEvent;
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
use Symfony\Component\Security\Http\Event\LogoutEvent; use Symfony\Component\Security\Http\Event\LogoutEvent;
use Symfony\Component\Security\Http\Event\VerifyAuthenticatorCredentialsEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/** /**
@ -34,6 +37,9 @@ class FirewallEventBubblingListener implements EventSubscriberInterface
{ {
return [ return [
LogoutEvent::class => 'bubbleEvent', LogoutEvent::class => 'bubbleEvent',
LoginFailureEvent::class => 'bubbleEvent',
LoginSuccessEvent::class => 'bubbleEvent',
VerifyAuthenticatorCredentialsEvent::class => 'bubbleEvent',
]; ];
} }

View File

@ -59,8 +59,9 @@
<argument type="service" id="Symfony\Component\Security\Core\User\UserCheckerInterface" /> <argument type="service" id="Symfony\Component\Security\Core\User\UserCheckerInterface" />
</service> </service>
<service id="security.listener.session" class="Symfony\Component\Security\Http\EventListener\SessionStrategyListener"> <service id="security.listener.session"
<tag name="kernel.event_subscriber" /> class="Symfony\Component\Security\Http\EventListener\SessionStrategyListener"
abstract="true">
<argument type="service" id="security.authentication.session_strategy" /> <argument type="service" id="security.authentication.session_strategy" />
<argument type="abstract">stateless firewall keys</argument> <argument type="abstract">stateless firewall keys</argument>
</service> </service>

View File

@ -26,26 +26,29 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
class RememberMeListener implements EventSubscriberInterface class RememberMeListener implements EventSubscriberInterface
{ {
private $rememberMeServices; private $rememberMeServices;
private $providerKey;
private $logger; private $logger;
public function __construct(RememberMeServicesInterface $rememberMeServices, string $providerKey, ?LoggerInterface $logger = null) public function __construct(RememberMeServicesInterface $rememberMeServices, ?LoggerInterface $logger = null)
{ {
$this->rememberMeServices = $rememberMeServices; $this->rememberMeServices = $rememberMeServices;
$this->providerKey = $providerKey;
$this->logger = $logger; $this->logger = $logger;
} }
public function onSuccessfulLogin(LoginSuccessEvent $event): void public function onSuccessfulLogin(LoginSuccessEvent $event): void
{ {
if (!$this->isRememberMeEnabled($event->getProviderKey(), $event->getAuthenticator())) { $authenticator = $event->getAuthenticator();
if (!$authenticator instanceof RememberMeAuthenticatorInterface || !$authenticator->supportsRememberMe()) {
if (null !== $this->logger) {
$this->logger->debug('Remember me skipped: your authenticator does not support it.', ['authenticator' => \get_class($authenticator)]);
}
return; return;
} }
if (null === $event->getResponse()) { if (null === $event->getResponse()) {
if (null !== $this->logger) { if (null !== $this->logger) {
$this->logger->debug('Remember me skipped: the authenticator did not set a success response.', ['authenticator' => \get_class($event->getAuthenticator())]); $this->logger->debug('Remember me skipped: the authenticator did not set a success response.', ['authenticator' => \get_class($authenticator)]);
} }
return; return;
@ -56,31 +59,9 @@ class RememberMeListener implements EventSubscriberInterface
public function onFailedLogin(LoginFailureEvent $event): void public function onFailedLogin(LoginFailureEvent $event): void
{ {
if (!$this->isRememberMeEnabled($event->getProviderKey())) {
return;
}
$this->rememberMeServices->loginFail($event->getRequest(), $event->getException()); $this->rememberMeServices->loginFail($event->getRequest(), $event->getException());
} }
private function isRememberMeEnabled(string $providerKey, ?AuthenticatorInterface $authenticator = null): bool
{
if ($providerKey !== $this->providerKey) {
// This listener is created for a different firewall.
return false;
}
if (null !== $authenticator && (!$authenticator instanceof RememberMeAuthenticatorInterface || !$authenticator->supportsRememberMe())) {
if (null !== $this->logger) {
$this->logger->debug('Remember me skipped: your authenticator does not support it.', ['authenticator' => \get_class($authenticator)]);
}
return false;
}
return true;
}
public static function getSubscribedEvents(): array public static function getSubscribedEvents(): array
{ {
return [ return [

View File

@ -28,21 +28,18 @@ use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterfa
class SessionStrategyListener implements EventSubscriberInterface class SessionStrategyListener implements EventSubscriberInterface
{ {
private $sessionAuthenticationStrategy; private $sessionAuthenticationStrategy;
private $statelessProviderKeys;
public function __construct(SessionAuthenticationStrategyInterface $sessionAuthenticationStrategy, array $statelessProviderKeys = []) public function __construct(SessionAuthenticationStrategyInterface $sessionAuthenticationStrategy)
{ {
$this->sessionAuthenticationStrategy = $sessionAuthenticationStrategy; $this->sessionAuthenticationStrategy = $sessionAuthenticationStrategy;
$this->statelessProviderKeys = $statelessProviderKeys;
} }
public function onSuccessfulLogin(LoginSuccessEvent $event): void public function onSuccessfulLogin(LoginSuccessEvent $event): void
{ {
$request = $event->getRequest(); $request = $event->getRequest();
$token = $event->getAuthenticatedToken(); $token = $event->getAuthenticatedToken();
$providerKey = $event->getProviderKey();
if (!$request->hasSession() || !$request->hasPreviousSession() || \in_array($providerKey, $this->statelessProviderKeys, true)) { if (!$request->hasSession() || !$request->hasPreviousSession()) {
return; return;
} }