Files
openstackid/app/services/oauth2/ClientService.php
Sebastian Marcet ab777ecb8d Integration Testing
refactored db transactions to allow IOC
that would make easier unit testing

Change-Id: Ifbaa14e8b8025c3a68b4eddd794c92f389087a94
Implements: blueprint openid-oauth2-integration-testing
2014-02-19 20:14:22 -03:00

421 lines
14 KiB
PHP

<?php
namespace services\oauth2;
use Client;
use ClientAuthorizedUri;
use ClientAllowedOrigin;
use DB;
use Input;
use oauth2\exceptions\AllowedClientUriAlreadyExistsException;
use oauth2\exceptions\InvalidClientType;
use oauth2\exceptions\MissingClientAuthorizationInfo;
use oauth2\exceptions\AbsentClientException;
use oauth2\models\IClient;
use oauth2\OAuth2Protocol;
use oauth2\services\IApiScopeService;
use oauth2\services\IApiScope;
use oauth2\services\IClientService;
use oauth2\services\id;
use Request;
use utils\services\IAuthService;
use Zend\Math\Rand;
use Event;
use utils\db\ITransactionService;
/**
* Class ClientService
* @package services\oauth2
*/
class ClientService implements IClientService
{
private $auth_service;
private $scope_service;
/**
* @param IAuthService $auth_service
* @param IApiScopeService $scope_service
* @param ITransactionService $tx_service
*/
public function __construct(IAuthService $auth_service, IApiScopeService $scope_service,ITransactionService $tx_service)
{
$this->auth_service = $auth_service;
$this->scope_service = $scope_service;
$this->tx_service = $tx_service;
}
/**
* Clients in possession of a client password MAY use the HTTP Basic
* authentication scheme as defined in [RFC2617] to authenticate with
* the authorization server
* Alternatively, the authorization server MAY support including the
* client credentials in the request-body using the following
* parameters:
* implementation of http://tools.ietf.org/html/rfc6749#section-2.3.1
* @throws MissingClientAuthorizationInfo;
* @return list
*/
public function getCurrentClientAuthInfo()
{
//check first http basic auth header
$auth_header = Request::header('Authorization');
if (!is_null($auth_header) && !empty($auth_header)) {
$auth_header = trim($auth_header);
$auth_header = explode(' ', $auth_header);
if (!is_array($auth_header) || count($auth_header) < 2)
throw new MissingClientAuthorizationInfo;
$auth_header_content = $auth_header[1];
$auth_header_content = base64_decode($auth_header_content);
$auth_header_content = explode(':', $auth_header_content);
if (!is_array($auth_header_content) || count($auth_header_content) !== 2)
throw new MissingClientAuthorizationInfo;
//client_id:client_secret
return array($auth_header_content[0], $auth_header_content[1]);
}
//if not get from http input
$client_id = Input::get(OAuth2Protocol::OAuth2Protocol_ClientId, '');
$client_secret = Input::get(OAuth2Protocol::OAuth2Protocol_ClientSecret, '');
return array($client_id, $client_secret);
}
public function addClient($application_type, $user_id, $app_name, $app_description,$app_url=null, $app_logo = '')
{
$instance = null;
$this_var = $this;
$scope_service = $this_var->scope_service;
$this->tx_service->transaction(function () use ($application_type, $user_id, $app_name,$app_url, $app_description, $app_logo, &$instance, &$this_var,&$scope_service) {
//check $application_type vs client_type
$client_type = $application_type == IClient::ApplicationType_JS_Client? IClient::ClientType_Public : IClient::ClientType_Confidential;
$instance = new Client;
$instance->app_name = $app_name;
$instance->app_logo = $app_logo;
$instance->client_id = Rand::getString(32, OAuth2Protocol::VsChar, true) . '.openstack.client';
//only generates secret for confidential clients
if ($client_type == IClient::ClientType_Confidential)
$instance->client_secret = Rand::getString(24, OAuth2Protocol::VsChar, true);
$instance->client_type = $client_type;
$instance->application_type = $application_type;
$instance->user_id = $user_id;
$instance->active = true;
$instance->use_refresh_token = false;
$instance->rotate_refresh_token = false;
$instance->website = $app_url;
$instance->Save();
//default allowed url
$this_var->addClientAllowedUri($instance->getId(), 'https://localhost');
//add default scopes
$default_scopes = $scope_service->getDefaultScopes();
foreach($default_scopes as $default_scope){
$instance->scopes()->attach($default_scope->id);
}
});
return $instance;
}
public function addClientAllowedUri($id, $uri)
{
$res = false;
$this->tx_service->transaction(function () use ($id,$uri,&$res){
$client = Client::find($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
$client_uri = ClientAuthorizedUri::where('uri', '=', $uri)->where('client_id', '=', $id)->first();
if (!is_null($client_uri)) {
throw new AllowedClientUriAlreadyExistsException(sprintf('uri : %s', $uri));
}
$client_authorized_uri = new ClientAuthorizedUri;
$client_authorized_uri->client_id = $id;
$client_authorized_uri->uri = $uri;
$res = $client_authorized_uri->Save();
});
return $res;
}
public function addClientScope($id, $scope_id)
{
$client = Client::find($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
return $client->scopes()->attach($scope_id);
}
public function deleteClientScope($id, $scope_id)
{
$client = Client::find($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
return $client->scopes()->detach($scope_id);
}
/**
* Deletes a former client allowed redirection Uri
* @param $id client identifier
* @param $uri_id uri identifier
*/
public function deleteClientAllowedUri($id, $uri_id)
{
return ClientAuthorizedUri::where('id', '=', $uri_id)->where('client_id', '=', $id)->delete();
}
public function deleteClientByIdentifier($id)
{
$res = false;
$this->tx_service->transaction(function () use ($id,&$res){
$client = Client::find($id);
if (!is_null($client)) {
$client->authorized_uris()->delete();
$client->scopes()->detach();
Event::fire('oauth2.client.delete', array($client->client_id));
$res = $client->delete();
}
});
return $res;
}
/**
* Regenerates Client Secret
* @param $id client id
* @return mixed
*/
public function regenerateClientSecret($id)
{
$new_secret = '';
$this->tx_service->transaction(function () use ($id, &$new_secret) {
$client = Client::find($id);
if(is_null($client))
throw new AbsentClientException(sprintf("client id %d does not exists!.",$id));
if($client->client_type != IClient::ClientType_Confidential)
throw new InvalidClientType($id,sprintf("client id %d is not confidential!.",$id));
$client_secret = Rand::getString(24, OAuth2Protocol::VsChar, true);
$client->client_secret = $client_secret;
$client->Save();
Event::fire('oauth2.client.regenerate.secret', array($client->client_id));
$new_secret = $client->client_secret;
});
return $new_secret;
}
/**
* @param client $client_id
* @return mixed
* @throws \oauth2\exceptions\AbsentClientException
*/
public function lockClient($client_id)
{
$res = false;
$this_var = $this;
$this->tx_service->transaction(function () use ($client_id, &$res, &$this_var) {
$client = $this_var->getClientByIdentifier($client_id);
if (is_null($client))
throw new AbsentClientException($client_id,sprintf("client id %s does not exists!",$client_id));
$client->locked = true;
$res = $client->Save();
});
return $res;
}
/**
* @param client $client_id
* @return mixed
* @throws \oauth2\exceptions\AbsentClientException
*/
public function unlockClient($client_id)
{
$res = false;
$this_var = $this;
$this->tx_service->transaction(function () use ($client_id, &$res, &$this_var) {
$client = $this_var->getClientByIdentifier($client_id);
if (is_null($client))
throw new AbsentClientException($client_id,sprintf("client id %s does not exists!",$client_id));
$client->locked = false;
$res = $client->Save();
});
return $res;
}
/**
* @param $client_id
* @return IClient
*/
public function getClientById($client_id)
{
$client = Client::where('client_id', '=', $client_id)->first();
return $client;
}
public function activateClient($id, $active)
{
$client = $this->getClientByIdentifier($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
$client->active = $active;
return $client->Save();
}
public function getClientByIdentifier($id)
{
$client = Client::where('id', '=', $id)->first();
return $client;
}
public function setRefreshTokenUsage($id, $use_refresh_token)
{
$client = $this->getClientByIdentifier($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
$client->use_refresh_token = $use_refresh_token;
return $client->Save();
}
public function setRotateRefreshTokenPolicy($id, $rotate_refresh_token)
{
$client = $this->getClientByIdentifier($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
$client->rotate_refresh_token = $rotate_refresh_token;
return $client->Save();
}
public function existClientAppName($app_name)
{
return Client::where('app_name', '=', $app_name)->count() > 0;
}
/**
* gets an api scope by id
* @param $id id of api scope
* @return IApiScope
*/
public function get($id)
{
return Client::find($id);
}
/**
* @param int $page_nbr
* @param int $page_size
* @param array $filters
* @param array $fields
* @return mixed
*/
public function getAll($page_nbr=1,$page_size=10,array $filters=array(), array $fields=array('*'))
{
DB::getPaginator()->setCurrentPage($page_nbr);
return Client::Filter($filters)->paginate($page_size,$fields);
}
/**
* @param IClient $client
* @return bool
*/
public function save(IClient $client)
{
if(!$client->exists() || count($client->getDirty())>0){
return $client->Save();
}
return true;
}
/**
* @param $id
* @param array $params
* @return bool
* @throws \oauth2\exceptions\AbsentClientException
*/
public function update($id, array $params)
{
$res = false;
$this_var = $this;
$this->tx_service->transaction(function () use ($id,$params, &$res, &$this_var) {
$client = Client::find($id);
if(is_null($client))
throw new AbsentClientException(sprintf('client id %s does not exists!',$id));
$allowed_update_params = array(
'app_name','website','app_description','app_logo','active','locked','use_refresh_token','rotate_refresh_token');
foreach($allowed_update_params as $param){
if(array_key_exists($param,$params)){
$client->{$param} = $params[$param];
}
}
$res = $this_var->save($client);
});
return $res;
}
/**
* @param $id
* @param $origin
* @return mixed
* @throws \oauth2\exceptions\AllowedClientUriAlreadyExistsException
* @throws \oauth2\exceptions\AbsentClientException
*/
public function addClientAllowedOrigin($id, $origin)
{
$res = false;
$this->tx_service->transaction(function () use ($id, $origin, &$res) {
$client = Client::find($id);
if (is_null($client))
throw new AbsentClientException(sprintf("client id %s does not exists!",$id));
if($client->getApplicationType()!=IClient::ApplicationType_JS_Client)
throw new InvalidClientType($id,sprintf("client id %s application type must be JS_CLIENT",$id));
$client_origin = ClientAllowedOrigin::where('allowed_origin', '=', $origin)->where('client_id', '=', $id)->first();
if (!is_null($client_origin)) {
throw new AllowedClientUriAlreadyExistsException(sprintf('origin : %s', $origin));
}
$client_origin = new ClientAllowedOrigin;
$client_origin->client_id = $id;
$client_origin->allowed_origin = $origin;
$res = $client_origin->Save();
});
return $res;
}
/**
* @param $id
* @param $origin_id
* @return mixed
*/
public function deleteClientAllowedOrigin($id, $origin_id)
{
return ClientAllowedOrigin::where('id', '=', $origin_id)->where('client_id', '=', $id)->delete();
}
}