vendor/pimcore/pimcore/bundles/AdminBundle/Security/Guard/AdminAuthenticator.php line 365

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\Security\Guard;
  15. use Pimcore\Bundle\AdminBundle\Security\Authentication\Token\LegacyTwoFactorRequiredToken;
  16. use Pimcore\Bundle\AdminBundle\Security\BruteforceProtectionHandler;
  17. use Pimcore\Bundle\AdminBundle\Security\User\User;
  18. use Pimcore\Cache\RuntimeCache;
  19. use Pimcore\Event\Admin\Login\LoginCredentialsEvent;
  20. use Pimcore\Event\Admin\Login\LoginFailedEvent;
  21. use Pimcore\Event\Admin\Login\LoginRedirectEvent;
  22. use Pimcore\Event\AdminEvents;
  23. use Pimcore\Model\User as UserModel;
  24. use Pimcore\Tool\Admin;
  25. use Pimcore\Tool\Authentication;
  26. use Pimcore\Tool\Session;
  27. use Psr\Log\LoggerAwareInterface;
  28. use Psr\Log\LoggerAwareTrait;
  29. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  30. use Symfony\Component\HttpFoundation\Cookie;
  31. use Symfony\Component\HttpFoundation\RedirectResponse;
  32. use Symfony\Component\HttpFoundation\Request;
  33. use Symfony\Component\HttpFoundation\Response;
  34. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  35. use Symfony\Component\Routing\RouterInterface;
  36. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  37. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  38. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  39. use Symfony\Component\Security\Core\User\UserInterface;
  40. use Symfony\Component\Security\Core\User\UserProviderInterface;
  41. use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
  42. use Symfony\Component\Security\Http\HttpUtils;
  43. use Symfony\Contracts\Translation\TranslatorInterface;
  44. /**
  45.  * @internal
  46.  *
  47.  * @deprecated will be removed in Pimcore 11
  48.  */
  49. class AdminAuthenticator extends AbstractGuardAuthenticator implements LoggerAwareInterface
  50. {
  51.     use LoggerAwareTrait;
  52.     /**
  53.      * @var TokenStorageInterface
  54.      */
  55.     protected $tokenStorage;
  56.     /**
  57.      * @var RouterInterface
  58.      */
  59.     protected $router;
  60.     /**
  61.      * @var EventDispatcherInterface
  62.      */
  63.     protected $dispatcher;
  64.     /**
  65.      * @var TranslatorInterface
  66.      */
  67.     protected $translator;
  68.     /**
  69.      * @var HttpUtils
  70.      */
  71.     protected $httpUtils;
  72.     /**
  73.      * @var BruteforceProtectionHandler
  74.      */
  75.     protected $bruteforceProtectionHandler;
  76.     /**
  77.      * @var bool
  78.      */
  79.     protected $twoFactorRequired false;
  80.     /**
  81.      * @param TokenStorageInterface $tokenStorage
  82.      * @param RouterInterface $router
  83.      * @param EventDispatcherInterface $dispatcher
  84.      * @param TranslatorInterface $translator
  85.      * @param HttpUtils $httpUtils
  86.      * @param BruteforceProtectionHandler $bruteforceProtectionHandler
  87.      */
  88.     public function __construct(
  89.         TokenStorageInterface $tokenStorage,
  90.         RouterInterface $router,
  91.         EventDispatcherInterface $dispatcher,
  92.         TranslatorInterface $translator,
  93.         HttpUtils $httpUtils,
  94.         BruteforceProtectionHandler $bruteforceProtectionHandler
  95.     ) {
  96.         $this->tokenStorage $tokenStorage;
  97.         $this->router $router;
  98.         $this->dispatcher $dispatcher;
  99.         $this->translator $translator;
  100.         $this->httpUtils $httpUtils;
  101.         $this->bruteforceProtectionHandler $bruteforceProtectionHandler;
  102.     }
  103.     /**
  104.      * {@inheritdoc}
  105.      */
  106.     public function supports(Request $request)
  107.     {
  108.         return $request->attributes->get('_route') === 'pimcore_admin_login_check'
  109.             || Authentication::authenticateSession($request);
  110.     }
  111.     /**
  112.      * {@inheritdoc}
  113.      */
  114.     public function start(Request $requestAuthenticationException $authException null)
  115.     {
  116.         if ($request->isXmlHttpRequest()) {
  117.             // TODO use a JSON formatted error response?
  118.             $response = new Response('Session expired or unauthorized request. Please reload and try again!');
  119.             $response->setStatusCode(Response::HTTP_FORBIDDEN);
  120.             return $response;
  121.         }
  122.         $event = new LoginRedirectEvent('pimcore_admin_login', ['perspective' => strip_tags($request->get('perspective'''))]);
  123.         $this->dispatcher->dispatch($eventAdminEvents::LOGIN_REDIRECT);
  124.         $url $this->router->generate($event->getRouteName(), $event->getRouteParams());
  125.         return new RedirectResponse($url);
  126.     }
  127.     /**
  128.      * {@inheritdoc}
  129.      */
  130.     public function getCredentials(Request $request)
  131.     {
  132.         $credentials = [];
  133.         if ($request->attributes->get('_route') === 'pimcore_admin_login_check') {
  134.             $username $request->get('username');
  135.             if ($request->getMethod() === 'POST' && $request->get('password') && $username) {
  136.                 $this->bruteforceProtectionHandler->checkProtection($username);
  137.                 $credentials = [
  138.                     'username' => $username,
  139.                     'password' => $request->get('password'),
  140.                 ];
  141.             } elseif ($token $request->get('token')) {
  142.                 $this->bruteforceProtectionHandler->checkProtection();
  143.                 $credentials = [
  144.                     'token' => $token,
  145.                     'reset' => (bool) $request->get('reset'false),
  146.                 ];
  147.             } else {
  148.                 $this->bruteforceProtectionHandler->checkProtection();
  149.                 throw new AuthenticationException('Missing username or token');
  150.             }
  151.             $event = new LoginCredentialsEvent($request$credentials);
  152.             $this->dispatcher->dispatch($eventAdminEvents::LOGIN_CREDENTIALS);
  153.             return $event->getCredentials();
  154.         } else {
  155.             if ($pimcoreUser Authentication::authenticateSession($request)) {
  156.                 return [
  157.                     'user' => $pimcoreUser,
  158.                 ];
  159.             }
  160.         }
  161.         return $credentials;
  162.     }
  163.     /**
  164.      * {@inheritdoc}
  165.      */
  166.     public function getUser($credentialsUserProviderInterface $userProvider)
  167.     {
  168.         /** @var User|null $user */
  169.         $user null;
  170.         if (!is_array($credentials)) {
  171.             throw new AuthenticationException('Invalid credentials');
  172.         }
  173.         if (isset($credentials['user']) && $credentials['user'] instanceof UserModel) {
  174.             $user = new User($credentials['user']);
  175.             $session Session::getReadOnly();
  176.             if ($session->has('2fa_required') && $session->get('2fa_required') === true) {
  177.                 $this->twoFactorRequired true;
  178.             }
  179.         } else {
  180.             if (!isset($credentials['username']) && !isset($credentials['token'])) {
  181.                 throw new AuthenticationException('Missing username/token');
  182.             }
  183.             if (isset($credentials['password'])) {
  184.                 $pimcoreUser Authentication::authenticatePlaintext($credentials['username'], $credentials['password']);
  185.                 if ($pimcoreUser) {
  186.                     $user = new User($pimcoreUser);
  187.                 } else {
  188.                     // trigger LOGIN_FAILED event if user could not be authenticated via username/password
  189.                     $event = new LoginFailedEvent($credentials);
  190.                     $this->dispatcher->dispatch($eventAdminEvents::LOGIN_FAILED);
  191.                     if ($event->hasUser()) {
  192.                         $user = new User($event->getUser());
  193.                     } else {
  194.                         throw new AuthenticationException('Failed to authenticate with username and password');
  195.                     }
  196.                 }
  197.             } elseif (isset($credentials['token'])) {
  198.                 $pimcoreUser Authentication::authenticateToken($credentials['token']);
  199.                 if ($pimcoreUser) {
  200.                     //disable two factor authentication for token based credentials e.g. reset password, admin access links
  201.                     $pimcoreUser->setTwoFactorAuthentication('required'false);
  202.                     $user = new User($pimcoreUser);
  203.                 } else {
  204.                     throw new AuthenticationException('Failed to authenticate with username and token');
  205.                 }
  206.                 if ($credentials['reset']) {
  207.                     // save the information to session when the user want's to reset the password
  208.                     // this is because otherwise the old password is required => see also PIMCORE-1468
  209.                     Session::useSession(function (AttributeBagInterface $adminSession) {
  210.                         $adminSession->set('password_reset'true);
  211.                     });
  212.                 }
  213.             } else {
  214.                 throw new AuthenticationException('Invalid authentication method, must be either password or token');
  215.             }
  216.             if ($user && Authentication::isValidUser($user->getUser())) {
  217.                 $pimcoreUser $user->getUser();
  218.                 Session::useSession(function (AttributeBagInterface $adminSession) use ($pimcoreUser) {
  219.                     Session::regenerateId();
  220.                     $adminSession->set('user'$pimcoreUser);
  221.                     // this flag gets removed after successful authentication in \Pimcore\Bundle\AdminBundle\EventListener\TwoFactorListener
  222.                     if ($pimcoreUser->getTwoFactorAuthentication('required') && $pimcoreUser->getTwoFactorAuthentication('enabled')) {
  223.                         $adminSession->set('2fa_required'true);
  224.                     }
  225.                 });
  226.             }
  227.         }
  228.         return $user;
  229.     }
  230.     /**
  231.      * {@inheritdoc}
  232.      */
  233.     public function checkCredentials($credentialsUserInterface $user)
  234.     {
  235.         // we rely on getUser returning a valid user
  236.         if ($user instanceof User) {
  237.             return true;
  238.         }
  239.         return false;
  240.     }
  241.     /**
  242.      * {@inheritdoc}
  243.      */
  244.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception)
  245.     {
  246.         $this->bruteforceProtectionHandler->addEntry($request->get('username'), $request);
  247.         $url $this->router->generate('pimcore_admin_login', [
  248.             'auth_failed' => 'true',
  249.         ]);
  250.         return new RedirectResponse($url);
  251.     }
  252.     /**
  253.      * {@inheritdoc}
  254.      */
  255.     public function onAuthenticationSuccess(Request $requestTokenInterface $token$providerKey)
  256.     {
  257.         /** @var UserModel $user */
  258.         $user $token->getUser()->getUser();
  259.         // set user language
  260.         $request->setLocale($user->getLanguage());
  261.         $this->translator->setLocale($user->getLanguage());
  262.         // set user on runtime cache for legacy compatibility
  263.         RuntimeCache::set('pimcore_admin_user'$user);
  264.         if ($user->isAdmin()) {
  265.             if (Admin::isMaintenanceModeScheduledForLogin()) {
  266.                 Admin::activateMaintenanceMode(Session::getSessionId());
  267.                 Admin::unscheduleMaintenanceModeOnLogin();
  268.             }
  269.         }
  270.         // as we authenticate statelessly (short lived sessions) the authentication is called for
  271.         // every request. therefore we only redirect if we're on the login page
  272.         if (!in_array($request->attributes->get('_route'), [
  273.             'pimcore_admin_login',
  274.             'pimcore_admin_login_check',
  275.         ])) {
  276.             return null;
  277.         }
  278.         $url null;
  279.         if ($request->get('deeplink') && $request->get('deeplink') !== 'true') {
  280.             $url $this->router->generate('pimcore_admin_login_deeplink');
  281.             $url .= '?' $request->get('deeplink');
  282.         } else {
  283.             $url $this->router->generate('pimcore_admin_index', [
  284.                 '_dc' => time(),
  285.                 'perspective' => strip_tags($request->get('perspective''')),
  286.             ]);
  287.         }
  288.         if ($url) {
  289.             $response = new RedirectResponse($url);
  290.             $response->headers->setCookie(new Cookie('pimcore_admin_sid'true));
  291.             return $response;
  292.         }
  293.         return null;
  294.     }
  295.     /**
  296.      * {@inheritdoc}
  297.      */
  298.     public function supportsRememberMe()
  299.     {
  300.         return false;
  301.     }
  302.     public function createAuthenticatedToken(UserInterface $user$providerKey)
  303.     {
  304.         if ($this->twoFactorRequired) {
  305.             return new LegacyTwoFactorRequiredToken(
  306.                 $user,
  307.                 $providerKey,
  308.                 $user->getRoles()
  309.             );
  310.         } else {
  311.             return parent::createAuthenticatedToken($user$providerKey);
  312.         }
  313.     }
  314. }