Created
October 22, 2020 14:40
-
-
Save ahmed-bhs/f7117b9b24ed2622c078b7e5e0d19d25 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @copyright Copyright (C) eZ Systems AS. All rights reserved. | |
* @license For full copyright and license information view LICENSE file distributed with this source code. | |
*/ | |
declare(strict_types=1); | |
namespace EzSystems\EzPlatformPageBuilder\Security\EditorialMode; | |
use eZ\Publish\API\Repository\PermissionResolver; | |
use eZ\Publish\Core\MVC\Symfony\Security\UserInterface; | |
use eZ\Publish\Core\MVC\Symfony\SiteAccess; | |
use EzSystems\EzPlatformAdminUi\Specification\SiteAccess\IsAdmin; | |
use InvalidArgumentException; | |
use Lexik\Bundle\JWTAuthenticationBundle\Exception\ExpiredTokenException; | |
use Lexik\Bundle\JWTAuthenticationBundle\Exception\InvalidTokenException; | |
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException; | |
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor; | |
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\TokenExtractorInterface; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Symfony\Component\Security\Core\User\UserProviderInterface; | |
use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface; | |
class TokenAuthenticator implements SimplePreAuthenticatorInterface | |
{ | |
/** @var \EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenManager */ | |
private $tokenManager; | |
/** @var \EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenRevokerInterface */ | |
private $tokenRevoker; | |
/** @var \eZ\Publish\API\Repository\PermissionResolver */ | |
private $permissionResolver; | |
/** @var bool */ | |
private $enabled; | |
/** @var array */ | |
private $siteAccessGroups; | |
/** @var string */ | |
private $tokenQueryParamName; | |
/** | |
* @param \EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenManager $tokenManager | |
* @param \EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenRevokerInterface $tokenRevoker | |
* @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver | |
* @param string $tokenQueryParamName | |
* @param bool $enabled | |
* @param array $siteAccessGroups | |
*/ | |
public function __construct( | |
TokenManager $tokenManager, | |
TokenRevokerInterface $tokenRevoker, | |
PermissionResolver $permissionResolver, | |
string $tokenQueryParamName, | |
bool $enabled, | |
array $siteAccessGroups | |
) { | |
$this->tokenManager = $tokenManager; | |
$this->tokenRevoker = $tokenRevoker; | |
$this->tokenQueryParamName = $tokenQueryParamName; | |
$this->permissionResolver = $permissionResolver; | |
$this->enabled = $enabled; | |
$this->siteAccessGroups = $siteAccessGroups; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) | |
{ | |
if (!($token instanceof PreAuthenticatedToken)) { | |
throw new InvalidArgumentException(sprintf( | |
'The token must be instance of PreAuthenticatedToken (%s was given).', | |
get_class($token) | |
)); | |
} | |
$payload = $token->getCredentials(); | |
$user = $token->getUser(); | |
if (!($user instanceof UserInterface)) { | |
$user = $userProvider->loadUserByUsername($token->getUsername()); | |
} | |
if (!$this->tokenRevoker->isValid($token)) { | |
throw new InvalidTokenException('Revoked JWT Token'); | |
} | |
$this->tokenRevoker->revoke($token); | |
$this->permissionResolver->setCurrentUserReference( | |
$user->getAPIUserReference() | |
); | |
return new PreAuthenticatedToken( | |
$user, | |
$payload, | |
$providerKey, | |
$user->getRoles() | |
); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function supportsToken(TokenInterface $token, $providerKey) | |
{ | |
return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey; | |
} | |
/** | |
* Returns name of query parameter used to pass token. | |
* | |
* @return string | |
*/ | |
public function getTokenQueryParamName(): string | |
{ | |
return $this->tokenQueryParamName; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function createToken(Request $request, $providerKey) | |
{ | |
if (!$this->isEnabled()) { | |
return null; | |
} | |
if ($this->isAdminSiteAccess($request)) { | |
return null; | |
} | |
$jsonWebToken = $this->getTokenExtractor()->extract($request); | |
if (false === $jsonWebToken) { | |
return null; | |
} | |
try { | |
if (!($payload = $this->tokenManager->decodeFromString($jsonWebToken))) { | |
throw new InvalidTokenException('Invalid JWT Token'); | |
} | |
} catch (JWTDecodeFailureException $e) { | |
if (JWTDecodeFailureException::EXPIRED_TOKEN === $e->getReason()) { | |
throw new ExpiredTokenException(); | |
} | |
throw new InvalidTokenException('Invalid JWT Token', 0, $e); | |
} | |
$username = $payload[$this->tokenManager->getUserIdentityField()]; | |
return new PreAuthenticatedToken( | |
$username, | |
$payload, | |
$providerKey | |
); | |
} | |
/** | |
* Returns true if token based authentication is enabled. | |
* | |
* @return bool | |
*/ | |
public function isEnabled(): bool | |
{ | |
return $this->enabled; | |
} | |
/** | |
* Returns true if the siteaccess of given request is administrative. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* | |
* @return bool | |
*/ | |
private function isAdminSiteAccess(Request $request): bool | |
{ | |
$siteaccess = $request->attributes->get('siteaccess', null); | |
if ($siteaccess instanceof SiteAccess) { | |
return (new IsAdmin($this->siteAccessGroups))->isSatisfiedBy($siteaccess); | |
} | |
return false; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
private function getTokenExtractor(): TokenExtractorInterface | |
{ | |
return new TokenExtractor\QueryParameterTokenExtractor($this->tokenQueryParamName); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment