add oauth2/oidc lib

This commit is contained in:
zotlabs
2016-10-07 14:11:24 -07:00
parent bf02e04283
commit 10863a5949
121 changed files with 14970 additions and 0 deletions

View File

@@ -0,0 +1,388 @@
<?php
namespace OAuth2\Controller;
use OAuth2\Storage\ClientInterface;
use OAuth2\ScopeInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use OAuth2\Scope;
/**
* @see OAuth2\Controller\AuthorizeControllerInterface
*/
class AuthorizeController implements AuthorizeControllerInterface
{
private $scope;
private $state;
private $client_id;
private $redirect_uri;
private $response_type;
protected $clientStorage;
protected $responseTypes;
protected $config;
protected $scopeUtil;
/**
* @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
* @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
* keys are "code" and "token"
* @param array $config OPTIONAL Configuration options for the server
* <code>
* $config = array(
* 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
* 'enforce_state' => true // if the controller should require the "state" parameter
* 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
* 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
* );
* </code>
* @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
*/
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
{
$this->clientStorage = $clientStorage;
$this->responseTypes = $responseTypes;
$this->config = array_merge(array(
'allow_implicit' => false,
'enforce_state' => true,
'require_exact_redirect_uri' => true,
'redirect_status_code' => 302,
), $config);
if (is_null($scopeUtil)) {
$scopeUtil = new Scope();
}
$this->scopeUtil = $scopeUtil;
}
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
{
if (!is_bool($is_authorized)) {
throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
}
// We repeat this, because we need to re-validate. The request could be POSTed
// by a 3rd-party (because we are not internally enforcing NONCEs, etc)
if (!$this->validateAuthorizeRequest($request, $response)) {
return;
}
// If no redirect_uri is passed in the request, use client's registered one
if (empty($this->redirect_uri)) {
$clientData = $this->clientStorage->getClientDetails($this->client_id);
$registered_redirect_uri = $clientData['redirect_uri'];
}
// the user declined access to the client's application
if ($is_authorized === false) {
$redirect_uri = $this->redirect_uri ?: $registered_redirect_uri;
$this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id);
return;
}
// build the parameters to set in the redirect URI
if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) {
return;
}
$authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id);
list($redirect_uri, $uri_params) = $authResult;
if (empty($redirect_uri) && !empty($registered_redirect_uri)) {
$redirect_uri = $registered_redirect_uri;
}
$uri = $this->buildUri($redirect_uri, $uri_params);
// return redirect response
$response->setRedirect($this->config['redirect_status_code'], $uri);
}
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
{
$error = 'access_denied';
$error_message = 'The user denied access to your application';
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
}
/*
* We have made this protected so this class can be extended to add/modify
* these parameters
*/
protected function buildAuthorizeParameters($request, $response, $user_id)
{
// @TODO: we should be explicit with this in the future
$params = array(
'scope' => $this->scope,
'state' => $this->state,
'client_id' => $this->client_id,
'redirect_uri' => $this->redirect_uri,
'response_type' => $this->response_type,
);
return $params;
}
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
{
// Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI)
if (!$client_id = $request->query('client_id', $request->request('client_id'))) {
// We don't have a good URI to use
$response->setError(400, 'invalid_client', "No client id supplied");
return false;
}
// Get client details
if (!$clientData = $this->clientStorage->getClientDetails($client_id)) {
$response->setError(400, 'invalid_client', 'The client id supplied is invalid');
return false;
}
$registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : '';
// Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI.
// @see http://tools.ietf.org/html/rfc6749#section-3.1.2
// @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1
// @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1
if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) {
// validate there is no fragment supplied
$parts = parse_url($supplied_redirect_uri);
if (isset($parts['fragment']) && $parts['fragment']) {
$response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment');
return false;
}
// validate against the registered redirect uri(s) if available
if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) {
$response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2');
return false;
}
$redirect_uri = $supplied_redirect_uri;
} else {
// use the registered redirect_uri if none has been supplied, if possible
if (!$registered_redirect_uri) {
$response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored');
return false;
}
if (count(explode(' ', $registered_redirect_uri)) > 1) {
$response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3');
return false;
}
$redirect_uri = $registered_redirect_uri;
}
// Select the redirect URI
$response_type = $request->query('response_type', $request->request('response_type'));
// for multiple-valued response types - make them alphabetical
if (false !== strpos($response_type, ' ')) {
$types = explode(' ', $response_type);
sort($types);
$response_type = ltrim(implode(' ', $types));
}
$state = $request->query('state', $request->request('state'));
// type and client_id are required
if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null);
return false;
}
if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
if (!isset($this->responseTypes['code'])) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null);
return false;
}
if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
return false;
}
if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) {
$response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied');
return false;
}
} else {
if (!$this->config['allow_implicit']) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null);
return false;
}
if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
return false;
}
}
// validate requested scope if it exists
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
if ($requestedScope) {
// restrict scope by client specific scope if applicable,
// otherwise verify the scope exists
$clientScope = $this->clientStorage->getClientScope($client_id);
if ((empty($clientScope) && !$this->scopeUtil->scopeExists($requestedScope))
|| (!empty($clientScope) && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null);
return false;
}
} else {
// use a globally-defined default scope
$defaultScope = $this->scopeUtil->getDefaultScope($client_id);
if (false === $defaultScope) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null);
return false;
}
$requestedScope = $defaultScope;
}
// Validate state parameter exists (if configured to enforce this)
if ($this->config['enforce_state'] && !$state) {
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required');
return false;
}
// save the input data and return true
$this->scope = $requestedScope;
$this->state = $state;
$this->client_id = $client_id;
// Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3)
$this->redirect_uri = $supplied_redirect_uri;
$this->response_type = $response_type;
return true;
}
/**
* Build the absolute URI based on supplied URI and parameters.
*
* @param $uri An absolute URI.
* @param $params Parameters to be append as GET.
*
* @return
* An absolute URI with supplied parameters.
*
* @ingroup oauth2_section_4
*/
private function buildUri($uri, $params)
{
$parse_url = parse_url($uri);
// Add our params to the parsed uri
foreach ($params as $k => $v) {
if (isset($parse_url[$k])) {
$parse_url[$k] .= "&" . http_build_query($v, '', '&');
} else {
$parse_url[$k] = http_build_query($v, '', '&');
}
}
// Put humpty dumpty back together
return
((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
. ((isset($parse_url["user"])) ? $parse_url["user"]
. ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "")
. ((isset($parse_url["host"])) ? $parse_url["host"] : "")
. ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "")
. ((isset($parse_url["path"])) ? $parse_url["path"] : "")
. ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "")
. ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "")
;
}
protected function getValidResponseTypes()
{
return array(
self::RESPONSE_TYPE_ACCESS_TOKEN,
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
);
}
/**
* Internal method for validating redirect URI supplied
*
* @param string $inputUri The submitted URI to be validated
* @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
* allow for multiple URIs
*
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2
*/
protected function validateRedirectUri($inputUri, $registeredUriString)
{
if (!$inputUri || !$registeredUriString) {
return false; // if either one is missing, assume INVALID
}
$registered_uris = explode(' ', $registeredUriString);
foreach ($registered_uris as $registered_uri) {
if ($this->config['require_exact_redirect_uri']) {
// the input uri is validated against the registered uri using exact match
if (strcmp($inputUri, $registered_uri) === 0) {
return true;
}
} else {
$registered_uri_length = strlen($registered_uri);
if ($registered_uri_length === 0) {
return false;
}
// the input uri is validated against the registered uri using case-insensitive match of the initial string
// i.e. additional query parameters may be applied
if (strcasecmp(substr($inputUri, 0, $registered_uri_length), $registered_uri) === 0) {
return true;
}
}
}
return false;
}
/**
* Convenience methods to access the parameters derived from the validated request
*/
public function getScope()
{
return $this->scope;
}
public function getState()
{
return $this->state;
}
public function getClientId()
{
return $this->client_id;
}
public function getRedirectUri()
{
return $this->redirect_uri;
}
public function getResponseType()
{
return $this->response_type;
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace OAuth2\Controller;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
/**
* This controller is called when a user should be authorized
* by an authorization server. As OAuth2 does not handle
* authorization directly, this controller ensures the request is valid, but
* requires the application to determine the value of $is_authorized
*
* ex:
* > $user_id = $this->somehowDetermineUserId();
* > $is_authorized = $this->somehowDetermineUserAuthorization();
* > $response = new OAuth2\Response();
* > $authorizeController->handleAuthorizeRequest(
* > OAuth2\Request::createFromGlobals(),
* > $response,
* > $is_authorized,
* > $user_id);
* > $response->send();
*
*/
interface AuthorizeControllerInterface
{
/**
* List of possible authentication response types.
* The "authorization_code" mechanism exclusively supports 'code'
* and the "implicit" mechanism exclusively supports 'token'.
*
* @var string
* @see http://tools.ietf.org/html/rfc6749#section-4.1.1
* @see http://tools.ietf.org/html/rfc6749#section-4.2.1
*/
const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null);
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response);
}

View File

@@ -0,0 +1,111 @@
<?php
namespace OAuth2\Controller;
use OAuth2\TokenType\TokenTypeInterface;
use OAuth2\Storage\AccessTokenInterface;
use OAuth2\ScopeInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use OAuth2\Scope;
/**
* @see OAuth2\Controller\ResourceControllerInterface
*/
class ResourceController implements ResourceControllerInterface
{
private $token;
protected $tokenType;
protected $tokenStorage;
protected $config;
protected $scopeUtil;
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
{
$this->tokenType = $tokenType;
$this->tokenStorage = $tokenStorage;
$this->config = array_merge(array(
'www_realm' => 'Service',
), $config);
if (is_null($scopeUtil)) {
$scopeUtil = new Scope();
}
$this->scopeUtil = $scopeUtil;
}
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null)
{
$token = $this->getAccessTokenData($request, $response);
// Check if we have token data
if (is_null($token)) {
return false;
}
/**
* Check scope, if provided
* If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403
* @see http://tools.ietf.org/html/rfc6750#section-3.1
*/
if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) {
$response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token');
$response->addHttpHeaders(array(
'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"',
$this->tokenType->getTokenType(),
$this->config['www_realm'],
$scope,
$response->getParameter('error'),
$response->getParameter('error_description')
)
));
return false;
}
// allow retrieval of the token
$this->token = $token;
return (bool) $token;
}
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response)
{
// Get the token parameter
if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) {
// Get the stored token data (from the implementing subclass)
// Check we have a well formed token
// Check token expiration (expires is a mandatory paramter)
if (!$token = $this->tokenStorage->getAccessToken($token_param)) {
$response->setError(401, 'invalid_token', 'The access token provided is invalid');
} elseif (!isset($token["expires"]) || !isset($token["client_id"])) {
$response->setError(401, 'malformed_token', 'Malformed token (missing "expires")');
} elseif (time() > $token["expires"]) {
$response->setError(401, 'expired_token', 'The access token provided has expired');
} else {
return $token;
}
}
$authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']);
if ($error = $response->getParameter('error')) {
$authHeader = sprintf('%s, error="%s"', $authHeader, $error);
if ($error_description = $response->getParameter('error_description')) {
$authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description);
}
}
$response->addHttpHeaders(array('WWW-Authenticate' => $authHeader));
return null;
}
// convenience method to allow retrieval of the token
public function getToken()
{
return $this->token;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace OAuth2\Controller;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
/**
* This controller is called when a "resource" is requested.
* call verifyResourceRequest in order to determine if the request
* contains a valid token.
*
* ex:
* > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
* > $response->send(); // authorization failed
* > die();
* > }
* > return json_encode($resource); // valid token! Send the stuff!
*
*/
interface ResourceControllerInterface
{
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null);
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response);
}

View File

@@ -0,0 +1,278 @@
<?php
namespace OAuth2\Controller;
use OAuth2\ResponseType\AccessTokenInterface;
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
use OAuth2\GrantType\GrantTypeInterface;
use OAuth2\ScopeInterface;
use OAuth2\Scope;
use OAuth2\Storage\ClientInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
/**
* @see OAuth2\Controller\TokenControllerInterface
*/
class TokenController implements TokenControllerInterface
{
protected $accessToken;
protected $grantTypes;
protected $clientAssertionType;
protected $scopeUtil;
protected $clientStorage;
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
{
if (is_null($clientAssertionType)) {
foreach ($grantTypes as $grantType) {
if (!$grantType instanceof ClientAssertionTypeInterface) {
throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
}
}
}
$this->clientAssertionType = $clientAssertionType;
$this->accessToken = $accessToken;
$this->clientStorage = $clientStorage;
foreach ($grantTypes as $grantType) {
$this->addGrantType($grantType);
}
if (is_null($scopeUtil)) {
$scopeUtil = new Scope();
}
$this->scopeUtil = $scopeUtil;
}
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response)
{
if ($token = $this->grantAccessToken($request, $response)) {
// @see http://tools.ietf.org/html/rfc6749#section-5.1
// server MUST disable caching in headers when tokens are involved
$response->setStatusCode(200);
$response->addParameters($token);
$response->addHttpHeaders(array(
'Cache-Control' => 'no-store',
'Pragma' => 'no-cache',
'Content-Type' => 'application/json'
));
}
}
/**
* Grant or deny a requested access token.
* This would be called from the "/token" endpoint as defined in the spec.
* You can call your endpoint whatever you want.
*
* @param $request - RequestInterface
* Request object to grant access token
*
* @throws InvalidArgumentException
* @throws LogicException
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @see http://tools.ietf.org/html/rfc6749#section-10.6
* @see http://tools.ietf.org/html/rfc6749#section-4.1.3
*
* @ingroup oauth2_section_4
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
{
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
$response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2');
$response->addHttpHeaders(array('Allow' => 'POST'));
return null;
}
/**
* Determine grant type from request
* and validate the request for that grant type
*/
if (!$grantTypeIdentifier = $request->request('grant_type')) {
$response->setError(400, 'invalid_request', 'The grant type was not specified in the request');
return null;
}
if (!isset($this->grantTypes[$grantTypeIdentifier])) {
/* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */
$response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier));
return null;
}
$grantType = $this->grantTypes[$grantTypeIdentifier];
/**
* Retrieve the client information from the request
* ClientAssertionTypes allow for grant types which also assert the client data
* in which case ClientAssertion is handled in the validateRequest method
*
* @see OAuth2\GrantType\JWTBearer
* @see OAuth2\GrantType\ClientCredentials
*/
if (!$grantType instanceof ClientAssertionTypeInterface) {
if (!$this->clientAssertionType->validateRequest($request, $response)) {
return null;
}
$clientId = $this->clientAssertionType->getClientId();
}
/**
* Retrieve the grant type information from the request
* The GrantTypeInterface object handles all validation
* If the object is an instance of ClientAssertionTypeInterface,
* That logic is handled here as well
*/
if (!$grantType->validateRequest($request, $response)) {
return null;
}
if ($grantType instanceof ClientAssertionTypeInterface) {
$clientId = $grantType->getClientId();
} else {
// validate the Client ID (if applicable)
if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) {
$response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier));
return null;
}
}
/**
* Validate the client can use the requested grant type
*/
if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) {
$response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id');
return false;
}
/**
* Validate the scope of the token
*
* requestedScope - the scope specified in the token request
* availableScope - the scope associated with the grant type
* ex: in the case of the "Authorization Code" grant type,
* the scope is specified in the authorize request
*
* @see http://tools.ietf.org/html/rfc6749#section-3.3
*/
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
$availableScope = $grantType->getScope();
if ($requestedScope) {
// validate the requested scope
if ($availableScope) {
if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) {
$response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request');
return null;
}
} else {
// validate the client has access to this scope
if ($clientScope = $this->clientStorage->getClientScope($clientId)) {
if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) {
$response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client');
return false;
}
} elseif (!$this->scopeUtil->scopeExists($requestedScope)) {
$response->setError(400, 'invalid_scope', 'An unsupported scope was requested');
return null;
}
}
} elseif ($availableScope) {
// use the scope associated with this grant type
$requestedScope = $availableScope;
} else {
// use a globally-defined default scope
$defaultScope = $this->scopeUtil->getDefaultScope($clientId);
// "false" means default scopes are not allowed
if (false === $defaultScope) {
$response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter');
return null;
}
$requestedScope = $defaultScope;
}
return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope);
}
/**
* addGrantType
*
* @param grantType - OAuth2\GrantTypeInterface
* the grant type to add for the specified identifier
* @param identifier - string
* a string passed in as "grant_type" in the response that will call this grantType
*/
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
{
if (is_null($identifier) || is_numeric($identifier)) {
$identifier = $grantType->getQuerystringIdentifier();
}
$this->grantTypes[$identifier] = $grantType;
}
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response)
{
if ($this->revokeToken($request, $response)) {
$response->setStatusCode(200);
$response->addParameters(array('revoked' => true));
}
}
/**
* Revoke a refresh or access token. Returns true on success and when tokens are invalid
*
* Note: invalid tokens do not cause an error response since the client
* cannot handle such an error in a reasonable way. Moreover, the
* purpose of the revocation request, invalidating the particular token,
* is already achieved.
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|null
*/
public function revokeToken(RequestInterface $request, ResponseInterface $response)
{
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
$response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2');
$response->addHttpHeaders(array('Allow' => 'POST'));
return null;
}
$token_type_hint = $request->request('token_type_hint');
if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) {
$response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\'');
return null;
}
$token = $request->request('token');
if ($token === null) {
$response->setError(400, 'invalid_request', 'Missing token parameter to revoke');
return null;
}
// @todo remove this check for v2.0
if (!method_exists($this->accessToken, 'revokeToken')) {
$class = get_class($this->accessToken);
throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method");
}
$this->accessToken->revokeToken($token, $token_type_hint);
return true;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace OAuth2\Controller;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
/**
* This controller is called when a token is being requested.
* it is called to handle all grant types the application supports.
* It also validates the client's credentials
*
* ex:
* > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
* > $response->send();
*
*/
interface TokenControllerInterface
{
/**
* handleTokenRequest
*
* @param $request
* OAuth2\RequestInterface - The current http request
* @param $response
* OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data
*
*/
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response);
public function grantAccessToken(RequestInterface $request, ResponseInterface $response);
}