vendor/scheb/2fa-bundle/Security/TwoFactor/Provider/TwoFactorProviderPreparationListener.php line 48
<?phpdeclare(strict_types=1);namespace Scheb\TwoFactorBundle\Security\TwoFactor\Provider;use Psr\Log\LoggerInterface;use Psr\Log\NullLogger;use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorTokenInterface;use Scheb\TwoFactorBundle\Security\TwoFactor\Event\TwoFactorAuthenticationEvent;use Scheb\TwoFactorBundle\Security\TwoFactor\Event\TwoFactorAuthenticationEvents;use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Exception\UnexpectedTokenException;use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpKernel\Event\ResponseEvent;use Symfony\Component\HttpKernel\KernelEvents;use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;use Symfony\Component\Security\Core\AuthenticationEvents;use Symfony\Component\Security\Core\Event\AuthenticationEvent;use function assert;use function sprintf;use const PHP_INT_MAX;/*** @final*/class TwoFactorProviderPreparationListener implements EventSubscriberInterface{// This must trigger very first, followed by AuthenticationSuccessEventSuppressorpublic const AUTHENTICATION_SUCCESS_LISTENER_PRIORITY = PHP_INT_MAX;// Execute right before ContextListener, which is serializing the security token into the sessionpublic const RESPONSE_LISTENER_PRIORITY = 1;private ?TwoFactorTokenInterface $twoFactorToken = null;private LoggerInterface $logger;public function __construct(private TwoFactorProviderRegistry $providerRegistry,private PreparationRecorderInterface $preparationRecorder,?LoggerInterface $logger,private string $firewallName,private bool $prepareOnLogin,private bool $prepareOnAccessDenied) {$this->logger = $logger ?? new NullLogger();}public function onLogin(AuthenticationEvent $event): void{$token = $event->getAuthenticationToken();if (!$this->prepareOnLogin || !$this->supports($token)) {return;}// After login, when the token is a TwoFactorTokenInterface, execute preparationassert($token instanceof TwoFactorTokenInterface);$this->twoFactorToken = $token;}public function onAccessDenied(TwoFactorAuthenticationEvent $event): void{$token = $event->getToken();if (!$this->prepareOnAccessDenied || !$this->supports($token)) {return;}// Whenever two-factor authentication is required, execute preparationassert($token instanceof TwoFactorTokenInterface);$this->twoFactorToken = $token;}public function onTwoFactorForm(TwoFactorAuthenticationEvent $event): void{$token = $event->getToken();if (!$this->supports($token)) {return;}// Whenever two-factor authentication form is shown, execute preparationassert($token instanceof TwoFactorTokenInterface);$this->twoFactorToken = $token;}public function onKernelResponse(ResponseEvent $event): void{if (!$event->isMainRequest()) {return;}// Unset the token from context. This is important for environments where this instance of the class is reused// for multiple requests, such as PHP PM.$twoFactorToken = $this->twoFactorToken;$this->twoFactorToken = null;if (!($twoFactorToken instanceof TwoFactorTokenInterface)) {return;}$providerName = $twoFactorToken->getCurrentTwoFactorProvider();if (null === $providerName) {return;}$firewallName = $twoFactorToken->getFirewallName();try {if ($this->preparationRecorder->isTwoFactorProviderPrepared($firewallName, $providerName)) {$this->logger->info(sprintf('Two-factor provider "%s" was already prepared.', $providerName));return;}$user = $twoFactorToken->getUser();$this->providerRegistry->getProvider($providerName)->prepareAuthentication($user);$this->preparationRecorder->setTwoFactorProviderPrepared($firewallName, $providerName);$this->logger->info(sprintf('Two-factor provider "%s" prepared.', $providerName));} catch (UnexpectedTokenException) {$this->logger->info(sprintf('Two-factor provider "%s" was not prepared, security token was change within the request.', $providerName));}}private function supports(TokenInterface $token): bool{return $token instanceof TwoFactorTokenInterface && $token->getFirewallName() === $this->firewallName;}/*** {@inheritdoc}*/public static function getSubscribedEvents(): array{return [AuthenticationEvents::AUTHENTICATION_SUCCESS => ['onLogin', self::AUTHENTICATION_SUCCESS_LISTENER_PRIORITY],TwoFactorAuthenticationEvents::REQUIRE => 'onAccessDenied',TwoFactorAuthenticationEvents::FORM => 'onTwoFactorForm',KernelEvents::RESPONSE => ['onKernelResponse', self::RESPONSE_LISTENER_PRIORITY],];}}