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

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