vendor/scheb/2fa-bundle/Security/Http/Firewall/TwoFactorAccessListener.php line 21

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Scheb\TwoFactorBundle\Security\Http\Firewall;
  4. use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorTokenInterface;
  5. use Scheb\TwoFactorBundle\Security\Authorization\TwoFactorAccessDecider;
  6. use Scheb\TwoFactorBundle\Security\TwoFactor\TwoFactorFirewallConfig;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpKernel\Event\RequestEvent;
  9. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  10. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  11. use Symfony\Component\Security\Http\Firewall\AbstractListener;
  12. /**
  13.  * Handles access control in the "2fa in progress" phase.
  14.  *
  15.  * @final
  16.  */
  17. class TwoFactorAccessListener extends AbstractListener implements FirewallListenerInterface
  18. {
  19.     /**
  20.      * @var TwoFactorFirewallConfig
  21.      */
  22.     private $twoFactorFirewallConfig;
  23.     /**
  24.      * @var TokenStorageInterface
  25.      */
  26.     private $tokenStorage;
  27.     /**
  28.      * @var TwoFactorAccessDecider
  29.      */
  30.     private $twoFactorAccessDecider;
  31.     public function __construct(
  32.         TwoFactorFirewallConfig $twoFactorFirewallConfig,
  33.         TokenStorageInterface $tokenStorage,
  34.         TwoFactorAccessDecider $twoFactorAccessDecider
  35.     ) {
  36.         $this->twoFactorFirewallConfig $twoFactorFirewallConfig;
  37.         $this->tokenStorage $tokenStorage;
  38.         $this->twoFactorAccessDecider $twoFactorAccessDecider;
  39.     }
  40.     public function supports(Request $request): ?bool
  41.     {
  42.         // When the path is explicitly configured for anonymous access, no need to check access (important for lazy
  43.         // firewalls, to prevent the response cache control to be flagged "private")
  44.         return !$this->twoFactorAccessDecider->isPubliclyAccessible($request);
  45.     }
  46.     public function authenticate(RequestEvent $event): void
  47.     {
  48.         // When the firewall is lazy, the token is not initialized in the "supports" stage, so this check does only work
  49.         // within the "authenticate" stage.
  50.         $token $this->tokenStorage->getToken();
  51.         if (!($token instanceof TwoFactorTokenInterface)) {
  52.             // No need to check for firewall name here, the listener is bound to the firewall context
  53.             return;
  54.         }
  55.         /** @var TwoFactorTokenInterface $token */
  56.         $token $this->tokenStorage->getToken();
  57.         $request $event->getRequest();
  58.         if ($this->twoFactorFirewallConfig->isCheckPathRequest($request)) {
  59.             return;
  60.         }
  61.         if ($this->twoFactorFirewallConfig->isAuthFormRequest($request)) {
  62.             return;
  63.         }
  64.         if (!$this->twoFactorAccessDecider->isAccessible($request$token)) {
  65.             $exception = new AccessDeniedException('User is in a two-factor authentication process.');
  66.             $exception->setSubject($request);
  67.             throw $exception;
  68.         }
  69.     }
  70.     public static function getPriority(): int
  71.     {
  72.         // When the class is injected via FirewallListenerFactoryInterface
  73.         // Inject before Symfony's AccessListener (-255) and after the LogoutListener (-127)
  74.         return -191;
  75.     }
  76. }