openstackid/app/libs/oauth2/OAuth2Protocol.php
smarcet ad1844984e Implements: blueprint openid-oauth2-implicit-client-flow
Change-Id: Iee3c9412a3f75a4aba5421e8c5f881a60b396df0
2014-01-06 18:07:55 -03:00

314 lines
14 KiB
PHP

<?php
namespace oauth2;
use Exception;
use oauth2\endpoints\AuthorizationEndpoint;
use oauth2\endpoints\TokenEndpoint;
use oauth2\exceptions\AccessDeniedException;
use oauth2\exceptions\BearerTokenDisclosureAttemptException;
use oauth2\exceptions\ExpiredAuthorizationCodeException;
use oauth2\exceptions\InvalidAccessTokenException;
use oauth2\exceptions\InvalidAuthorizationCodeException;
use oauth2\exceptions\InvalidClientException;
use oauth2\exceptions\InvalidGrantTypeException;
use oauth2\exceptions\InvalidOAuth2Request;
use oauth2\exceptions\OAuth2GenericException;
use oauth2\exceptions\ReplayAttackException;
use oauth2\exceptions\ScopeNotAllowedException;
use oauth2\exceptions\UnAuthorizedClientException;
use oauth2\exceptions\UnsupportedResponseTypeException;
use oauth2\exceptions\UriNotAllowedException;
use oauth2\grant_types\AuthorizationCodeGrantType;
use oauth2\grant_types\ImplicitGrantType;
use oauth2\grant_types\ValidateBearerTokenGrantType;
use oauth2\grant_types\RefreshBearerTokenGrantType;
use oauth2\requests\OAuth2Request;
use oauth2\responses\OAuth2DirectErrorResponse;
use oauth2\responses\OAuth2IndirectErrorResponse;
use oauth2\services\IClientService;
use oauth2\services\IMementoOAuth2AuthenticationRequestService;
use oauth2\services\ITokenService;
use oauth2\services\IApiScopeService;
use oauth2\strategies\IOAuth2AuthenticationStrategy;
use oauth2\strategies\OAuth2IndirectErrorResponseFactoryMethod;
use utils\services\IAuthService;
use utils\services\ICheckPointService;
//grant types
use utils\services\ILogService;
/**
* Class OAuth2Protocol
* Implementation of http://tools.ietf.org/html/rfc6749
* @package oauth2
*/
class OAuth2Protocol implements IOAuth2Protocol
{
const OAuth2Protocol_GrantType_AuthCode = 'authorization_code';
const OAuth2Protocol_GrantType_Implicit = 'implicit';
const OAuth2Protocol_GrantType_ResourceOwner_Password = 'password';
const OAuth2Protocol_GrantType_ClientCredentials = 'client_credentials';
const OAuth2Protocol_GrantType_RefreshToken = 'refresh_token';
const OAuth2Protocol_ResponseType_Code = 'code';
const OAuth2Protocol_ResponseType_Token = 'token';
const OAuth2Protocol_ResponseType = 'response_type';
const OAuth2Protocol_ClientId = 'client_id';
const OAuth2Protocol_ClientSecret = "client_secret";
const OAuth2Protocol_AccessToken = "access_token";
const OAuth2Protocol_Token = "token";
const OAuth2Protocol_TokenType = "token_type";
const OAuth2Protocol_AccessToken_ExpiresIn = "expires_in";
const OAuth2Protocol_RefreshToken = "refresh_token";
const OAuth2Protocol_RedirectUri = "redirect_uri";
const OAuth2Protocol_Scope = "scope";
const OAuth2Protocol_Audience = "audience";
const OAuth2Protocol_State = "state";
const OAuth2Protocol_GrantType = 'grant_type';
const OAuth2Protocol_Error = "error";
const OAuth2Protocol_ErrorDescription = "error_description";
const OAuth2Protocol_ErrorUri = "error_uri";
const OAuth2Protocol_Error_InvalidRequest = "invalid_request";
const OAuth2Protocol_Error_UnauthorizedClient = "unauthorized_client";
const OAuth2Protocol_Error_AccessDenied = "access_denied";
const OAuth2Protocol_Error_UnsupportedResponseType = "unsupported_response_type";
const OAuth2Protocol_Error_InvalidScope = "invalid_scope";
const OAuth2Protocol_Error_UnsupportedGrantType = "unsupported_grant_type";
const OAuth2Protocol_Error_InvalidGrant = "invalid_grant";
//error codes definitions http://tools.ietf.org/html/rfc6749#section-4.1.2.1
const OAuth2Protocol_Error_ServerError = "server_error";
const OAuth2Protocol_Error_TemporallyUnavailable = "temporally_unavailable";
public static $valid_responses_types = array(
self::OAuth2Protocol_ResponseType_Code => self::OAuth2Protocol_ResponseType_Code,
self::OAuth2Protocol_ResponseType_Token => self::OAuth2Protocol_ResponseType_Token
);
public static $protocol_definition = array(
self::OAuth2Protocol_ResponseType => self::OAuth2Protocol_ResponseType,
self::OAuth2Protocol_ClientId => self::OAuth2Protocol_ClientId,
self::OAuth2Protocol_RedirectUri => self::OAuth2Protocol_RedirectUri,
self::OAuth2Protocol_Scope => self::OAuth2Protocol_Scope,
self::OAuth2Protocol_State => self::OAuth2Protocol_State
);
//services
private $log_service;
private $checkpoint_service;
private $client_service;
//endpoints
private $authorize_endpoint;
private $token_endpoint;
//grant types
private $grant_types = array();
public function __construct(
ILogService $log_service,
IClientService $client_service,
ITokenService $token_service,
IAuthService $auth_service,
IMementoOAuth2AuthenticationRequestService $memento_service,
IOAuth2AuthenticationStrategy $auth_strategy,
ICheckPointService $checkpoint_service,
IApiScopeService $scope_service)
{
//todo: add dynamic creation logic (configure grants types from db)
$authorization_code_grant_type = new AuthorizationCodeGrantType($scope_service, $client_service, $token_service, $auth_service, $memento_service, $auth_strategy, $log_service);
$implicit_grant_type = new ImplicitGrantType($scope_service, $client_service, $token_service, $auth_service, $memento_service, $auth_strategy, $log_service);
$validate_bearer_token_grant_type = new ValidateBearerTokenGrantType($client_service, $token_service, $log_service);
$refresh_bearer_token_grant_type = new RefreshBearerTokenGrantType($client_service,$token_service,$log_service);
$this->grant_types[$authorization_code_grant_type->getType()] = $authorization_code_grant_type;
$this->grant_types[$implicit_grant_type->getType()] = $implicit_grant_type;
$this->grant_types[$validate_bearer_token_grant_type->getType()] = $validate_bearer_token_grant_type;
$this->grant_types[$refresh_bearer_token_grant_type->getType()] = $refresh_bearer_token_grant_type;
$this->log_service = $log_service;
$this->checkpoint_service = $checkpoint_service;
$this->client_service = $client_service;
$this->authorize_endpoint = new AuthorizationEndpoint($this);
$this->token_endpoint = new TokenEndpoint($this);
}
/**
* @param OAuth2Request $request
* @return mixed|OAuth2IndirectErrorResponse
* @throws \Exception
* @throws exceptions\UriNotAllowedException
*/
public function authorize(OAuth2Request $request = null)
{
try {
if (is_null($request) || !$request->isValid())
throw new InvalidOAuth2Request;
return $this->authorize_endpoint->handle($request);
} catch (InvalidOAuth2Request $ex1) {
$this->log_service->error($ex1);
$this->checkpoint_service->trackException($ex1);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex1;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request, OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest, $redirect_uri);
} catch (UnsupportedResponseTypeException $ex2) {
$this->log_service->error($ex2);
$this->checkpoint_service->trackException($ex2);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex2;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request, OAuth2Protocol::OAuth2Protocol_Error_UnsupportedResponseType, $redirect_uri);
} catch (InvalidClientException $ex3) {
$this->log_service->error($ex3);
$this->checkpoint_service->trackException($ex3);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex3;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request,OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient, $redirect_uri);
} catch (UriNotAllowedException $ex4) {
$this->log_service->error($ex4);
$this->checkpoint_service->trackException($ex4);
throw $ex4;
} catch (ScopeNotAllowedException $ex5) {
$this->log_service->error($ex5);
$this->checkpoint_service->trackException($ex5);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex5;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request,OAuth2Protocol::OAuth2Protocol_Error_InvalidScope, $redirect_uri);
} catch (UnAuthorizedClientException $ex6) {
$this->log_service->error($ex6);
$this->checkpoint_service->trackException($ex6);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex6;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request,OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient, $redirect_uri);
} catch (AccessDeniedException $ex7) {
$this->log_service->error($ex7);
$this->checkpoint_service->trackException($ex7);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex7;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request,OAuth2Protocol::OAuth2Protocol_Error_AccessDenied, $redirect_uri);
} catch (OAuth2GenericException $ex8) {
$this->log_service->error($ex8);
$this->checkpoint_service->trackException($ex8);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex8;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request,OAuth2Protocol::OAuth2Protocol_Error_ServerError, $redirect_uri);
} catch (Exception $ex) {
$this->log_service->error($ex);
$this->checkpoint_service->trackException($ex);
$redirect_uri = $this->validateRedirectUri($request);
if (is_null($redirect_uri))
throw $ex;
return OAuth2IndirectErrorResponseFactoryMethod::buildResponse($request,OAuth2Protocol::OAuth2Protocol_Error_ServerError, $redirect_uri);
}
}
private function validateRedirectUri(OAuth2Request $request = null)
{
if(is_null($request))
return null;
$redirect_uri = $request->getRedirectUri();
if (is_null($redirect_uri))
return null;
$client_id = $request->getClientId();
if (is_null($client_id))
return null;
$client = $this->client_service->getClientById($client_id);
if (is_null($client))
return null;
if (!$client->isUriAllowed($redirect_uri))
return null;
return $redirect_uri;
}
/**
* @param OAuth2Request $request
* @return OAuth2DirectErrorResponse|void
*/
public function token(OAuth2Request $request = null)
{
try {
if (is_null($request) || !$request->isValid())
throw new InvalidOAuth2Request;
return $this->token_endpoint->handle($request);
} catch (InvalidOAuth2Request $ex1) {
$this->log_service->error($ex1);
$this->checkpoint_service->trackException($ex1);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest);
} catch (InvalidAuthorizationCodeException $ex2) {
$this->log_service->error($ex2);
$this->checkpoint_service->trackException($ex2);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient);
} catch (InvalidClientException $ex3) {
$this->log_service->error($ex3);
$this->checkpoint_service->trackException($ex3);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient);
} catch (UriNotAllowedException $ex4) {
$this->log_service->error($ex4);
$this->checkpoint_service->trackException($ex4);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient);
} catch (UnAuthorizedClientException $ex5) {
$this->log_service->error($ex5);
$this->checkpoint_service->trackException($ex5);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient);
} catch (ExpiredAuthorizationCodeException $ex6) {
$this->log_service->error($ex6);
$this->checkpoint_service->trackException($ex6);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest);
} catch (ReplayAttackException $ex7) {
$this->log_service->error($ex7);
$this->checkpoint_service->trackException($ex7);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest);
} catch (InvalidAccessTokenException $ex8) {
$this->log_service->error($ex8);
$this->checkpoint_service->trackException($ex8);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_InvalidGrant);
} catch (InvalidGrantTypeException $ex9) {
$this->log_service->error($ex9);
$this->checkpoint_service->trackException($ex9);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_InvalidGrant);
} catch (BearerTokenDisclosureAttemptException $ex10) {
$this->log_service->error($ex10);
$this->checkpoint_service->trackException($ex10);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_InvalidGrant);
} catch (Exception $ex) {
$this->log_service->error($ex);
$this->checkpoint_service->trackException($ex);
return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_ServerError);
}
}
public function getAvailableGrants()
{
return $this->grant_types;
}
}