vendor/contao/core-bundle/src/EventListener/TwoFactorFrontendListener.php line 62

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\EventListener;
  11. use Contao\CoreBundle\Exception\PageNotFoundException;
  12. use Contao\CoreBundle\Framework\ContaoFramework;
  13. use Contao\CoreBundle\Routing\ScopeMatcher;
  14. use Contao\FrontendUser;
  15. use Contao\PageModel;
  16. use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorToken;
  17. use Symfony\Component\HttpFoundation\RedirectResponse;
  18. use Symfony\Component\HttpKernel\Event\RequestEvent;
  19. use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
  20. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  21. use Symfony\Component\Security\Http\Util\TargetPathTrait;
  22. /**
  23.  * @internal
  24.  */
  25. class TwoFactorFrontendListener
  26. {
  27.     use TargetPathTrait;
  28.     /**
  29.      * @var ContaoFramework
  30.      */
  31.     private $framework;
  32.     /**
  33.      * @var ScopeMatcher
  34.      */
  35.     private $scopeMatcher;
  36.     /**
  37.      * @var TokenStorageInterface
  38.      */
  39.     private $tokenStorage;
  40.     /**
  41.      * @var array
  42.      */
  43.     private $supportedTokens;
  44.     public function __construct(ContaoFramework $frameworkScopeMatcher $scopeMatcherTokenStorageInterface $tokenStorage, array $supportedTokens)
  45.     {
  46.         $this->framework $framework;
  47.         $this->scopeMatcher $scopeMatcher;
  48.         $this->tokenStorage $tokenStorage;
  49.         $this->supportedTokens $supportedTokens;
  50.     }
  51.     public function __invoke(RequestEvent $event): void
  52.     {
  53.         if (!$this->scopeMatcher->isFrontendMasterRequest($event)) {
  54.             return;
  55.         }
  56.         $token $this->tokenStorage->getToken();
  57.         if (null === $token) {
  58.             return;
  59.         }
  60.         // Check if is a supported token
  61.         if (!$token instanceof TwoFactorToken && !\in_array(\get_class($token), $this->supportedTokenstrue)) {
  62.             return;
  63.         }
  64.         $request $event->getRequest();
  65.         $page $request->attributes->get('pageModel');
  66.         // Check if actual page is available
  67.         if (!$page instanceof PageModel) {
  68.             return;
  69.         }
  70.         $user $token->getUser();
  71.         if (!$user instanceof FrontendUser) {
  72.             return;
  73.         }
  74.         /** @var PageModel $adapter */
  75.         $adapter $this->framework->getAdapter(PageModel::class);
  76.         // Check if user has two-factor disabled but is enforced
  77.         if ($page->enforceTwoFactor && !$user->useTwoFactor) {
  78.             $twoFactorPage $adapter->findPublishedById($page->twoFactorJumpTo);
  79.             if (!$twoFactorPage instanceof PageModel) {
  80.                 throw new PageNotFoundException('No two-factor authentication page found');
  81.             }
  82.             // Redirect to two-factor page
  83.             if ($page->id !== $twoFactorPage->id) {
  84.                 $event->setResponse(new RedirectResponse($twoFactorPage->getAbsoluteUrl()));
  85.             }
  86.             return;
  87.         }
  88.         // Return if user is authenticated
  89.         if (!$token instanceof TwoFactorToken) {
  90.             return;
  91.         }
  92.         $page401 $adapter->find401ByPid($page->rootId);
  93.         // Return if we are on the 401 target page already
  94.         if ($page401 instanceof PageModel && $page401->autoforward && $page->id === $page401->jumpTo) {
  95.             return;
  96.         }
  97.         $targetPath $this->getTargetPath($request->getSession(), $token->getFirewallName());
  98.         if ($targetPath) {
  99.             // Redirect to the target path
  100.             if ($targetPath !== $request->getSchemeAndHttpHost().$request->getRequestUri()) {
  101.                 $event->setResponse(new RedirectResponse($targetPath));
  102.             }
  103.             return;
  104.         }
  105.         throw new UnauthorizedHttpException('''Missing two-factor authentication');
  106.     }
  107. }