<?php/** * Pimcore * * This source file is available under two different licenses: * - GNU General Public License version 3 (GPLv3) * - Pimcore Commercial License (PCL) * Full copyright and license information is available in * LICENSE.md which is distributed with this source code. * * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) * @license http://www.pimcore.org/license GPLv3 and PCL */namespace Pimcore\Bundle\AdminBundle\EventListener;use Pimcore\Bundle\AdminBundle\Controller\DoubleAuthenticationControllerInterface;use Pimcore\Bundle\AdminBundle\EventListener\Traits\ControllerTypeTrait;use Pimcore\Bundle\CoreBundle\EventListener\Traits\PimcoreContextAwareTrait;use Pimcore\Http\Request\Resolver\PimcoreContextResolver;use Pimcore\Http\RequestMatcherFactory;use Pimcore\Security\User\TokenStorageUserResolver;use Pimcore\Tool\Authentication;use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\RequestMatcherInterface;use Symfony\Component\HttpKernel\Event\ControllerEvent;use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;use Symfony\Component\HttpKernel\KernelEvents;/** * Handles double authentication check for pimcore controllers after the firewall did to make sure the admin interface is * not accessible on configuration errors. Unauthenticated routes are not double-checked (e.g. login). * * @internal * * @deprecated and will be removed in Pimcore 11. */class AdminAuthenticationDoubleCheckListener implements EventSubscriberInterface{ use ControllerTypeTrait; use PimcoreContextAwareTrait; /** * @var RequestMatcherFactory */ protected $requestMatcherFactory; /** * @var array */ protected $unauthenticatedRoutes; /** * @var RequestMatcherInterface[] */ protected $unauthenticatedMatchers; /** * @var TokenStorageUserResolver */ protected $tokenResolver; /** * @param RequestMatcherFactory $factory * @param TokenStorageUserResolver $tokenResolver * @param array $unauthenticatedRoutes */ public function __construct( RequestMatcherFactory $factory, TokenStorageUserResolver $tokenResolver, array $unauthenticatedRoutes ) { $this->requestMatcherFactory = $factory; $this->tokenResolver = $tokenResolver; $this->unauthenticatedRoutes = $unauthenticatedRoutes; } /** * {@inheritdoc} */ public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER => 'onKernelController', ]; } public function onKernelController(ControllerEvent $event) { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); $isDoubleAuthController = $this->isControllerType($event, DoubleAuthenticationControllerInterface::class); $isPimcoreAdminContext = $this->matchesPimcoreContext($request, PimcoreContextResolver::CONTEXT_ADMIN); if (!$isDoubleAuthController && !$isPimcoreAdminContext) { return; } // double check we have a valid user to make sure there is no invalid security config // opening admin interface to the public if ($this->requestNeedsAuthentication($request)) { if ($isDoubleAuthController) { /** @var DoubleAuthenticationControllerInterface $controller */ $controller = $this->getControllerType($event, DoubleAuthenticationControllerInterface::class); if ($controller->needsSessionDoubleAuthenticationCheck()) { $this->checkSessionUser(); } if ($controller->needsStorageDoubleAuthenticationCheck()) { $this->checkTokenStorageUser(); } } else { $this->checkSessionUser(); $this->checkTokenStorageUser(); } } } /** * Check if the current request needs double authentication * * @param Request $request * * @return bool */ protected function requestNeedsAuthentication(Request $request) { foreach ($this->getUnauthenticatedMatchers() as $matcher) { if ($matcher->matches($request)) { return false; } } return true; } /** * Get list of paths which don't need double authentication check * * @return RequestMatcherInterface[] */ protected function getUnauthenticatedMatchers() { if (null === $this->unauthenticatedMatchers) { $this->unauthenticatedMatchers = $this->requestMatcherFactory->buildRequestMatchers($this->unauthenticatedRoutes); } return $this->unauthenticatedMatchers; } /** * @throws AccessDeniedHttpException * if there's no current user in the session */ protected function checkSessionUser() { $user = Authentication::authenticateSession(); if (null === $user) { throw new AccessDeniedHttpException('User is invalid.'); } } /** * @throws AccessDeniedHttpException * if there's no current user in the token storage */ protected function checkTokenStorageUser() { $user = $this->tokenResolver->getUser(); if (null === $user || !Authentication::isValidUser($user)) { throw new AccessDeniedHttpException('User is invalid.'); } }}