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

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 Enterprise License (PEL)
  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 PEL
  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\Http\RequestMatcherFactory;
  19. use Pimcore\Tool\Authentication;
  20. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\RequestMatcherInterface;
  23. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  24. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  25. use Symfony\Component\HttpKernel\KernelEvents;
  26. /**
  27.  * Handles double authentication check for pimcore controllers after the firewall did to make sure the admin interface is
  28.  * not accessible on configuration errors. Unauthenticated routes are not double-checked (e.g. login).
  29.  *
  30.  * TODO: the double authentication check is currently running for every DoubleAuthenticationControllerInterface, independent
  31.  * of the request context, to ensure third party bundles using the AdminController handle authentication as well. Should we
  32.  * do this on the pimcore context instead?
  33.  */
  34. class AdminAuthenticationDoubleCheckListener implements EventSubscriberInterface
  35. {
  36.     use ControllerTypeTrait;
  37.     /**
  38.      * @var RequestMatcherFactory
  39.      */
  40.     protected $requestMatcherFactory;
  41.     /**
  42.      * @var array
  43.      */
  44.     protected $unauthenticatedRoutes;
  45.     /**
  46.      * @var RequestMatcherInterface[]
  47.      */
  48.     protected $unauthenticatedMatchers;
  49.     /**
  50.      * @var TokenStorageUserResolver
  51.      */
  52.     protected $tokenResolver;
  53.     /**
  54.      * @param RequestMatcherFactory $factory
  55.      * @param TokenStorageUserResolver $tokenResolver
  56.      * @param array $unauthenticatedRoutes
  57.      */
  58.     public function __construct(
  59.         RequestMatcherFactory $factory,
  60.         TokenStorageUserResolver $tokenResolver,
  61.         array $unauthenticatedRoutes
  62.     ) {
  63.         $this->requestMatcherFactory $factory;
  64.         $this->tokenResolver $tokenResolver;
  65.         $this->unauthenticatedRoutes $unauthenticatedRoutes;
  66.     }
  67.     /**
  68.      * @inheritDoc
  69.      */
  70.     public static function getSubscribedEvents()
  71.     {
  72.         return [
  73.             KernelEvents::CONTROLLER => 'onKernelController'
  74.         ];
  75.     }
  76.     public function onKernelController(FilterControllerEvent $event)
  77.     {
  78.         if (!$this->isControllerType($eventDoubleAuthenticationControllerInterface::class)) {
  79.             return;
  80.         }
  81.         $request $event->getRequest();
  82.         /** @var DoubleAuthenticationControllerInterface $controller */
  83.         $controller $this->getControllerType($eventDoubleAuthenticationControllerInterface::class);
  84.         // double check we have a valid user to make sure there is no invalid security config
  85.         // opening admin interface to the public
  86.         if ($this->requestNeedsAuthentication($request)) {
  87.             if ($controller->needsSessionDoubleAuthenticationCheck()) {
  88.                 $this->checkSessionUser();
  89.             }
  90.             if ($controller->needsStorageDoubleAuthenticationCheck()) {
  91.                 $this->checkTokenStorageUser();
  92.             }
  93.         }
  94.     }
  95.     /**
  96.      * Check if the current request needs double authentication
  97.      *
  98.      * @param Request $request
  99.      *
  100.      * @return bool
  101.      */
  102.     protected function requestNeedsAuthentication(Request $request)
  103.     {
  104.         foreach ($this->getUnauthenticatedMatchers() as $matcher) {
  105.             if ($matcher->matches($request)) {
  106.                 return false;
  107.             }
  108.         }
  109.         return true;
  110.     }
  111.     /**
  112.      * Get list of paths which don't need double authentication check
  113.      *
  114.      * @return RequestMatcherInterface[]
  115.      */
  116.     protected function getUnauthenticatedMatchers()
  117.     {
  118.         if (null === $this->unauthenticatedMatchers) {
  119.             $this->unauthenticatedMatchers $this->requestMatcherFactory->buildRequestMatchers($this->unauthenticatedRoutes);
  120.         }
  121.         return $this->unauthenticatedMatchers;
  122.     }
  123.     /**
  124.      * @throws AccessDeniedHttpException
  125.      *      if there's no current user in the session
  126.      */
  127.     protected function checkSessionUser()
  128.     {
  129.         $user Authentication::authenticateSession();
  130.         if (null === $user) {
  131.             throw new AccessDeniedHttpException('User is invalid.');
  132.         }
  133.     }
  134.     /**
  135.      * @throws AccessDeniedHttpException
  136.      *      if there's no current user in the token storage
  137.      */
  138.     protected function checkTokenStorageUser()
  139.     {
  140.         $user $this->tokenResolver->getUser();
  141.         if (null === $user || !Authentication::isValidUser($user)) {
  142.             throw new AccessDeniedHttpException('User is invalid.');
  143.         }
  144.     }
  145. }