Skip to content

Add token revocation support #995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/AuthorizationServer.php
Original file line number Diff line number Diff line change
@@ -34,6 +34,11 @@ class AuthorizationServer implements EmitterAwareInterface
*/
protected $enabledGrantTypes = [];

/**
* @var RevokeTokenHandler
*/
protected $revokeTokenHandler = null;

/**
* @var DateInterval[]
*/
@@ -206,6 +211,45 @@ public function respondToAccessTokenRequest(ServerRequestInterface $request, Res
throw OAuthServerException::unsupportedGrantType();
}

/**
* Enable the revoke token handler on the server.
*
* @param RevokeTokenHandler $handler
*/
public function enableRevokeTokenHandler(RevokeTokenHandler $handler)
{
$handler->setAccessTokenRepository($this->accessTokenRepository);
$handler->setClientRepository($this->clientRepository);
$handler->setEncryptionKey($this->encryptionKey);
$handler->setEmitter($this->getEmitter());

$this->revokeTokenHandler = $handler;
}

/**
* Return an revoke token response.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
*
* @throws OAuthServerException
*
* @return ResponseInterface
*/
public function respondToRevokeTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
{
if ($this->revokeTokenHandler !== null) {
$revokeResponse = $this->revokeTokenHandler->respondToRevokeTokenRequest($request, $this->getResponseType());

if ($revokeResponse instanceof ResponseTypeInterface) {
return $revokeResponse->generateHttpResponse($response);
}
}

$errorMessage = 'Token revocation not supported.';
throw new OAuthServerException($errorMessage, 3, 'invalid_request', 400);
}

/**
* Get the token type that grants will return in the HTTP response.
*
173 changes: 10 additions & 163 deletions src/Grant/AbstractGrant.php
Original file line number Diff line number Diff line change
@@ -30,8 +30,8 @@
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
use League\OAuth2\Server\RequestEvent;
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
use League\OAuth2\Server\RequestValidatorTrait;
use LogicException;
use Psr\Http\Message\ServerRequestInterface;
use TypeError;
@@ -41,7 +41,7 @@
*/
abstract class AbstractGrant implements GrantTypeInterface
{
use EmitterAwareTrait, CryptTrait;
use EmitterAwareTrait, CryptTrait, RequestValidatorTrait;

const SCOPE_DELIMITER_STRING = ' ';

@@ -92,6 +92,14 @@ abstract class AbstractGrant implements GrantTypeInterface
*/
protected $defaultScope;

/**
* @return ClientRepositoryInterface
*/
public function getClientRepository()
{
return $this->clientRepository;
}

/**
* @param ClientRepositoryInterface $clientRepository
*/
@@ -166,76 +174,6 @@ public function setDefaultScope($scope)
$this->defaultScope = $scope;
}

/**
* Validate the client.
*
* @param ServerRequestInterface $request
*
* @throws OAuthServerException
*
* @return ClientEntityInterface
*/
protected function validateClient(ServerRequestInterface $request)
{
list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);

$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
if ($clientId === null) {
throw OAuthServerException::invalidRequest('client_id');
}

// If the client is confidential require the client secret
$clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);

$client = $this->clientRepository->getClientEntity(
$clientId,
$this->getIdentifier(),
$clientSecret,
true
);

if ($client instanceof ClientEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient();
}

$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);

if ($redirectUri !== null) {
$this->validateRedirectUri($redirectUri, $client, $request);
}

return $client;
}

/**
* Validate redirectUri from the request.
* If a redirect URI is provided ensure it matches what is pre-registered
*
* @param string $redirectUri
* @param ClientEntityInterface $client
* @param ServerRequestInterface $request
*
* @throws OAuthServerException
*/
protected function validateRedirectUri(
string $redirectUri,
ClientEntityInterface $client,
ServerRequestInterface $request
) {
if (\is_string($client->getRedirectUri())
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient();
} elseif (\is_array($client->getRedirectUri())
&& \in_array($redirectUri, $client->getRedirectUri(), true) === false
) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient();
}
}

/**
* Validate scopes in the request.
*
@@ -281,97 +219,6 @@ private function convertScopesQueryStringToArray($scopes)
});
}

/**
* Retrieve request parameter.
*
* @param string $parameter
* @param ServerRequestInterface $request
* @param mixed $default
*
* @return null|string
*/
protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null)
{
$requestParameters = (array) $request->getParsedBody();

return $requestParameters[$parameter] ?? $default;
}

/**
* Retrieve HTTP Basic Auth credentials with the Authorization header
* of a request. First index of the returned array is the username,
* second is the password (so list() will work). If the header does
* not exist, or is otherwise an invalid HTTP Basic header, return
* [null, null].
*
* @param ServerRequestInterface $request
*
* @return string[]|null[]
*/
protected function getBasicAuthCredentials(ServerRequestInterface $request)
{
if (!$request->hasHeader('Authorization')) {
return [null, null];
}

$header = $request->getHeader('Authorization')[0];
if (strpos($header, 'Basic ') !== 0) {
return [null, null];
}

if (!($decoded = base64_decode(substr($header, 6)))) {
return [null, null];
}

if (strpos($decoded, ':') === false) {
return [null, null]; // HTTP Basic header without colon isn't valid
}

return explode(':', $decoded, 2);
}

/**
* Retrieve query string parameter.
*
* @param string $parameter
* @param ServerRequestInterface $request
* @param mixed $default
*
* @return null|string
*/
protected function getQueryStringParameter($parameter, ServerRequestInterface $request, $default = null)
{
return isset($request->getQueryParams()[$parameter]) ? $request->getQueryParams()[$parameter] : $default;
}

/**
* Retrieve cookie parameter.
*
* @param string $parameter
* @param ServerRequestInterface $request
* @param mixed $default
*
* @return null|string
*/
protected function getCookieParameter($parameter, ServerRequestInterface $request, $default = null)
{
return isset($request->getCookieParams()[$parameter]) ? $request->getCookieParams()[$parameter] : $default;
}

/**
* Retrieve server parameter.
*
* @param string $parameter
* @param ServerRequestInterface $request
* @param mixed $default
*
* @return null|string
*/
protected function getServerParameter($parameter, ServerRequestInterface $request, $default = null)
{
return isset($request->getServerParams()[$parameter]) ? $request->getServerParams()[$parameter] : $default;
}

/**
* Issue an access token.
*
Loading
Oops, something went wrong.