mirror of
https://github.com/webmasterskaya/joomla-oauth-server.git
synced 2024-11-23 18:24:50 +03:00
Add JWT token in query validator
This commit is contained in:
parent
5e8ccd7c66
commit
5faaf7eb24
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Webmasterskaya\Component\OauthServer\Administrator\AuthorizationValidators;
|
||||
|
||||
use Lcobucci\Clock\SystemClock;
|
||||
use Lcobucci\JWT\Configuration;
|
||||
use Lcobucci\JWT\Signer\Key\InMemory;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
|
||||
use Lcobucci\JWT\Validation\Constraint\SignedWith;
|
||||
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
||||
use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class JwtInQueryTokenValidator implements AuthorizationValidatorInterface
|
||||
{
|
||||
use CryptTrait;
|
||||
|
||||
/**
|
||||
* @var AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
protected $publicKey;
|
||||
|
||||
/**
|
||||
* @var Configuration
|
||||
*/
|
||||
private $jwtConfiguration;
|
||||
|
||||
/**
|
||||
* @var \DateInterval|null
|
||||
*/
|
||||
private $jwtValidAtDateLeeway;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $queryParamName;
|
||||
|
||||
/**
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param \DateInterval|null $jwtValidAtDateLeeway
|
||||
* @param string $queryParamName
|
||||
*/
|
||||
public function __construct(AccessTokenRepositoryInterface $accessTokenRepository, \DateInterval $jwtValidAtDateLeeway = null, string $queryParamName = 'access_token')
|
||||
{
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
$this->jwtValidAtDateLeeway = $jwtValidAtDateLeeway;
|
||||
$this->queryParamName = $queryParamName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the public key
|
||||
*
|
||||
* @param CryptKey $key
|
||||
*/
|
||||
public function setPublicKey(CryptKey $key)
|
||||
{
|
||||
$this->publicKey = $key;
|
||||
|
||||
$this->initJwtConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the JWT configuration.
|
||||
*/
|
||||
private function initJwtConfiguration()
|
||||
{
|
||||
$this->jwtConfiguration = Configuration::forSymmetricSigner(
|
||||
new Sha256(),
|
||||
InMemory::plainText('empty', 'empty')
|
||||
);
|
||||
|
||||
$clock = new SystemClock(new \DateTimeZone(\date_default_timezone_get()));
|
||||
$this->jwtConfiguration->setValidationConstraints(
|
||||
new LooseValidAt($clock, $this->jwtValidAtDateLeeway),
|
||||
new SignedWith(
|
||||
new Sha256(),
|
||||
InMemory::plainText($this->publicKey->getKeyContents(), $this->publicKey->getPassPhrase() ?? '')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAuthorization(ServerRequestInterface $request)
|
||||
{
|
||||
$query = $request->getQueryParams();
|
||||
if (!key_exists($this->queryParamName, $query)
|
||||
|| empty($query[$this->queryParamName])) {
|
||||
throw OAuthServerException::accessDenied(sprintf('Missing parameter "%s" in query', $this->queryParamName));
|
||||
}
|
||||
|
||||
$jwt = \trim((string)$query[$this->queryParamName]);
|
||||
|
||||
try {
|
||||
// Attempt to parse the JWT
|
||||
$token = $this->jwtConfiguration->parser()->parse($jwt);
|
||||
} catch (\Lcobucci\JWT\Exception $exception) {
|
||||
throw OAuthServerException::accessDenied($exception->getMessage(), null, $exception);
|
||||
}
|
||||
|
||||
try {
|
||||
// Attempt to validate the JWT
|
||||
$constraints = $this->jwtConfiguration->validationConstraints();
|
||||
$this->jwtConfiguration->validator()->assert($token, ...$constraints);
|
||||
} catch (RequiredConstraintsViolated $exception) {
|
||||
throw OAuthServerException::accessDenied('Access token could not be verified', null, $exception);
|
||||
}
|
||||
|
||||
$claims = $token->claims();
|
||||
|
||||
// Check if token has been revoked
|
||||
if ($this->accessTokenRepository->isAccessTokenRevoked($claims->get('jti'))) {
|
||||
throw OAuthServerException::accessDenied('Access token has been revoked');
|
||||
}
|
||||
|
||||
// Return the request with additional attributes
|
||||
return $request
|
||||
->withAttribute('oauth_access_token_id', $claims->get('jti'))
|
||||
->withAttribute('oauth_client_id', $this->convertSingleRecordAudToString($claims->get('aud')))
|
||||
->withAttribute('oauth_user_id', $claims->get('sub'))
|
||||
->withAttribute('oauth_scopes', $claims->get('scopes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert single record arrays into strings to ensure backwards compatibility between v4 and v3.x of lcobucci/jwt
|
||||
*
|
||||
* @param mixed $aud
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
private function convertSingleRecordAudToString($aud)
|
||||
{
|
||||
return \is_array($aud) && \count($aud) === 1 ? $aud[0] : $aud;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user