vendor/pimcore/pimcore/bundles/AdminBundle/EventListener/AdminAuthenticationDoubleCheckListener.php line 88

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Bundle\AdminBundle\EventListener;
  15. use Pimcore\Bundle\AdminBundle\Controller\DoubleAuthenticationControllerInterface;
  16. use Pimcore\Bundle\AdminBundle\EventListener\Traits\ControllerTypeTrait;
  17. use Pimcore\Bundle\AdminBundle\Security\User\TokenStorageUserResolver;
  18. use Pimcore\Bundle\CoreBundle\EventListener\Traits\PimcoreContextAwareTrait;
  19. use Pimcore\Http\Request\Resolver\PimcoreContextResolver;
  20. use Pimcore\Http\RequestMatcherFactory;
  21. use Pimcore\Tool\Authentication;
  22. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\RequestMatcherInterface;
  25. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  26. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  27. use Symfony\Component\HttpKernel\KernelEvents;
  28. /**
  29.  * Handles double authentication check for pimcore controllers after the firewall did to make sure the admin interface is
  30.  * not accessible on configuration errors. Unauthenticated routes are not double-checked (e.g. login).
  31.  *
  32.  * @internal
  33.  */
  34. class AdminAuthenticationDoubleCheckListener implements EventSubscriberInterface
  35. {
  36.     use ControllerTypeTrait;
  37.     use PimcoreContextAwareTrait;
  38.     /**
  39.      * @var RequestMatcherFactory
  40.      */
  41.     protected $requestMatcherFactory;
  42.     /**
  43.      * @var array
  44.      */
  45.     protected $unauthenticatedRoutes;
  46.     /**
  47.      * @var RequestMatcherInterface[]
  48.      */
  49.     protected $unauthenticatedMatchers;
  50.     /**
  51.      * @var TokenStorageUserResolver
  52.      */
  53.     protected $tokenResolver;
  54.     /**
  55.      * @param RequestMatcherFactory $factory
  56.      * @param TokenStorageUserResolver $tokenResolver
  57.      * @param array $unauthenticatedRoutes
  58.      */
  59.     public function __construct(
  60.         RequestMatcherFactory $factory,
  61.         TokenStorageUserResolver $tokenResolver,
  62.         array $unauthenticatedRoutes
  63.     ) {
  64.         $this->requestMatcherFactory $factory;
  65.         $this->tokenResolver $tokenResolver;
  66.         $this->unauthenticatedRoutes $unauthenticatedRoutes;
  67.     }
  68.     /**
  69.      * {@inheritdoc}
  70.      */
  71.     public static function getSubscribedEvents()
  72.     {
  73.         return [
  74.             KernelEvents::CONTROLLER => 'onKernelController',
  75.         ];
  76.     }
  77.     public function onKernelController(ControllerEvent $event)
  78.     {
  79.         if (!$event->isMainRequest()) {
  80.             return;
  81.         }
  82.         $request $event->getRequest();
  83.         $isDoubleAuthController $this->isControllerType($eventDoubleAuthenticationControllerInterface::class);
  84.         $isPimcoreAdminContext $this->matchesPimcoreContext($requestPimcoreContextResolver::CONTEXT_ADMIN);
  85.         if (!$isDoubleAuthController && !$isPimcoreAdminContext) {
  86.             return;
  87.         }
  88.         // double check we have a valid user to make sure there is no invalid security config
  89.         // opening admin interface to the public
  90.         if ($this->requestNeedsAuthentication($request)) {
  91.             if ($isDoubleAuthController) {
  92.                 /** @var DoubleAuthenticationControllerInterface $controller */
  93.                 $controller $this->getControllerType($eventDoubleAuthenticationControllerInterface::class);
  94.                 if ($controller->needsSessionDoubleAuthenticationCheck()) {
  95.                     $this->checkSessionUser();
  96.                 }
  97.                 if ($controller->needsStorageDoubleAuthenticationCheck()) {
  98.                     $this->checkTokenStorageUser();
  99.                 }
  100.             } else {
  101.                 $this->checkSessionUser();
  102.                 $this->checkTokenStorageUser();
  103.             }
  104.         }
  105.     }
  106.     /**
  107.      * Check if the current request needs double authentication
  108.      *
  109.      * @param Request $request
  110.      *
  111.      * @return bool
  112.      */
  113.     protected function requestNeedsAuthentication(Request $request)
  114.     {
  115.         foreach ($this->getUnauthenticatedMatchers() as $matcher) {
  116.             if ($matcher->matches($request)) {
  117.                 return false;
  118.             }
  119.         }
  120.         return true;
  121.     }
  122.     /**
  123.      * Get list of paths which don't need double authentication check
  124.      *
  125.      * @return RequestMatcherInterface[]
  126.      */
  127.     protected function getUnauthenticatedMatchers()
  128.     {
  129.         if (null === $this->unauthenticatedMatchers) {
  130.             $this->unauthenticatedMatchers $this->requestMatcherFactory->buildRequestMatchers($this->unauthenticatedRoutes);
  131.         }
  132.         return $this->unauthenticatedMatchers;
  133.     }
  134.     /**
  135.      * @throws AccessDeniedHttpException
  136.      *      if there's no current user in the session
  137.      */
  138.     protected function checkSessionUser()
  139.     {
  140.         $user Authentication::authenticateSession();
  141.         if (null === $user) {
  142.             throw new AccessDeniedHttpException('User is invalid.');
  143.         }
  144.     }
  145.     /**
  146.      * @throws AccessDeniedHttpException
  147.      *      if there's no current user in the token storage
  148.      */
  149.     protected function checkTokenStorageUser()
  150.     {
  151.         $user $this->tokenResolver->getUser();
  152.         if (null === $user || !Authentication::isValidUser($user)) {
  153.             throw new AccessDeniedHttpException('User is invalid.');
  154.         }
  155.     }
  156. }