vendor/ezsystems/ezplatform-page-builder/src/lib/Security/EditorialMode/TokenAuthenticator.php line 24

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) eZ Systems AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. declare(strict_types=1);
  7. namespace EzSystems\EzPlatformPageBuilder\Security\EditorialMode;
  8. use eZ\Publish\Core\MVC\Symfony\SiteAccess;
  9. use EzSystems\EzPlatformAdminUi\Specification\SiteAccess\IsAdmin;
  10. use Lexik\Bundle\JWTAuthenticationBundle\Exception\ExpiredTokenException;
  11. use Lexik\Bundle\JWTAuthenticationBundle\Exception\InvalidTokenException;
  12. use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  15. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  16. use Symfony\Component\Security\Core\Security;
  17. use Symfony\Component\Security\Core\User\UserInterface;
  18. use Symfony\Component\Security\Core\User\UserProviderInterface;
  19. use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
  20. class TokenAuthenticator extends AbstractGuardAuthenticator
  21. {
  22.     /** @var \Symfony\Component\Security\Core\Security */
  23.     private $security;
  24.     /** @var \EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenManager */
  25.     private $tokenManager;
  26.     /** @var \EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenRevokerInterface */
  27.     private $tokenRevoker;
  28.     /** @var bool */
  29.     private $enabled;
  30.     /** @var array */
  31.     private $siteAccessGroups;
  32.     /** @var string */
  33.     private $tokenQueryParamName;
  34.     /** @var string */
  35.     private $tokenCookieName;
  36.     public function __construct(
  37.         Security $security,
  38.         TokenManager $tokenManager,
  39.         TokenRevokerInterface $tokenRevoker,
  40.         string $tokenQueryParamName,
  41.         string $tokenCookieName,
  42.         bool $enabled,
  43.         array $siteAccessGroups
  44.     ) {
  45.         $this->security $security;
  46.         $this->tokenManager $tokenManager;
  47.         $this->tokenRevoker $tokenRevoker;
  48.         $this->tokenQueryParamName $tokenQueryParamName;
  49.         $this->tokenCookieName $tokenCookieName;
  50.         $this->enabled $enabled;
  51.         $this->siteAccessGroups $siteAccessGroups;
  52.     }
  53.     public function start(Request $requestAuthenticationException $authException null)
  54.     {
  55.     }
  56.     public function supports(Request $request): bool
  57.     {
  58.         if (!$this->isEnabled() || $this->isAdminSiteAccess($request)) {
  59.             return false;
  60.         }
  61.         if (!$this->hasToken($request)) {
  62.             return false;
  63.         }
  64.         if ($this->security->getUser() && !$this->isUserSwitch($request)) {
  65.             return false;
  66.         }
  67.         return true;
  68.     }
  69.     public function getCredentials(Request $request)
  70.     {
  71.         $rawToken $request->query->get($this->getTokenQueryParamName())
  72.             ?? $request->cookies->get($this->getTokenCookieName());
  73.         try {
  74.             $token $this->tokenManager->decodeFromString($rawToken);
  75.             if ($token === false) {
  76.                 throw new InvalidTokenException('Invalid JWT Token');
  77.             }
  78.             return $token;
  79.         } catch (JWTDecodeFailureException $e) {
  80.             if (JWTDecodeFailureException::EXPIRED_TOKEN === $e->getReason()) {
  81.                 throw new ExpiredTokenException();
  82.             }
  83.             throw new InvalidTokenException('Invalid JWT Token'0$e);
  84.         }
  85.     }
  86.     public function getUser($credentialsUserProviderInterface $userProvider)
  87.     {
  88.         if (null === $credentials) {
  89.             // The token header was empty, authentication fails with 401
  90.             return null;
  91.         }
  92.         $username $credentials[$this->tokenManager->getUserIdentityField()];
  93.         return $userProvider->loadUserByUsername($username);
  94.     }
  95.     public function checkCredentials($credentialsUserInterface $user)
  96.     {
  97.         if ($this->tokenRevoker->isValid($credentials)) {
  98.             $this->tokenRevoker->revoke($credentials);
  99.             return true;
  100.         }
  101.         return false;
  102.     }
  103.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception)
  104.     {
  105.     }
  106.     public function onAuthenticationSuccess(Request $requestTokenInterface $token$providerKey)
  107.     {
  108.         return null;
  109.     }
  110.     public function supportsRememberMe(): bool
  111.     {
  112.         return false;
  113.     }
  114.     private function isUserSwitch(Request $request): bool
  115.     {
  116.         $rawToken $request->query->get($this->getTokenQueryParamName())
  117.             ?? $request->cookies->get($this->getTokenCookieName());
  118.         try {
  119.             $token $this->tokenManager->decodeFromString($rawToken);
  120.             if ($token === false) {
  121.                 return false;
  122.             }
  123.             $currentUsername $this->security->getUser()->getUsername();
  124.             $tokenUsername $token[$this->tokenManager->getUserIdentityField()];
  125.             return $currentUsername !== $tokenUsername;
  126.         } catch (JWTDecodeFailureException $e) {
  127.             return false;
  128.         }
  129.     }
  130.     private function hasToken(Request $request): bool
  131.     {
  132.         $hasTokenInQueryParam $request->query->has($this->getTokenQueryParamName());
  133.         $hasTokenInCookie $request->cookies->has($this->getTokenCookieName());
  134.         return $hasTokenInQueryParam || $hasTokenInCookie;
  135.     }
  136.     /**
  137.      * Returns true if token based authentication is enabled.
  138.      */
  139.     public function isEnabled(): bool
  140.     {
  141.         return $this->enabled;
  142.     }
  143.     /**
  144.      * Returns name of query parameter used to pass token.
  145.      */
  146.     public function getTokenQueryParamName(): string
  147.     {
  148.         return $this->tokenQueryParamName;
  149.     }
  150.     /**
  151.      * Returns name of cookie used to pass token.
  152.      */
  153.     public function getTokenCookieName(): string
  154.     {
  155.         return $this->tokenCookieName;
  156.     }
  157.     /**
  158.      * Create an authenticated token for the given user.
  159.      */
  160.     public function createAuthenticatedToken(UserInterface $userstring $providerKey): PostAuthenticationGuardToken
  161.     {
  162.         return new PostAuthenticationGuardToken(
  163.             $user,
  164.             $providerKey,
  165.             $user->getRoles()
  166.         );
  167.     }
  168.     /**
  169.      * Returns true if the siteaccess of given request is administrative.
  170.      */
  171.     private function isAdminSiteAccess(Request $request): bool
  172.     {
  173.         $siteaccess $request->attributes->get('siteaccess'null);
  174.         if ($siteaccess instanceof SiteAccess) {
  175.             return (new IsAdmin($this->siteAccessGroups))->isSatisfiedBy($siteaccess);
  176.         }
  177.         return false;
  178.     }
  179.     /**
  180.      * {@inheritdoc}
  181.      */
  182.     private function getTokenExtractor(): TokenExtractorInterface
  183.     {
  184.         return new TokenExtractor\ChainTokenExtractor([
  185.             new TokenExtractor\QueryParameterTokenExtractor($this->tokenQueryParamName),
  186.             new TokenExtractor\CookieTokenExtractor($this->tokenCookieName),
  187.         ]);
  188.     }
  189. }