153 lines
7.0 KiB
PHP
153 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace oauth2\grant_types;
|
|
|
|
use oauth2\exceptions\InvalidApplicationType;
|
|
use oauth2\exceptions\InvalidOAuth2Request;
|
|
use oauth2\exceptions\InvalidAccessTokenException;
|
|
use oauth2\exceptions\BearerTokenDisclosureAttemptException;
|
|
use oauth2\exceptions\LockedClientException;
|
|
use oauth2\exceptions\InvalidGrantTypeException;
|
|
|
|
use oauth2\requests\OAuth2Request;
|
|
use oauth2\responses\OAuth2AccessTokenValidationResponse;
|
|
use oauth2\services\IClientService;
|
|
use oauth2\services\ITokenService;
|
|
use services\IPHelper;
|
|
use utils\services\ILogService;
|
|
use oauth2\models\IClient;
|
|
|
|
use ReflectionClass;
|
|
|
|
|
|
/**
|
|
* Class ValidateBearerTokenGrantType
|
|
* In OAuth2, the contents of tokens are opaque to clients. This means
|
|
* that the client does not need to know anything about the content or
|
|
* structure of the token itself, if there is any. However, there is
|
|
* still a large amount of metadata that may be attached to a token,
|
|
* such as its current validity, approved scopes, and extra information
|
|
* about the authentication context in which the token was issued.
|
|
* These pieces of information are often vital to Protected Resources
|
|
* making authorization decisions based on the tokens being presented.
|
|
* Since OAuth2 defines no direct relationship between the Authorization
|
|
* Server and the Protected Resource, only that they must have an
|
|
* agreement on the tokens themselves, there have been many different
|
|
* approaches to bridging this gap.
|
|
* This specification defines an Introspection Endpoint that allows the
|
|
* holder of a token to query the Authorization Server to discover the
|
|
* set of metadata for a token. A Protected Resource may use the
|
|
* mechanism described in this draft to query the Introspection Endpoint
|
|
* in a particular authorization decision context and ascertain the
|
|
* relevant metadata about the token in order to make this authorization
|
|
* decision appropriately.
|
|
* The endpoint SHOULD also require some form of authentication to
|
|
* access this endpoint, such as the Client Authentication as described
|
|
* in OAuth 2 Core Specification [RFC6749] or a separate OAuth 2.0
|
|
* Access Token. The methods of managing and validating these
|
|
* authentication credentials are out of scope of this specification.
|
|
* http://tools.ietf.org/html/draft-richer-oauth-introspection-04
|
|
* @package oauth2\grant_types
|
|
*/
|
|
class ValidateBearerTokenGrantType extends AbstractGrantType
|
|
{
|
|
|
|
const OAuth2Protocol_GrantType_Extension_ValidateBearerToken = 'urn:tools.ietf.org:oauth2:grant_type:validate_bearer';
|
|
|
|
public function __construct(IClientService $client_service, ITokenService $token_service, ILogService $log_service)
|
|
{
|
|
parent::__construct($client_service, $token_service,$log_service);
|
|
}
|
|
|
|
public function canHandle(OAuth2Request $request)
|
|
{
|
|
$reflector = new ReflectionClass($request);
|
|
$class_name = $reflector->getName();
|
|
return $class_name == 'oauth2\requests\OAuth2AccessTokenValidationRequest' && $request->isValid();
|
|
}
|
|
|
|
public function getType()
|
|
{
|
|
return self::OAuth2Protocol_GrantType_Extension_ValidateBearerToken;
|
|
}
|
|
|
|
/**
|
|
* @param OAuth2Request $request
|
|
* @return mixed|void
|
|
* @throws \oauth2\exceptions\InvalidOAuth2Request
|
|
*/
|
|
public function handle(OAuth2Request $request)
|
|
{
|
|
throw new InvalidOAuth2Request('Not Implemented!');
|
|
}
|
|
|
|
/**
|
|
* @param OAuth2Request $request
|
|
* @return mixed|OAuth2AccessTokenValidationResponse|void
|
|
* @throws \oauth2\exceptions\InvalidOAuth2Request
|
|
* @throws \oauth2\exceptions\LockedClientException
|
|
* @throws \oauth2\exceptions\InvalidApplicationType
|
|
* @throws \oauth2\exceptions\BearerTokenDisclosureAttemptException
|
|
*/
|
|
public function completeFlow(OAuth2Request $request)
|
|
{
|
|
$reflector = new ReflectionClass($request);
|
|
$class_name = $reflector->getName();
|
|
if ($class_name == 'oauth2\requests\OAuth2AccessTokenValidationRequest') {
|
|
|
|
parent::completeFlow($request);
|
|
|
|
$token_value = $request->getToken();
|
|
|
|
try{
|
|
|
|
$access_token = $this->token_service->getAccessToken($token_value);
|
|
|
|
if(!$this->current_client->isResourceServerClient()){
|
|
// if current client is not a resource server, then we could only access to our own tokens
|
|
if($access_token->getClientId()!== $this->current_client_id)
|
|
throw new BearerTokenDisclosureAttemptException($this->current_client_id,sprintf('access token %s does not belongs to client id %s',$token_value, $this->current_client_id));
|
|
}
|
|
else{
|
|
// current client is a resource server, validate client type (must be confidential)
|
|
if($this->current_client->getClientType()!== IClient::ClientType_Confidential)
|
|
throw new InvalidApplicationType($this->current_client_id,'resource server client is not of confidential type!');
|
|
//validate resource server IP address
|
|
$current_ip = IPHelper::getUserIp();
|
|
$resource_server = $this->current_client->getResourceServer();
|
|
//check if resource server is active
|
|
if(!$resource_server->active)
|
|
throw new LockedClientException($this->current_client_id,'resource server is disabled!');
|
|
//check resource server ip address
|
|
if($current_ip !== $resource_server->ip)
|
|
throw new BearerTokenDisclosureAttemptException($this->current_client_id,sprintf('resource server ip (%s) differs from current request ip %s',$resource_server->ip,$current_ip));
|
|
// check if current ip belongs to a registered resource server audience
|
|
if(!$this->token_service->checkAccessTokenAudience($access_token,$current_ip))
|
|
throw new BearerTokenDisclosureAttemptException($this->current_client_id,sprintf('access token current audience does not match with current request ip %s', $current_ip));
|
|
}
|
|
|
|
return new OAuth2AccessTokenValidationResponse($token_value, $access_token->getScope(), $access_token->getAudience(),$access_token->getClientId(),$access_token->getRemainingLifetime(),$access_token->getUserId());
|
|
}
|
|
catch(InvalidAccessTokenException $ex1){
|
|
$this->log_service->error($ex1);
|
|
throw new BearerTokenDisclosureAttemptException($this->current_client_id,$ex1->getMessage());
|
|
}
|
|
catch(InvalidGrantTypeException $ex2){
|
|
$this->log_service->error($ex2);
|
|
throw new BearerTokenDisclosureAttemptException($this->current_client_id,$ex2->getMessage());
|
|
}
|
|
}
|
|
throw new InvalidOAuth2Request;
|
|
}
|
|
|
|
public function getResponseType()
|
|
{
|
|
throw new InvalidOAuth2Request('Not Implemented!');
|
|
}
|
|
|
|
public function buildTokenRequest(OAuth2Request $request)
|
|
{
|
|
throw new InvalidOAuth2Request('Not Implemented!');
|
|
}
|
|
|
|
} |