vendor/ibexa/core/src/lib/MVC/Symfony/Security/Authentication/RepositoryAuthenticationProvider.php line 23

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. namespace Ibexa\Core\MVC\Symfony\Security\Authentication;
  7. use Ibexa\Bundle\Core\DependencyInjection\Compiler\SecurityPass;
  8. use Ibexa\Contracts\Core\Repository\Exceptions\PasswordInUnsupportedFormatException;
  9. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  10. use Ibexa\Contracts\Core\Repository\UserService;
  11. use Ibexa\Core\MVC\Symfony\Security\UserInterface as IbexaUserInterface;
  12. use Ibexa\Core\Repository\User\Exception\UnsupportedPasswordHashType;
  13. use Psr\Log\LoggerAwareInterface;
  14. use Psr\Log\LoggerAwareTrait;
  15. use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider;
  16. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  17. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  18. use Symfony\Component\Security\Core\Exception\BadCredentialsException;
  19. use Symfony\Component\Security\Core\User\UserInterface;
  20. class RepositoryAuthenticationProvider extends DaoAuthenticationProvider implements LoggerAwareInterface
  21. {
  22.     use LoggerAwareTrait;
  23.     /** @var float|null */
  24.     private $constantAuthTime;
  25.     /** @var \Ibexa\Contracts\Core\Repository\PermissionResolver */
  26.     private $permissionResolver;
  27.     /** @var \Ibexa\Contracts\Core\Repository\UserService */
  28.     private $userService;
  29.     public function setConstantAuthTime(float $constantAuthTime)
  30.     {
  31.         $this->constantAuthTime $constantAuthTime;
  32.     }
  33.     public function setPermissionResolver(PermissionResolver $permissionResolver)
  34.     {
  35.         $this->permissionResolver $permissionResolver;
  36.     }
  37.     public function setUserService(UserService $userService)
  38.     {
  39.         $this->userService $userService;
  40.     }
  41.     protected function checkAuthentication(UserInterface $userUsernamePasswordToken $token)
  42.     {
  43.         if (!$user instanceof IbexaUserInterface) {
  44.             parent::checkAuthentication($user$token);
  45.             return;
  46.         }
  47.         $apiUser $user->getAPIUser();
  48.         // $currentUser can either be an instance of UserInterface or just the username (e.g. during form login).
  49.         /** @var \Ibexa\Core\MVC\Symfony\Security\UserInterface|string $currentUser */
  50.         $currentUser $token->getUser();
  51.         if ($currentUser instanceof UserInterface) {
  52.             if ($currentUser->getAPIUser()->passwordHash !== $apiUser->passwordHash) {
  53.                 throw new BadCredentialsException('The credentials were changed in another session.');
  54.             }
  55.             $apiUser $currentUser->getAPIUser();
  56.         } else {
  57.             $credentialsValid $this->userService->checkUserCredentials($apiUser$token->getCredentials());
  58.             if (!$credentialsValid) {
  59.                 throw new BadCredentialsException('Invalid credentials'0);
  60.             }
  61.         }
  62.         // Finally inject current user in the Repository
  63.         $this->permissionResolver->setCurrentUserReference($apiUser);
  64.     }
  65.     /**
  66.      * @throws \Ibexa\Contracts\Core\Repository\Exceptions\PasswordInUnsupportedFormatException
  67.      */
  68.     public function authenticate(TokenInterface $token)
  69.     {
  70.         $startTime $this->startConstantTimer();
  71.         try {
  72.             $result parent::authenticate($token);
  73.         } catch (UnsupportedPasswordHashType $exception) {
  74.             $this->sleepUsingConstantTimer($startTime);
  75.             throw new PasswordInUnsupportedFormatException($exception);
  76.         } catch (\Exception $e) {
  77.             $this->sleepUsingConstantTimer($startTime);
  78.             throw $e;
  79.         }
  80.         $this->sleepUsingConstantTimer($startTime);
  81.         return $result;
  82.     }
  83.     private function startConstantTimer()
  84.     {
  85.         return microtime(true);
  86.     }
  87.     private function sleepUsingConstantTimer(float $startTime): void
  88.     {
  89.         if ($this->constantAuthTime <= 0.0) {
  90.             return;
  91.         }
  92.         $remainingTime $this->constantAuthTime - (microtime(true) - $startTime);
  93.         if ($remainingTime 0) {
  94.             usleep($remainingTime 1000000);
  95.         } elseif ($this->logger) {
  96.             $this->logger->warning(
  97.                 sprintf(
  98.                     'Authentication took longer than the configured constant time. Consider increasing the value of %s',
  99.                     SecurityPass::CONSTANT_AUTH_TIME_SETTING
  100.                 ),
  101.                 [static::class]
  102.             );
  103.         }
  104.     }
  105. }
  106. class_alias(RepositoryAuthenticationProvider::class, 'eZ\Publish\Core\MVC\Symfony\Security\Authentication\RepositoryAuthenticationProvider');