diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..c3caec60 --- /dev/null +++ b/.env.example @@ -0,0 +1,64 @@ +APP_ENV=local +APP_DEBUG=true +APP_KEY=SomeRandomString +APP_URL=http://localhost +APP_OAUTH_2_0_CLIENT_ID=clientid +APP_OAUTH_2_0_CLIENT_SECRET=clientsecret +APP_OAUTH_2_0_AUTH_SERVER_BASE_URL=http://localhost + +DB_HOST=localhost +DB_DATABASE=homestead +DB_USERNAME=homestead +DB_PASSWORD=secret + +SS_DB_DRIVER=mysql +SS_DB_HOST=localhost +SS_DB_DATABASE=homestead +SS_DB_USERNAME=homestead +SS_DB_PASSWORD=secret + +REDIS_HOST=127.0.0.1 +REDIS_PORT=port +REDIS_DB=0 +REDIS_PASSWORD= + +CACHE_DRIVER=file + +SESSION_DRIVER=redis +SESSION_COOKIE_DOMAIN= +SESSION_COOKIE_SECURE=false + +QUEUE_DRIVER=sync + +MAIL_DRIVER=smtp +MAIL_HOST=mailtrap.io +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null + +CORS_ALLOWED_HEADERS=origin, content-type, accept, authorization, x-requested-with +CORS_ALLOWED_METHODS=GET, POST, OPTIONS, PUT, DELETE +CORS_USE_PRE_FLIGHT_CACHING=true +CORS_MAX_AGE=3200 +CORS_EXPOSED_HEADERS= + +CURL_TIMEOUT=3600 +CURL_ALLOWS_REDIRECT=false +CURL_VERIFY_SSL_CERT=false + +ASSETS_BASE_URL=http://www.openstack.org +SSL_ENABLED=true +DB_LOG_ENABLED=true +ACCESS_TOKEN_CACHE_LIFETIME=300 +API_RESPONSE_CACHE_LIFETIME=600 + +LOG_EMAIL_TO=smarcet@gmail.com +LOG_EMAIL_FROM=smarcet@gmail.com +LOG_LEVEL=info + +EVENTBRITE_OAUTH2_PERSONAL_TOKEN= + +RECAPTCHA_PUBLIC_KEY= +RECAPTCHA_PRIVATE_KEY= + +BANNING_ENABLE= \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 21256661..f2920314 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ -* text=auto \ No newline at end of file +* text=auto +*.css linguist-vendored +*.less linguist-vendored \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8141b7fa..df3fa515 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,7 @@ /vendor composer.phar composer.lock -.DS_Storeapp/storage -/app/storage/* .idea/* -app/config/dev/* -app/config/testing/* -app/config/local/* -app/config/production/* -app/config/staging/* -app/config/packages/greggilbert/recaptcha/dev/* -app/config/packages/greggilbert/recaptcha/local/* -app/config/packages/greggilbert/recaptcha/production/* -app/config/packages/greggilbert/recaptcha/staging/* -/bootstrap/compiled.php -/bootstrap/environment.php .tox AUTHORS ChangeLog @@ -23,4 +10,11 @@ doc/build *.egg-info public/bower_assets public/bower_assets/* -*.log \ No newline at end of file +*.log +/node_modules +/public/storage +Homestead.yaml +Homestead.json +.env +.env.testing + diff --git a/app/Console/Commands/Inspire.php b/app/Console/Commands/Inspire.php new file mode 100644 index 00000000..db9ab854 --- /dev/null +++ b/app/Console/Commands/Inspire.php @@ -0,0 +1,33 @@ +comment(PHP_EOL.Inspiring::quote().PHP_EOL); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php new file mode 100644 index 00000000..71c519d3 --- /dev/null +++ b/app/Console/Kernel.php @@ -0,0 +1,30 @@ +command('inspire') + // ->hourly(); + } +} diff --git a/app/Events/Event.php b/app/Events/Event.php new file mode 100644 index 00000000..ba2f8883 --- /dev/null +++ b/app/Events/Event.php @@ -0,0 +1,8 @@ +client_service = $client_service; - $this->scope_service = $scope_service; - $this->token_service = $token_service; - $this->resource_server_service = $resource_server_service; - $this->api_service = $api_service; - $this->endpoint_service = $endpoint_service; - $this->auth_service = $auth_service; - $this->user_service = $user_service; - $this->configuration_service = $configuration_service; - $this->banned_ips_service = $banned_ips_service; - $this->private_keys_repository = $private_keys_repository; - $this->group_repository = $group_repository; + $this->client_service = $client_service; + $this->scope_service = $scope_service; + $this->access_token_repository = $access_token_repository; + $this->refresh_token_repository = $refresh_token_repository; + $this->resource_server_service = $resource_server_service; + $this->api_service = $api_service; + $this->endpoint_service = $endpoint_service; + $this->auth_service = $auth_service; + $this->user_service = $user_service; + $this->configuration_service = $configuration_service; + $this->banned_ips_service = $banned_ips_service; + $this->private_keys_repository = $private_keys_repository; + $this->group_repository = $group_repository; + $this->client_repository = $client_repository; + $this->user_repository = $user_repository; + $this->endpoint_repository = $endpoint_repository; + $this->scope_repository = $scope_repository; + $this->api_repository = $api_repository; + $this->resource_server_repository = $resource_server_repository; } public function editRegisteredClient($id) { - $user = $this->auth_service->getCurrentUser(); - $client = $this->client_service->getClientByIdentifier($id); + $user = $this->auth_service->getCurrentUser(); + $client = $this->client_repository->getClientByIdentifier($id); if (is_null($client)) { Log::warning(sprintf("invalid oauth2 client id %s", $id)); - return View::make("404"); + return View::make("errors.404"); } $selected_scopes = $client->getClientScopes(); @@ -115,31 +198,33 @@ class AdminController extends BaseController { $scopes = $this->scope_service->getAvailableScopes(); $group_scopes = $user->getGroupScopes(); - $access_tokens = $this->token_service->getAccessTokenByClient($client->client_id); + $access_tokens = $this->access_token_repository->getAllValidByClientIdentifier($client->getId(), 1 , self::TokenPageSize); - foreach ($access_tokens as $token) { + foreach ($access_tokens->items() as $token) { $friendly_scopes = $this->scope_service->getFriendlyScopesByName(explode(' ', $token->scope)); $token->setFriendlyScopes(implode(',', $friendly_scopes)); } - $refresh_tokens = $this->token_service->getRefreshTokenByClient($client->client_id); + $refresh_tokens = $this->refresh_token_repository->getAllValidByClientIdentifier($client->getId(), 1 , self::TokenPageSize); - foreach ($refresh_tokens as $token) { + foreach ($refresh_tokens->items() as $token) { $friendly_scopes = $this->scope_service->getFriendlyScopesByName(explode(' ', $token->scope)); $token->setFriendlyScopes(implode(',', $friendly_scopes)); } return View::make("oauth2.profile.edit-client", - array( + [ 'client' => $client, 'selected_scopes' => $aux_scopes, 'scopes' => array_merge($scopes, $group_scopes), - 'access_tokens' => $access_tokens, + 'access_tokens' => $access_tokens->items(), + 'access_tokens_pages' => $access_tokens->total() > 0 ? intval(ceil($access_tokens->total() / self::TokenPageSize)) : 0, "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), "is_openstackid_admin" => $user->isOpenstackIdAdmin(), "use_system_scopes" => $user->canUseSystemScopes(), - 'refresh_tokens' => $refresh_tokens, - )); + 'refresh_tokens' => $refresh_tokens->items(), + 'refresh_tokens_pages' => $refresh_tokens->total() > 0 ? intval(ceil($refresh_tokens->total() / self::TokenPageSize)) : 0, + ]); } // Api Scope Groups @@ -147,7 +232,7 @@ class AdminController extends BaseController { public function listApiScopeGroups() { $user = $this->auth_service->getCurrentUser(); - $groups = $this->group_repository->getAll(1,1000); + $groups = $this->group_repository->getAll(1, PHP_INT_MAX); $non_selected_scopes = $this->scope_service->getAssignedByGroups(); return View::make("oauth2.profile.admin.api-scope-groups",array ( @@ -162,7 +247,7 @@ class AdminController extends BaseController { $group = $this->group_repository->get($id); if(is_null($group)) - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); $user = $this->auth_service->getCurrentUser(); $non_selected_scopes = $this->scope_service->getAssignedByGroups(); return View::make("oauth2.profile.admin.edit-api-scope-group", @@ -179,7 +264,7 @@ class AdminController extends BaseController { // Resource servers public function listResourceServers() { $user = $this->auth_service->getCurrentUser(); - $resource_servers = $this->resource_server_service->getAll(1,1000); + $resource_servers = $this->resource_server_repository->getAll(1, PHP_INT_MAX); return View::make("oauth2.profile.admin.resource-servers",array( "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), "is_openstackid_admin" => $user->isOpenstackIdAdmin(), @@ -187,9 +272,9 @@ class AdminController extends BaseController { } public function editResourceServer($id){ - $resource_server = $this->resource_server_service->get($id); + $resource_server = $this->resource_server_repository->get($id); if(is_null($resource_server)) - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); $user = $this->auth_service->getCurrentUser(); return View::make("oauth2.profile.admin.edit-resource-server",array( "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), @@ -199,9 +284,9 @@ class AdminController extends BaseController { } public function editApi($id){ - $api = $this->api_service->get($id); + $api = $this->api_repository->get($id); if(is_null($api)) - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); $user = $this->auth_service->getCurrentUser(); return View::make("oauth2.profile.admin.edit-api",array( "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), @@ -210,9 +295,9 @@ class AdminController extends BaseController { } public function editScope($id){ - $scope = $this->scope_service->get($id); + $scope = $this->scope_repository->get($id); if(is_null($scope)) - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); $user = $this->auth_service->getCurrentUser(); return View::make("oauth2.profile.admin.edit-scope",array( "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), @@ -221,18 +306,17 @@ class AdminController extends BaseController { } public function editEndpoint($id){ - $endpoint = $this->endpoint_service->get($id); - if(is_null($endpoint)) - return Response::view('404', array(), 404); + $endpoint = $this->endpoint_repository->get($id); + if(is_null($endpoint)) return Response::view('errors.404', array(), 404); $user = $this->auth_service->getCurrentUser(); $selected_scopes = array(); $list = $endpoint->scopes()->get(array('id')); foreach($list as $selected_scope){ array_push($selected_scopes,$selected_scope->id); } - return View::make("oauth2.profile.admin.edit-endpoint",array( - "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), - "is_openstackid_admin" => $user->isOpenstackIdAdmin(), + return View::make('oauth2.profile.admin.edit-endpoint',array( + 'is_oauth2_admin' => $user->isOAuth2ServerAdmin(), + 'is_openstackid_admin' => $user->isOpenstackIdAdmin(), 'endpoint' => $endpoint , 'selected_scopes' => $selected_scopes)); } @@ -240,15 +324,15 @@ class AdminController extends BaseController { public function editIssuedGrants(){ $user = $this->auth_service->getCurrentUser(); - $access_tokens = $this->token_service->getAccessTokenByUserId($user->getId()); - $refresh_tokens = $this->token_service->getRefreshTokenByUserId($user->getId()); + $access_tokens = $this->access_token_repository->getAllValidByUserId($user->getId(), 1, self::TokenPageSize); + $refresh_tokens = $this->refresh_token_repository->getAllValidByUserId($user->getId(), 1, self::TokenPageSize); - foreach($access_tokens as $access_token){ + foreach($access_tokens->items() as $access_token){ $friendly_scopes = $this->scope_service->getFriendlyScopesByName(explode(' ',$access_token->scope)); $access_token->setFriendlyScopes(implode(', ',$friendly_scopes)); } - foreach($refresh_tokens as $refresh_token){ + foreach($refresh_tokens->items() as $refresh_token){ $friendly_scopes = $this->scope_service->getFriendlyScopesByName(explode(' ',$refresh_token->scope)); $refresh_token->setFriendlyScopes(implode(', ',$friendly_scopes)); } @@ -257,8 +341,10 @@ class AdminController extends BaseController { array ( 'user_id' => $user->getId(), - 'access_tokens' => $access_tokens , - 'refresh_tokens' => $refresh_tokens , + 'access_tokens' => $access_tokens->items() , + 'access_tokens_pages' => $access_tokens->total() > 0 ? intval(ceil($access_tokens->total() / self::TokenPageSize)) : 0, + 'refresh_tokens' => $refresh_tokens->items(), + 'refresh_tokens_pages' => $refresh_tokens->total() > 0 ? intval(ceil($refresh_tokens->total() / self::TokenPageSize)) : 0, 'is_oauth2_admin' => $user->isOAuth2ServerAdmin(), 'is_openstackid_admin' => $user->isOpenstackIdAdmin(), ) @@ -281,13 +367,13 @@ class AdminController extends BaseController { public function listLockedClients(){ $user = $this->auth_service->getCurrentUser(); - $clients = $this->client_service->getAll(1,1000,array( - array( + $clients = $this->client_repository->getAll(1, PHP_INT_MAX,[ + [ 'name'=>'locked', 'op' => '=', 'value'=> true - ) - )); + ] + ]); return View::make("oauth2.profile.admin.clients", array( "username" => $user->getFullName(), @@ -300,28 +386,28 @@ class AdminController extends BaseController { public function listLockedUsers(){ $user = $this->auth_service->getCurrentUser(); - $users = $this->user_service->getAll(1,1000,array( - array( - 'name'=>'lock', - 'op' => '=', - 'value'=> true - ) - )); + $users = $this->user_repository->getAll(1, PHP_INT_MAX,[ + [ + 'name' => 'lock', + 'op' => '=', + 'value' => true + ] + ]); - return View::make("admin.users", array( - "username" => $user->getFullName(), - "user_id" => $user->getId(), - "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), - "is_openstackid_admin" => $user->isOpenstackIdAdmin(), - 'users' => $users, - )); + return View::make('admin.users', [ + 'username' => $user->getFullName(), + 'user_id' => $user->getId(), + 'is_oauth2_admin' => $user->isOAuth2ServerAdmin(), + 'is_openstackid_admin' => $user->isOpenstackIdAdmin(), + 'users' => $users, + ]); } public function listServerConfig(){ - $user = $this->auth_service->getCurrentUser(); + $user = $this->auth_service->getCurrentUser(); $config_values = array(); - $dictionary = array + $dictionary = array ( 'MaxFailed.Login.Attempts', 'MaxFailed.LoginAttempts.2ShowCaptcha', @@ -422,14 +508,17 @@ class AdminController extends BaseController { public function listBannedIPs(){ $user = $this->auth_service->getCurrentUser(); - $ips = $this->banned_ips_service->getByPage(1,1000); - return View::make("admin.banned-ips", array( - "username" => $user->getFullName(), - "user_id" => $user->getId(), - "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), - "is_openstackid_admin" => $user->isOpenstackIdAdmin(), - "ips" =>$ips - )); + $ips = $this->banned_ips_service->getByPage(1, PHP_INT_MAX); + return View::make("admin.banned-ips", + array + ( + "username" => $user->getFullName(), + "user_id" => $user->getId(), + "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), + "is_openstackid_admin" => $user->isOpenstackIdAdmin(), + "ips" => $ips + ) + ); } public function listServerPrivateKeys(){ @@ -437,7 +526,7 @@ class AdminController extends BaseController { $user = $this->auth_service->getCurrentUser(); return View::make("oauth2.profile.admin.server-private-keys", array( - 'private_keys' => $this->private_keys_repository->getAll(1,4294967296), + 'private_keys' => $this->private_keys_repository->getAll(1, PHP_INT_MAX), "is_oauth2_admin" => $user->isOAuth2ServerAdmin(), "is_openstackid_admin" => $user->isOpenstackIdAdmin(), )); diff --git a/app/controllers/apis/AbstractRESTController.php b/app/Http/Controllers/Api/AbstractRESTController.php similarity index 57% rename from app/controllers/apis/AbstractRESTController.php rename to app/Http/Controllers/Api/AbstractRESTController.php index 3375481b..889af6e8 100644 --- a/app/controllers/apis/AbstractRESTController.php +++ b/app/Http/Controllers/Api/AbstractRESTController.php @@ -1,9 +1,21 @@ -$value){ if(in_array($fieldname,$this->allowed_filter_fields)){ - array_push($res,array('name'=>$fieldname,'op'=>'=','value'=>$value)); + array_push($res,['name' => $fieldname, 'op' => '=','value' => $value]); } } return $res; diff --git a/app/controllers/apis/ApiBannedIPController.php b/app/Http/Controllers/Api/ApiBannedIPController.php similarity index 67% rename from app/controllers/apis/ApiBannedIPController.php rename to app/Http/Controllers/Api/ApiBannedIPController.php index 0aebce40..52dbd40f 100644 --- a/app/controllers/apis/ApiBannedIPController.php +++ b/app/Http/Controllers/Api/ApiBannedIPController.php @@ -1,10 +1,25 @@ -banned_ip_service = $banned_ip_service; - $this->allowed_filter_fields = array(); + $this->banned_ip_service = $banned_ip_service; + $this->allowed_filter_fields = array(); $this->allowed_projection_fields = array('*'); } @@ -56,9 +71,9 @@ class ApiBannedIPController extends AbstractRESTController implements ICRUDContr { try { //check for optional filters param on querystring - $fields = $this->getProjection(Input::get('fields', null)); - $filters = $this->getFilters(Input::except('fields', 'limit', 'offset')); - $page_nbr = intval(Input::get('offset', 1)); + $fields = $this->getProjection(Input::get('fields', null)); + $filters = $this->getFilters(Input::except('fields', 'limit', 'offset')); + $page_nbr = intval(Input::get('offset', 1)); $page_size = intval(Input::get('limit', 10)); $list = $this->banned_ip_service->getByPage($page_nbr, $page_size, $filters, $fields); @@ -67,7 +82,7 @@ class ApiBannedIPController extends AbstractRESTController implements ICRUDContr array_push($items, $ip->toArray()); } return $this->ok(array( - 'page' => $items, + 'page' => $items, 'total_items' => $list->getTotal() )); } catch (Exception $ex) { @@ -83,7 +98,7 @@ class ApiBannedIPController extends AbstractRESTController implements ICRUDContr $ip = Input::get("ip", null); } else { $banned_ip = $this->banned_ip_service->get($id); - $ip = $banned_ip->ip; + $ip = $banned_ip->ip; } if (is_null($ip)) return $this->error400('invalid request'); diff --git a/app/controllers/apis/ApiController.php b/app/Http/Controllers/Api/ApiController.php similarity index 66% rename from app/controllers/apis/ApiController.php rename to app/Http/Controllers/Api/ApiController.php index 6a9a48e9..509c09ad 100644 --- a/app/controllers/apis/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -1,31 +1,67 @@ -api_service = $api_service; + $this->api_repository = $api_repository; + $this->api_service = $api_service; //set filters allowed values - $this->allowed_filter_fields = array('resource_server_id'); - $this->allowed_projection_fields = array('*'); + $this->allowed_filter_fields = ['resource_server_id']; + $this->allowed_projection_fields = ['*']; } public function get($id) { try { - $api = $this->api_service->get($id); + $api = $this->api_repository->get($id); if(is_null($api)){ return $this->error404(array('error' => 'api not found')); } @@ -45,20 +81,28 @@ class ApiController extends AbstractRESTController implements ICRUDController { try { //check for optional filters param on querystring - $fields = $this->getProjection(Input::get('fields',null)); - $filters = $this->getFilters(Input::except('fields','limit','offset')); - $page_nbr = intval(Input::get('offset',1)); + $fields = $this->getProjection(Input::get('fields',null)); + $filters = $this->getFilters(Input::except('fields','limit','offset')); + $page_nbr = intval(Input::get('offset',1)); $page_size = intval(Input::get('limit',10)); - $list = $this->api_service->getAll($page_nbr,$page_size, $filters,$fields); - $items = array(); - foreach ($list->getItems() as $api) { + $list = $this->api_repository->getAll($page_nbr,$page_size, $filters,$fields); + $items = array(); + foreach ($list->items() as $api) + { array_push($items, $api->toArray()); } - return $this->ok( array( - 'page' => $items, - 'total_items' => $list->getTotal() - )); - } catch (Exception $ex) { + + return $this->ok + ( + array + ( + 'page' => $items, + 'total_items' => $list->total() + ) + ); + } + catch (Exception $ex) + { $this->log_service->error($ex); return $this->error500($ex); } @@ -134,9 +178,9 @@ class ApiController extends AbstractRESTController implements ICRUDController return $this->error400(array('error'=>'validation','messages' => $messages)); } - $res = $this->api_service->update(intval($values['id']),$values); + $this->api_service->update(intval($values['id']),$values); - return $res?$this->ok():$this->error400(array('error'=>'operation failed')); + return $this->ok(); } catch(InvalidApi $ex1){ diff --git a/app/controllers/apis/ApiEndpointController.php b/app/Http/Controllers/Api/ApiEndpointController.php similarity index 79% rename from app/controllers/apis/ApiEndpointController.php rename to app/Http/Controllers/Api/ApiEndpointController.php index 94fd7cf0..246c946c 100644 --- a/app/controllers/apis/ApiEndpointController.php +++ b/app/Http/Controllers/Api/ApiEndpointController.php @@ -1,9 +1,26 @@ -api_endpoint_service = $api_endpoint_service; + $this->endpoint_repository = $endpoint_repository; //set filters allowed values $this->allowed_filter_fields = array('api_id'); $this->allowed_projection_fields = array('*'); @@ -43,20 +75,27 @@ class ApiEndpointController extends AbstractRESTController implements ICRUDContr { try { //check for optional filters param on querystring - $fields = $this->getProjection(Input::get('fields',null)); - $filters = $this->getFilters(Input::except('fields','limit','offset')); - $page_nbr = intval(Input::get('offset',1)); + $fields = $this->getProjection(Input::get('fields',null)); + $filters = $this->getFilters(Input::except('fields','limit','offset')); + $page_nbr = intval(Input::get('offset',1)); $page_size = intval(Input::get('limit',10)); - $list = $this->api_endpoint_service->getAll($page_nbr, $page_size, $filters,$fields); - $items = array(); - foreach ($list->getItems() as $api_endpoint) { + $list = $this->endpoint_repository->getAll($page_nbr, $page_size, $filters, $fields); + $items = array(); + + foreach ($list->items() as $api_endpoint) { array_push($items, $api_endpoint->toArray()); } - return $this->ok( array( - 'page' => $items, - 'total_items' => $list->getTotal() - )); - } catch (Exception $ex) { + return $this->ok + ( + array + ( + 'page' => $items, + 'total_items' => $list->total() + ) + ); + } + catch (Exception $ex) + { $this->log_service->error($ex); return $this->error500($ex); } diff --git a/app/controllers/apis/ApiResourceServerController.php b/app/Http/Controllers/Api/ApiResourceServerController.php similarity index 50% rename from app/controllers/apis/ApiResourceServerController.php rename to app/Http/Controllers/Api/ApiResourceServerController.php index 560e65a4..9fed3938 100644 --- a/app/controllers/apis/ApiResourceServerController.php +++ b/app/Http/Controllers/Api/ApiResourceServerController.php @@ -1,11 +1,28 @@ -resource_server_service = $resource_server_service; - $this->allowed_filter_fields = array(''); - $this->allowed_projection_fields = array('*'); + $this->repository = $repository; + $this->resource_server_service = $resource_server_service; + $this->allowed_filter_fields = ['']; + $this->allowed_projection_fields = ['*']; } public function get($id) { try { - $resource_server = $this->resource_server_service->get($id); + $resource_server = $this->repository->get($id); if (is_null($resource_server)) { return $this->error404(array('error' => 'resource server not found')); } - $data = $resource_server->toArray(); - $apis = $resource_server->apis()->get(array('id', 'name')); + $data = $resource_server->toArray(); + $apis = $resource_server->apis()->get(array('id', 'name')); $data['apis'] = $apis->toArray(); - - $client = $resource_server->getClient(); + $client = $resource_server->getClient(); if (!is_null($client)) { $data['client_id'] = $client->getClientId(); @@ -42,9 +75,9 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU } return $this->ok($data); - } catch (Exception $ex) { + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } @@ -52,24 +85,25 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU public function getByPage() { try { - $fields = $this->getProjection(Input::get('fields', null)); - $filters = $this->getFilters(Input::except('fields', 'limit', 'offset')); - $page_nbr = intval(Input::get('offset', 1)); + $fields = $this->getProjection(Input::get('fields', null)); + $filters = $this->getFilters(Input::except('fields', 'limit', 'offset')); + $page_nbr = intval(Input::get('offset', 1)); $page_size = intval(Input::get('limit', 10)); - $list = $this->resource_server_service->getAll($page_nbr, $page_size, $filters, $fields); - $items = array(); - foreach ($list->getItems() as $rs) { - array_push($items, $rs->toArray()); + $paginator = $this->repository->getAll($page_nbr, $page_size, $filters, $fields); + $items = []; + + foreach ($paginator->items() as $rs) { + $items[] = $rs->toArray(); } - return $this->ok(array( - 'page' => $items, - 'total_items' => $list->getTotal() - )); - } catch (Exception $ex) { + return $this->ok([ + 'page' => $items, + 'total_items' => $paginator->total() + ]); + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } @@ -115,12 +149,15 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU public function delete($id) { try { - $res = $this->resource_server_service->delete($id); - - return $res ? $this->deleted() : $this->error404(array('error' => 'operation failed')); - } catch (Exception $ex) { + $this->resource_server_service->delete($id); + return $this->deleted(); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(['message' => $ex1->getMessage()]); + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } @@ -131,9 +168,13 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU $res = $this->resource_server_service->regenerateClientSecret($id); return !is_null($res) ? $this->ok(array('new_secret' => $res)) : $this->error404(array('error' => 'operation failed')); - } catch (Exception $ex) { + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(['message' => $ex1->getMessage()]); + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } @@ -159,14 +200,18 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU } $res = $this->resource_server_service->update(intval($values['id']), $values); - return $res ? $this->ok() : $this->error400(array('error' => 'operation failed')); - } catch (InvalidResourceServer $ex1) { + return $this->ok(); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(['message' => $ex1->getMessage()]); + } + catch (InvalidResourceServer $ex1) { $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { + return $this->error404(array('message' => $ex1->getMessage())); + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } @@ -174,12 +219,15 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU public function activate($id) { try { - $res = $this->resource_server_service->setStatus($id, true); - - return $res ? $this->ok() : $this->error400(array('error' => 'operation failed')); - } catch (Exception $ex) { + $this->resource_server_service->setStatus($id, true); + return $this->ok(); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(['message' => $ex1->getMessage()]); + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } @@ -187,12 +235,16 @@ class ApiResourceServerController extends AbstractRESTController implements ICRU public function deactivate($id) { try { - $res = $this->resource_server_service->setStatus($id, false); + $this->resource_server_service->setStatus($id, false); - return $res ? $this->ok() : $this->error400(array('error' => 'operation failed')); - } catch (Exception $ex) { + return $this->ok(); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(['message' => $ex1->getMessage()]); + } + catch (Exception $ex) { $this->log_service->error($ex); - return $this->error500($ex); } } diff --git a/app/controllers/apis/ApiScopeController.php b/app/Http/Controllers/Api/ApiScopeController.php similarity index 75% rename from app/controllers/apis/ApiScopeController.php rename to app/Http/Controllers/Api/ApiScopeController.php index 306290b0..fe301a3a 100644 --- a/app/controllers/apis/ApiScopeController.php +++ b/app/Http/Controllers/Api/ApiScopeController.php @@ -1,9 +1,26 @@ -scope_repository = $scope_repository; $this->api_scope_service = $api_scope_service; //set filters allowed values $this->allowed_filter_fields = array('api_id'); @@ -27,7 +55,7 @@ class ApiScopeController extends AbstractRESTController implements ICRUDControll public function get($id) { try { - $scope = $this->api_scope_service->get($id); + $scope = $this->scope_repository->get($id); if(is_null($scope)){ return $this->error404(array('error' => 'scope not found')); } @@ -43,20 +71,27 @@ class ApiScopeController extends AbstractRESTController implements ICRUDControll { try { //check for optional filters param on querystring - $fields = $this->getProjection(Input::get('fields',null)); - $filters = $this->getFilters(Input::except('fields','limit','offset')); - $page_nbr = intval(Input::get('offset',1)); + $fields = $this->getProjection(Input::get('fields',null)); + $filters = $this->getFilters(Input::except('fields','limit','offset')); + $page_nbr = intval(Input::get('offset',1)); $page_size = intval(Input::get('limit',10)); - $list = $this->api_scope_service->getAll($page_nbr, $page_size, $filters,$fields); + $list = $this->scope_repository->getAll($page_nbr, $page_size, $filters,$fields); $items = array(); - foreach ($list->getItems() as $scope) { + + foreach ($list->items() as $scope) + { array_push($items, $scope->toArray()); } - return $this->ok( array( - 'page' => $items, - 'total_items' => $list->getTotal() - )); + + return $this->ok + ( + array + ( + 'page' => $items, + 'total_items' => $list->total() + ) + ); } catch (Exception $ex) { $this->log_service->error($ex); return $this->error500($ex); diff --git a/app/controllers/apis/ApiScopeGroupController.php b/app/Http/Controllers/Api/ApiScopeGroupController.php similarity index 92% rename from app/controllers/apis/ApiScopeGroupController.php rename to app/Http/Controllers/Api/ApiScopeGroupController.php index 1a886497..f3962800 100644 --- a/app/controllers/apis/ApiScopeGroupController.php +++ b/app/Http/Controllers/Api/ApiScopeGroupController.php @@ -1,4 +1,4 @@ -repository->getAll($page_nbr, $page_size, $filters, $fields); $items = array(); - foreach ($list->getItems() as $g) + foreach ($list->items() as $g) { array_push($items, $g->toArray()); } @@ -152,7 +156,7 @@ final class ApiScopeGroupController extends AbstractRESTController implements IC array ( 'page' => $items, - 'total_items' => $list->getTotal() + 'total_items' => $list->total() ) ); } catch (Exception $ex) { diff --git a/app/controllers/apis/AssymetricKeyApiController.php b/app/Http/Controllers/Api/AsymmetricKeyApiController.php similarity index 75% rename from app/controllers/apis/AssymetricKeyApiController.php rename to app/Http/Controllers/Api/AsymmetricKeyApiController.php index 6ecb87d6..bd62e0af 100644 --- a/app/controllers/apis/AssymetricKeyApiController.php +++ b/app/Http/Controllers/Api/AsymmetricKeyApiController.php @@ -1,5 +1,4 @@ -error400(array('error' => 'validation', 'messages' => $messages)); } - $res = $this->service->update(intval($id), $values); + $this->service->update(intval($id), $values); - return $res ? $this->ok() : $this->error400(array('error' => 'operation failed')); + return $this->ok(); - } catch (AbsentClientException $ex1) { + } catch (EntityNotFoundException $ex1) { $this->log_service->error($ex1); return $this->error404(array('error' => $ex1->getMessage())); @@ -111,16 +114,20 @@ class AssymetricKeyApiController extends AbstractRESTController $list = $this->repository->getAll($page_nbr, $page_size, $filters, $fields); $items = array(); - foreach ($list->getItems() as $private_key) { + foreach ($list->items() as $private_key) { $data = $private_key->toArray(); $data['sha_256'] = $private_key->getSHA_256_Thumbprint(); array_push($items, $data); } - return $this->ok(array( - 'page' => $items, - 'total_items' => $list->getTotal() - )); + return $this->ok + ( + array + ( + 'page' => $items, + 'total_items' => $list->total() + ) + ); } catch (Exception $ex) { $this->log_service->error($ex); diff --git a/app/Http/Controllers/Api/ClientApiController.php b/app/Http/Controllers/Api/ClientApiController.php new file mode 100644 index 00000000..1fe132db --- /dev/null +++ b/app/Http/Controllers/Api/ClientApiController.php @@ -0,0 +1,754 @@ +client_service = $client_service; + $this->scope_service = $scope_service; + $this->token_service = $token_service; + $this->auth_service = $auth_service; + $this->access_token_repository = $access_token_repository; + $this->refresh_token_repository = $refresh_token_repository; + $this->client_repository = $client_repository; + + //set filters allowed values + $this->allowed_filter_fields = ['user_id']; + $this->allowed_projection_fields = ['*']; + } + + public function get($id) + { + try { + $client = $this->client_repository->getClientByIdentifier($id); + if (is_null($client)) + { + return $this->error404(array('error' => 'client not found')); + } + return $this->ok($client->toArray()); + } catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * Deletes an existing client + * @param $id + * @return mixed + */ + public function delete($id) + { + try { + $res = $this->client_service->deleteClientByIdentifier($id); + return $res ? $this->deleted() : $this->error404(array('error' => 'operation failed')); + } catch (Exception $ex) { + $this->log_service->error($ex); + + return $this->error500($ex); + } + } + + /** + * Creates an existing client + * @return mixed + */ + public function create() + { + try + { + + $values = Input::All(); + + // Build the validation constraint set. + $rules = array + ( + 'app_name' => 'required|freetext|max:255', + 'app_description' => 'required|freetext|max:512', + 'application_type' => 'required|applicationtype', + 'website' => 'sometimes|required|url', + 'admin_users' => 'sometimes|required|user_ids', + ); + + // Create a new validator instance. + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412(array('error' => 'validation', 'messages' => $messages)); + } + + + $admin_users = isset($values['admin_users']) ? trim($values['admin_users']): null; + $admin_users = empty($admin_users) ? array() : explode(',',$admin_users); + $website = isset($values['website']) ? trim($values['website']): null; + + $new_client = $this->client_service->register + ( + $values['application_type'], + trim($values['app_name']), + trim($values['app_description']), + $website, + $admin_users + ); + + return $this->created + ( + array + ( + 'id' => $new_client->id, + 'client_id' => $new_client->client_id, + 'client_secret' => $new_client->client_secret, + ) + ); + + } + catch(ValidationException $ex2) + { + $this->log_service->error($ex2); + return $this->error412(array($ex2->getMessage())); + } + catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @return mixed + */ + public function update() + { + try { + + $values = Input::all(); + + $rules = array( + 'id' => 'required|integer', + //'application_type' => 'required|application_type', + 'app_name' => 'sometimes|required|freetext|max:255', + 'app_description' => 'sometimes|required|freetext|max:512', + 'website' => 'sometimes|required|url', + 'active' => 'sometimes|required|boolean', + 'locked' => 'sometimes|required|boolean', + 'use_refresh_token' => 'sometimes|required|boolean', + 'rotate_refresh_token' => 'sometimes|required|boolean', + 'contacts' => 'sometimes|required|email_set', + 'logo_uri' => 'sometimes|required|url', + 'tos_uri' => 'sometimes|required|url', + 'redirect_uris' => 'sometimes|required|custom_url_set:application_type', + 'post_logout_redirect_uris' => 'sometimes|required|ssl_url_set', + 'allowed_origins' => 'sometimes|required|ssl_url_set', + 'logout_uri' => 'sometimes|required|url', + 'logout_session_required' => 'sometimes|required|boolean', + 'logout_use_iframe' => 'sometimes|required|boolean', + 'policy_uri' => 'sometimes|required|url', + 'jwks_uri' => 'sometimes|required|url', + 'default_max_age' => 'sometimes|required|integer', + 'logout_use_iframe' => 'sometimes|required|boolean', + 'require_auth_time' => 'sometimes|required|boolean', + 'token_endpoint_auth_method' => 'sometimes|required|token_endpoint_auth_method', + 'token_endpoint_auth_signing_alg' => 'sometimes|required|signing_alg', + 'subject_type' => 'sometimes|required|subject_type', + 'userinfo_signed_response_alg' => 'sometimes|required|signing_alg', + 'userinfo_encrypted_response_alg' => 'sometimes|required|encrypted_alg', + 'userinfo_encrypted_response_enc' => 'sometimes|required|encrypted_enc', + 'id_token_signed_response_alg' => 'sometimes|required|signing_alg', + 'id_token_encrypted_response_alg' => 'sometimes|required|encrypted_alg', + 'id_token_encrypted_response_enc' => 'sometimes|required|encrypted_enc', + 'admin_users' => 'sometimes|required|user_ids', + ); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412(array('error' => 'validation', 'messages' => $messages)); + } + + $this->client_service->update(intval($values['id']), $values); + + return $this->ok(); + + } + catch (EntityNotFoundException $ex1) + { + $this->log_service->error($ex1); + return $this->error404(array('error' => $ex1->getMessage())); + } + catch(ValidationException $ex2) + { + $this->log_service->error($ex2); + return $this->error412(array($ex2->getMessage())); + } + catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @return mixed + */ + public function getByPage() + { + try { + + $items = array(); + $user = $this->auth_service->getCurrentUser(); + if(is_null($user)) return $this->error403(); + $clients = $user->getClients(); + + foreach ($clients as $client) + { + $data = $client->toArray(); + $data['application_type'] = $client->getFriendlyApplicationType(); + $data['is_own'] = $client->isOwner($this->auth_service->getCurrentUser()); + $data['modified_by'] = $client->getEditedByNice(); + array_push($items, $data); + } + + return $this->ok + ( + array + ( + 'page' => $items, + 'total_items' => count($items) + ) + ); + + } + catch (Exception $ex) + { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @param $scope_id + * @return mixed + */ + public function addAllowedScope($id, $scope_id) + { + try + { + $this->client_service->addClientScope($id, $scope_id); + return $this->ok(); + } + catch (EntityNotFoundException $ex1) + { + $this->log_service->error($ex1); + return $this->error404(array('error' => $ex1->getMessage())); + } + catch (InvalidApiScope $ex2) + { + $this->log_service->error($ex2); + return $this->error412(array('messages' => $ex2->getMessage())); + } + catch (Exception $ex) + { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @param $scope_id + * @return mixed + */ + public function removeAllowedScope($id, $scope_id) + { + try + { + $this->client_service->deleteClientScope($id, $scope_id); + return $this->ok(); + } catch (EntityNotFoundException $ex1) { + $this->log_service->error($ex1); + + return $this->error404(array('error' => $ex1->getMessage())); + } catch (Exception $ex) { + $this->log_service->error($ex); + + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function activate($id) + { + try { + $this->client_service->activateClient($id, true); + return $this->ok(); + } catch (EntityNotFoundException $ex1) { + $this->log_service->error($ex1); + return $this->error404(array('error' => $ex1->getMessage())); + } catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function deactivate($id) + { + try { + $this->client_service->activateClient($id, false); + return $this->ok(); + } catch (EntityNotFoundException $ex1) { + $this->log_service->error($ex1); + + return $this->error404(array('error' => $ex1->getMessage())); + } catch (Exception $ex) { + $this->log_service->error($ex); + + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function regenerateClientSecret($id) + { + try + { + $client = $this->client_service->regenerateClientSecret($id); + + return !is_null($client) ? + $this->ok + ( + array + ( + 'new_secret' => $client->getClientSecret(), + 'new_expiration_date' => $client->getClientSecretExpiration(), + ) + ) : $this->error404(array('error' => 'operation failed')); + } + catch (Exception $ex) + { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function setRefreshTokenClient($id) + { + try { + $values = Input::All(); + + // Build the validation constraint set. + $rules = array( + 'use_refresh_token' => 'required|boolean' + ); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($values, $rules); + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error400(array('error' => 'validation', 'messages' => $messages)); + } + + $this->client_service->setRefreshTokenUsage($id, $values['use_refresh_token']); + + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + $this->log_service->error($ex1); + + return $this->error404(array('error' => $ex1->getMessage())); + } catch (Exception $ex) { + $this->log_service->error($ex); + + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function setRotateRefreshTokenPolicy($id) + { + try { + $values = Input::All(); + + // Build the validation constraint set. + $rules = array( + 'rotate_refresh_token' => 'required|boolean' + ); + // Creates a Validator instance and validates the data. + $validation = Validator::make($values, $rules); + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error400(array('error' => 'validation', 'messages' => $messages)); + } + + $this->client_service->setRotateRefreshTokenPolicy($id, $values['rotate_refresh_token']); + + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + $this->log_service->error($ex1); + + return $this->error404(array('error' => $ex1->getMessage())); + } catch (Exception $ex) { + $this->log_service->error($ex); + + return $this->error500($ex); + } + } + + /** + * @param $id + * @param $value + * @param $hint + * @return mixed + */ + public function revokeToken($id, $value, $hint) + { + try { + $res = false; + $client = $this->client_repository->getClientByIdentifier($id); + switch ($hint) { + case 'access-token': { + $token = $this->token_service->getAccessToken($value, true); + if (is_null($token)) { + return $this->error404(array('error' => sprintf('access token %s does not exists!', $value))); + } + Log::debug(sprintf('access token client id %s - client id %s ',$token->getClientId() , $client->client_id)); + if ($token->getClientId() !== $client->client_id) { + return $this->error412(array( + 'error' => sprintf('access token %s does not belongs to client id !', $value, $id) + )); + } + $res = $this->token_service->revokeAccessToken($value, true); + } + break; + case 'refresh-token': { + $token = $this->token_service->getRefreshToken($value, true); + if (is_null($token)) { + return $this->error404(array('error' => sprintf('refresh token %s does not exists!', $value))); + } + Log::debug(sprintf('refresh token client id %s - client id %s ',$token->getClientId() , $client->client_id)); + if ($token->getClientId() !== $client->client_id) { + return $this->error412(array( + 'error' => sprintf('refresh token %s does not belongs to client id !', $value, $id) + )); + } + $res = $this->token_service->revokeRefreshToken($value, true); + } + break; + default: + break; + } + + return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); + } + catch(ExpiredAccessTokenException $ex1){ + $this->log_service->warning($ex1); + return $this->error404(); + } + catch(Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function getAccessTokens($id) + { + try { + $page_nbr = intval(Input::get('offset', 1)); + $page_size = intval(Input::get('limit', 10)); + + $client = $this->client_repository->getClientByIdentifier($id); + + if(is_null($client)) + throw new EntityNotFoundException(); + + $paginator = $this->access_token_repository->getAllValidByClientIdentifier($id, $page_nbr, $page_size); + $res = []; + + foreach ($paginator->items() as $token) { + $res[] = [ + 'value' => $token->value, + 'scope' => $token->scope, + 'lifetime' => $token->getRemainingLifetime(), + 'issued' => $token->created_at->format('Y-m-d H:i:s') + ]; + } + return $this->ok([ + 'total' => $paginator->total(), + 'pages' => $paginator->total() > 0 ? ceil($paginator->total()/$page_size) : 0, + 'items' => $res + ]); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(); + } + catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function getRefreshTokens($id) + { + try { + $page_nbr = intval(Input::get('offset', 1)); + $page_size = intval(Input::get('limit', 10)); + + $client = $this->client_repository->getClientByIdentifier($id); + + if(is_null($client)) + throw new EntityNotFoundException(); + + $paginator = $this->refresh_token_repository->getAllValidByClientIdentifier($id, $page_nbr, $page_size); + $res = []; + + foreach ($paginator->items() as $token) { + $res[] = [ + 'value' => $token->value, + 'scope' => $token->scope, + 'lifetime' => $token->getRemainingLifetime(), + 'issued' => $token->created_at->format('Y-m-d H:i:s') + ]; + } + + return $this->ok([ + 'total' => $paginator->total(), + 'pages' => $paginator->total() > 0 ? ceil($paginator->total()/$page_size) : 0, + 'items' => $res + ]); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(); + } + catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @return mixed + */ + public function getAccessTokensByCurrentUser() + { + try { + $user = $this->auth_service->getCurrentUser(); + $page_nbr = intval(Input::get('offset', 1)); + $page_size = intval(Input::get('limit', 10)); + + + $paginator = $this->access_token_repository->getAllValidByUserId($user->getId(), $page_nbr, $page_size); + $res = []; + + foreach ($paginator->items() as $token) { + $res[] = [ + 'value' => $token->value, + 'scope' => $token->scope, + 'lifetime' => $token->getRemainingLifetime(), + 'issued' => $token->created_at->format('Y-m-d H:i:s') + ]; + } + return $this->ok([ + 'total' => $paginator->total(), + 'pages' => $paginator->total() > 0 ? ceil($paginator->total()/$page_size) : 0, + 'items' => $res + ]); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(); + } + catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @return mixed + */ + public function getRefreshTokensByCurrentUser() + { + try { + $user = $this->auth_service->getCurrentUser(); + $page_nbr = intval(Input::get('offset', 1)); + $page_size = intval(Input::get('limit', 10)); + + $paginator = $this->refresh_token_repository->getAllValidByUserId($user->getId(), $page_nbr, $page_size); + $res = []; + + foreach ($paginator->items() as $token) { + $res[] = [ + 'value' => $token->value, + 'scope' => $token->scope, + 'lifetime' => $token->getRemainingLifetime(), + 'issued' => $token->created_at->format('Y-m-d H:i:s') + ]; + } + + return $this->ok([ + 'total' => $paginator->total(), + 'pages' => $paginator->total() > 0 ? ceil($paginator->total()/$page_size) : 0, + 'items' => $res + ]); + } + catch (EntityNotFoundException $ex1) { + $this->log_service->warning($ex1); + return $this->error404(); + } + catch (Exception $ex) { + $this->log_service->error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return mixed + */ + public function unlock($id) + { + try { + $this->client_service->unlockClient($id); + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + + $this->log_service->error($ex1); + + return $this->error404(array('error' => $ex1->getMessage())); + } catch (Exception $ex) { + $this->log_service->error($ex); + + return $this->error500($ex); + } + } + +} \ No newline at end of file diff --git a/app/controllers/apis/ClientPublicKeyApiController.php b/app/Http/Controllers/Api/ClientPublicKeyApiController.php similarity index 73% rename from app/controllers/apis/ClientPublicKeyApiController.php rename to app/Http/Controllers/Api/ClientPublicKeyApiController.php index 3a9c1bf5..9c3fd4c8 100644 --- a/app/controllers/apis/ClientPublicKeyApiController.php +++ b/app/Http/Controllers/Api/ClientPublicKeyApiController.php @@ -1,33 +1,40 @@ - 'required|integer', 'kid' => 'required|text|max:255', 'active' => 'required|boolean', - 'valid_from' => 'date_format:m/d/Y', - 'valid_to' => 'date_format:m/d/Y|after:valid_from', + 'valid_from' => 'required|date_format:m/d/Y', + 'valid_to' => 'required|date_format:m/d/Y|after:valid_from', 'pem_content' => 'required|public_key_pem|public_key_pem_length', 'usage' => 'required|public_key_usage', 'type' => 'required|public_key_type', @@ -115,7 +122,7 @@ final class ClientPublicKeyApiController extends AssymetricKeyApiController ); $list = $this->repository->getAll($page_nbr, $page_size, $filters, $fields); $items = array(); - foreach ($list->getItems() as $private_key) { + foreach ($list->items() as $private_key) { $data = $private_key->toArray(); $data['sha_256'] = $private_key->getSHA_256_Thumbprint(); array_push($items, $data); @@ -123,7 +130,7 @@ final class ClientPublicKeyApiController extends AssymetricKeyApiController return $this->ok(array( 'page' => $items, - 'total_items' => $list->getTotal() + 'total_items' => $list->total() )); } catch (Exception $ex) { $this->log_service->error($ex); diff --git a/app/controllers/apis/ICRUDController.php b/app/Http/Controllers/Api/ICRUDController.php similarity index 86% rename from app/controllers/apis/ICRUDController.php rename to app/Http/Controllers/Api/ICRUDController.php index bfc96b6c..c6a68136 100644 --- a/app/controllers/apis/ICRUDController.php +++ b/app/Http/Controllers/Api/ICRUDController.php @@ -1,7 +1,7 @@ - 'Forbidden')) + { + return Response::json($data, 403); + } + /** * { "message": "Validation Failed", diff --git a/app/Http/Controllers/Api/OAuth2/OAuth2ProtectedController.php b/app/Http/Controllers/Api/OAuth2/OAuth2ProtectedController.php new file mode 100644 index 00000000..b7cc635d --- /dev/null +++ b/app/Http/Controllers/Api/OAuth2/OAuth2ProtectedController.php @@ -0,0 +1,50 @@ +resource_server_context = $resource_server_context; + } +} \ No newline at end of file diff --git a/app/controllers/apis/protected/OAuth2UserApiController.php b/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php similarity index 66% rename from app/controllers/apis/protected/OAuth2UserApiController.php rename to app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php index 3e9b1c2e..af08117a 100644 --- a/app/controllers/apis/protected/OAuth2UserApiController.php +++ b/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php @@ -1,17 +1,28 @@ -user_service = $user_service; - $this->client_service = $client_service; - $this->id_token_builder = $id_token_builder; + $this->user_service = $user_service; + $this->client_repository = $client_repository; + $this->id_token_builder = $id_token_builder; } /** @@ -77,7 +88,7 @@ class OAuth2UserApiController extends OAuth2ProtectedController { $claims = $this->user_service->getCurrentUserInfoClaims(); $client_id = $this->resource_server_context->getCurrentClientId(); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); // The UserInfo Claims MUST be returned as the members of a JSON object unless a signed or encrypted response // was requested during Client Registration. diff --git a/app/controllers/apis/ServerPrivateKeyApiController.php b/app/Http/Controllers/Api/ServerPrivateKeyApiController.php similarity index 87% rename from app/controllers/apis/ServerPrivateKeyApiController.php rename to app/Http/Controllers/Api/ServerPrivateKeyApiController.php index 5e3a786c..a2241641 100644 --- a/app/controllers/apis/ServerPrivateKeyApiController.php +++ b/app/Http/Controllers/Api/ServerPrivateKeyApiController.php @@ -1,5 +1,4 @@ -user_service->unlockUser($id); return $this->updated(); } - catch (AbsentClientException $ex1) { + catch (EntityNotFoundException $ex1) { $this->log_service->error($ex1); return $this->error404(array('error' => $ex1->getMessage())); } @@ -117,7 +130,7 @@ class UserApiController extends AbstractRESTController implements ICRUDControlle public function get($id) { try { - $user = $this->user_service->get($id); + $user = $this->user_repository->get($id); if(is_null($user)){ return $this->error404(array('error' => 'user not found')); } @@ -153,11 +166,14 @@ class UserApiController extends AbstractRESTController implements ICRUDControlle { $values = Input::all(); if(!isset($values['t'])) return $this->error404(); + $term = $values['t']; $users = $this->user_repository->getByEmailOrName($term); + $list = array(); + if(count($users) > 0) { - $list = array(); + foreach($users as $u) { array_push($list, array @@ -167,8 +183,8 @@ class UserApiController extends AbstractRESTController implements ICRUDControlle ) ); } - return $this->ok($list); + } - return $this->updated(); + return $this->ok($list); } } \ No newline at end of file diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 00000000..6979db15 --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,27 @@ +discovery = $discovery; + } + + public function index() + { + + if ($this->isDiscoveryRequest()) + return $this->discovery->idp(); + if (Auth::guest()) { + Session::flush(); + Session::regenerate(); + return View::make("home"); + } + else + return Redirect::action("UserController@getProfile"); + } +} \ No newline at end of file diff --git a/app/controllers/oauth2/OAuth2ProviderController.php b/app/Http/Controllers/OAuth2/OAuth2ProviderController.php similarity index 72% rename from app/controllers/oauth2/OAuth2ProviderController.php rename to app/Http/Controllers/OAuth2/OAuth2ProviderController.php index 5517e431..8d0ef625 100644 --- a/app/controllers/oauth2/OAuth2ProviderController.php +++ b/app/Http/Controllers/OAuth2/OAuth2ProviderController.php @@ -1,24 +1,43 @@ -oauth2_protocol = $oauth2_protocol; - $this->auth_service = $auth_service; - $this->client_service = $client_service; + $this->oauth2_protocol = $oauth2_protocol; + $this->auth_service = $auth_service; + $this->client_repository = $client_repository; } /** @@ -59,7 +78,7 @@ final class OAuth2ProviderController extends BaseController * use of the "POST" method as well. * @return mixed */ - public function authorize() + public function auth() { try { @@ -89,10 +108,10 @@ final class OAuth2ProviderController extends BaseController { return Response::view ( - '400', + 'errors.400', array ( - 'error_code' => $ex1->getError(), + 'error_code' => $ex1->getError(), 'error_description' => $ex1->getMessage() ), 400 @@ -162,7 +181,7 @@ final class OAuth2ProviderController extends BaseController } /** - * http://tools.ietf.org/html/draft-richer-oauth-introspection-04 + * @see http://tools.ietf.org/html/draft-richer-oauth-introspection-04 * Introspection Token HTTP Endpoint * @return mixed */ @@ -218,7 +237,7 @@ final class OAuth2ProviderController extends BaseController } /** - * http://openid.net/specs/openid-connect-session-1_0.html#OPiframe + * @see http://openid.net/specs/openid-connect-session-1_0.html#OPiframe */ public function checkSessionIFrame() { @@ -227,12 +246,12 @@ final class OAuth2ProviderController extends BaseController } /** - * http://openid.net/specs/openid-connect-session-1_0.html#RPLogout + * @see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout */ public function endSession() { if(!$this->auth_service->isUserLogged()) - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); $request = new OAuth2LogoutRequest ( @@ -245,7 +264,7 @@ final class OAuth2ProviderController extends BaseController if(!$request->isValid()) { Log::error('invalid OAuth2LogoutRequest!'); - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); } if(Request::isMethod('get') ) @@ -254,7 +273,7 @@ final class OAuth2ProviderController extends BaseController $clients = array(); foreach($this->auth_service->getLoggedRPs() as $client_id) { - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); if(!is_null($client)) array_push($clients, $client); } @@ -285,7 +304,7 @@ final class OAuth2ProviderController extends BaseController } Log::error('invalid consent response!'); - return Response::view('404', array(), 404); + return Response::view('errors.404', array(), 404); } public function cancelLogout() diff --git a/app/Http/Controllers/OpenId/DiscoveryController.php b/app/Http/Controllers/OpenId/DiscoveryController.php new file mode 100644 index 00000000..8a77df4e --- /dev/null +++ b/app/Http/Controllers/OpenId/DiscoveryController.php @@ -0,0 +1,90 @@ +openid_protocol = $openid_protocol; + $this->auth_service = $auth_service; + $this->server_config_service = $server_config_service; + } + + /** + * XRDS discovery(eXtensible Resource Descriptor Sequence) + * @return xrds document on response + */ + public function idp() + { + $response = Response::make($this->openid_protocol->getXRDSDiscovery(IOpenIdProtocol::OpenIdXRDSModeIdp), 200); + $this->setDiscoveryResponseType($response); + return $response; + } + + /** + * If the Claimed Identifier was not previously discovered by the Relying Party + * (the "openid.identity" in the request was "http://specs.openid.net/auth/2.0/identifier_select" + * or a different Identifier, or if the OP is sending an unsolicited positive assertion), + * the Relying Party MUST perform discovery on the Claimed Identifier in + * the response to make sure that the OP is authorized to make assertions about the Claimed Identifier. + * @param $identifier + * @return mixed + */ + public function user($identifier) + { + $user = $this->auth_service->getUserByOpenId($identifier); + if (is_null($user)) + return View::make("errors.404"); + + $local_identifier = $this->server_config_service->getUserIdentityEndpointURL($identifier); + $response = Response::make($this->openid_protocol->getXRDSDiscovery(IOpenIdProtocol::OpenIdXRDSModeUser, $local_identifier), 200); + $this->setDiscoveryResponseType($response); + return $response; + } + +} \ No newline at end of file diff --git a/app/controllers/openid/OpenIdController.php b/app/Http/Controllers/OpenId/OpenIdController.php similarity index 82% rename from app/controllers/openid/OpenIdController.php rename to app/Http/Controllers/OpenId/OpenIdController.php index 10db8def..069e736e 100644 --- a/app/controllers/openid/OpenIdController.php +++ b/app/Http/Controllers/OpenId/OpenIdController.php @@ -1,4 +1,4 @@ -openid_protocol = $openid_protocol; + $this->memento_service = $memento_service; + } + + /** + * @return OpenIdResponse + * @throws Exception + * @throws InvalidOpenIdMessageException + */ + public function endpoint() + { + $msg = new OpenIdMessage(Input::all()); + + if ($this->memento_service->exists()) { + $msg = OpenIdMessage::buildFromMemento($this->memento_service->load()); + } + + if (!$msg->isValid()) + throw new InvalidOpenIdMessageException(OpenIdErrorMessages::InvalidOpenIdMessage); + + //get response and manage it taking in consideration its type (direct or indirect) + $response = $this->openid_protocol->handleOpenIdMessage($msg); + + if ($response instanceof OpenIdResponse) { + $strategy = OpenIdResponseStrategyFactoryMethod::buildStrategy($response); + return $strategy->handle($response); + } + return $response; + } +} \ No newline at end of file diff --git a/app/controllers/UserController.php b/app/Http/Controllers/UserController.php similarity index 77% rename from app/controllers/UserController.php rename to app/Http/Controllers/UserController.php index 0d746f66..3e3e4b5f 100644 --- a/app/controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -1,33 +1,58 @@ -openid_memento_service = $openid_memento_service; - $this->oauth2_memento_service = $oauth2_memento_service; - $this->auth_service = $auth_service; + $this->openid_memento_service = $openid_memento_service; + $this->oauth2_memento_service = $oauth2_memento_service; + $this->auth_service = $auth_service; $this->server_configuration_service = $server_configuration_service; - $this->trusted_sites_service = $trusted_sites_service; - $this->discovery = $discovery; - $this->user_service = $user_service; - $this->user_action_service = $user_action_service; - $this->client_service = $client_service; - $this->scope_service = $scope_service; - $this->token_service = $token_service; - $this->resource_server_service = $resource_server_service; - $this->utils_configuration_service = $utils_configuration_service; - //filters - $this->beforeFilter('csrf', array('only' => array('postLogin', 'postConsent'))); + $this->trusted_sites_service = $trusted_sites_service; + $this->discovery = $discovery; + $this->user_service = $user_service; + $this->user_action_service = $user_action_service; + $this->client_repository = $client_repository; + $this->scope_repository = $scope_repository; + $this->token_service = $token_service; + $this->resource_server_service = $resource_server_service; + $this->utils_configuration_service = $utils_configuration_service; if ($this->openid_memento_service->exists()) { @@ -169,8 +194,8 @@ final class UserController extends OpenIdController ( $auth_service, $oauth2_memento_service, - $scope_service, - $client_service + $scope_repository, + $client_repository ); } else @@ -291,7 +316,7 @@ final class UserController extends OpenIdController { if (is_null($this->consent_strategy)) { - return View::make("404"); + return View::make("errors.404"); } return $this->consent_strategy->getConsent(); @@ -312,7 +337,7 @@ final class UserController extends OpenIdController { if (is_null($this->consent_strategy)) { - return View::make("404"); + return View::make("errors.404"); } return $this->consent_strategy->postConsent(Input::get("trust")); @@ -333,7 +358,7 @@ final class UserController extends OpenIdController $user = $this->auth_service->getUserByOpenId($identifier); if (is_null($user)) { - return View::make("404"); + return View::make("errors.404"); } if ($this->isDiscoveryRequest()) @@ -375,7 +400,7 @@ final class UserController extends OpenIdController catch (Exception $ex) { Log::error($ex); - return View::make("404"); + return View::make("errors.404"); } } @@ -383,7 +408,7 @@ final class UserController extends OpenIdController { $this->user_action_service->addUserAction ( - $this->auth_service->getCurrentUser(), + $this->auth_service->getCurrentUser()->getId(), IPHelper::getUserIp(), IUserActionService::LogoutAction ); @@ -419,8 +444,9 @@ final class UserController extends OpenIdController public function postUserProfileOptions() { $show_full_name = Input::get("show_full_name"); - $show_email = Input::get("show_email"); - $show_pic = Input::get("show_pic"); + $show_email = Input::get("show_email"); + $show_pic = Input::get("show_pic"); + $user = $this->auth_service->getCurrentUser(); $this->user_service->saveProfileInfo($user->getId(), $show_pic, $show_full_name, $show_email); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php new file mode 100644 index 00000000..82494ac4 --- /dev/null +++ b/app/Http/Kernel.php @@ -0,0 +1,78 @@ + [ + \App\Http\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + ], + + 'api' => [ + 'ssl', + 'cors', + 'oauth2.endpoint', + ], + ]; + + /** + * The application's route middleware. + * + * These middleware may be assigned to groups or used individually. + * + * @var array + */ + protected $routeMiddleware = [ + 'auth' => \App\Http\Middleware\Authenticate::class, + 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'ssl' => \App\Http\Middleware\SSLMiddleware::class, + 'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'csrf' => \App\Http\Middleware\VerifyCsrfToken::class, + 'oauth2.endpoint' => \App\Http\Middleware\OAuth2BearerAccessTokenRequestValidator::class, + 'cors' => \App\Http\Middleware\CORSMiddleware::class, + 'oauth2.currentuser.serveradmin' => \App\Http\Middleware\CurrentUserIsOAuth2ServerAdmin::class, + 'oauth2.currentuser.serveradmin.json' => \App\Http\Middleware\CurrentUserIsOAuth2ServerAdminJson::class, + 'openstackid.currentuser.serveradmin' => \App\Http\Middleware\CurrentUserIsOpenIdServerAdmin::class, + 'openstackid.currentuser.serveradmin.json' => \App\Http\Middleware\CurrentUserIsOpenIdServerAdminJson::class, + 'oauth2.currentuser.allow.client.edition' => \App\Http\Middleware\CurrentUserCanEditOAuth2Client::class, + 'oauth2.currentuser.owns.client' => \App\Http\Middleware\CurrentUserOwnsOAuth2Client::class, + 'currentuser.checkroute' => \App\Http\Middleware\CurrentUserCheckRouteParams::class, + ]; +} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php new file mode 100644 index 00000000..2e050d2e --- /dev/null +++ b/app/Http/Middleware/Authenticate.php @@ -0,0 +1,49 @@ +guest()) { + Session::put('url.intended', URL::full()); + Session::save(); + return Redirect::action('HomeController@index'); + } + $redirect = Session::get('url.intended'); + if (!empty($redirect)) { + Session::forget('url.intended'); + Session::save(); + return Redirect::to($redirect); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/CORSMiddleware.php b/app/Http/Middleware/CORSMiddleware.php new file mode 100644 index 00000000..ab7b02ed --- /dev/null +++ b/app/Http/Middleware/CORSMiddleware.php @@ -0,0 +1,457 @@ +endpoint_repository = $endpoint_repository; + $this->cache_service = $cache_service; + $this->allowed_headers = Config::get('cors.allowed_headers', self::DefaultAllowedHeaders); + $this->allowed_methods = Config::get('cors.allowed_methods', self::DefaultAllowedMethods); + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + if ($response = $this->preProcess($request)) { + return $response; + } + //normal processing + $response = $next($request); + $this->postProcess($request, $response); + return $response; + } + + private function generatePreflightCacheKey($request) + { + $cache_id = 'pre-flight-' . $request->getClientIp() . '-' . $request->getRequestUri() . '-' . $request->getMethod(); + return $cache_id; + } + + /** + * @param Request $request + * @return Response + */ + public function preProcess(Request $request) + { + $actual_request = false; + if ($this->isValidCORSRequest($request)) { + if (!$this->testOriginHeaderScrutiny($request)) { + $response = new Response(); + $response->setStatusCode(403); + return $response; + } + /* Step 01 : Determine the type of the incoming request */ + $type = $this->getRequestType($request); + /* Step 02 : Process request according to is type */ + switch ($type) { + case CORSRequestPreflightType::REQUEST_FOR_PREFLIGHT: { + // HTTP request send by client to preflight a further 'Complex' request + // sets the original method on request in order to be able to find the + // correct route + $real_method = $request->headers->get('Access-Control-Request-Method'); + + $route_path = Route::getCurrentRoute()->getPath(); + if (strpos($route_path, '/') != 0) + $route_path = '/' . $route_path; + + $request->setMethod($real_method); + + if (!$route_path || !$this->checkEndPoint($route_path, $real_method)) { + $response = new Response(); + $response->setStatusCode(403); + return $response; + } + // ----Step 2b: Store pre-flight request data in the Cache to keep (mark) the request as correctly followed the request pre-flight process + $data = new CORSRequestPreflightData($request, $this->current_endpoint->supportCredentials()); + $cache_id = $this->generatePreflightCacheKey($request); + $this->cache_service->storeHash($cache_id, $data->toArray(), CORSRequestPreflightData::$cache_lifetime); + // ----Step 2c: Return corresponding response - This part should be customized with application specific constraints..... + return $this->makePreflightResponse($request); + } + break; + case CORSRequestPreflightType::COMPLEX_REQUEST: { + $cache_id = $this->generatePreflightCacheKey($request);; // ----Step 2a: Check if the current request has an entry into the preflighted requests Cache + $data = $this->cache_service->getHash($cache_id, CORSRequestPreflightData::$cache_attributes); + if (!count($data)) { + $response = new Response(); + $response->setStatusCode(403); + return $response; + } + // ----Step 2b: Check that pre-flight information declared during the pre-flight request match the current request on key information + $match = false; + // ------Start with comparison of "Origin" HTTP header (according to utility method impl. used to retrieve header reference cannot be null)... + if ($request->headers->get('Origin') === $data['origin']) { + // ------Continue with HTTP method... + if ($request->getMethod() === $data['expected_method']) { + // ------Finish with custom HTTP headers (use an method to avoid manual iteration on collection to increase the speed)... + $x_headers = self::getCustomHeaders($request); + $x_headers_pre = explode(',', $data['expected_custom_headers']); + sort($x_headers); + sort($x_headers_pre); + if (count(array_diff($x_headers, $x_headers_pre)) === 0) { + $match = true; + } + } + } + if (!$match) { + $response = new Response(); + $response->setStatusCode(403); + return $response; + } + $actual_request = true; + } + break; + case CORSRequestPreflightType::SIMPLE_REQUEST: { + // origins, do not set any additional headers and terminate this set of steps. + if (!$this->isAllowedOrigin($request)) { + $response = new Response(); + $response->setStatusCode(403); + + return $response; + } + $actual_request = true; + // If the resource supports credentials add a single Access-Control-Allow-Origin header, with the value + // of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the + // case-sensitive string "true" as value. + // Otherwise, add a single Access-Control-Allow-Origin header, with either the value of the Origin header + // or the string "*" as value. + } + break; + } + } + if ($actual_request) { + // Save response headers + $cache_id = $this->generatePreflightCacheKey($request); + // ----Step 2a: Check if the current request has an entry into the preflighted requests Cache + $data = $this->cache_service->getHash($cache_id, CORSRequestPreflightData::$cache_attributes); + $this->headers['Access-Control-Allow-Origin'] = $request->headers->get('Origin'); + if ((isset($data['allows_credentials']) && (bool)$data['allows_credentials'])) { + $this->headers['Access-Control-Allow-Credentials'] = 'true'; + } + /** + * During a CORS request, the getResponseHeader() method can only access simple response headers. + * Simple response headers are defined as follows: + ** Cache-Control + ** Content-Language + ** Content-Type + ** Expires + ** Last-Modified + ** Pragma + * If you want clients to be able to access other headers, + * you have to use the Access-Control-Expose-Headers header. + * The value of this header is a comma-delimited list of response headers you want to expose + * to the client. + */ + $exposed_headers = Config::get('cors.exposed_headers', 'Content-Type, Expires'); + if (!empty($exposed_headers)) { + $this->headers['Access-Control-Expose-Headers'] = $exposed_headers; + } + } + } + + public function postProcess(Request $request, Response $response) + { + // add CORS response headers + if (count($this->headers) > 0) { + $response->headers->add($this->headers); + } + return $response; + } + + /** + * @param Request $request + * @return Response + */ + private function makePreflightResponse(Request $request) + { + $response = new Response(); + if (!$this->isAllowedOrigin($request)) { + $response->headers->set('Access-Control-Allow-Origin', 'null'); + $response->setStatusCode(403); + return $response; + } + $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin')); + // The Access-Control-Request-Method header indicates which method will be used in the actual + // request as part of the preflight request + // check request method + if ($request->headers->get('Access-Control-Request-Method') != $this->current_endpoint->getHttpMethod()) { + $response->setStatusCode(405); + return $response; + } + // The Access-Control-Allow-Credentials header indicates whether the response to request + // can be exposed when the omit credentials flag is unset. When part of the response to a preflight request + // it indicates that the actual request can include user credentials. + if ($this->current_endpoint->supportCredentials()) { + $response->headers->set('Access-Control-Allow-Credentials', 'true'); + } + if (Config::get('cors.use_pre_flight_caching', false)) { + // The Access-Control-Max-Age header indicates how long the response can be cached, so that for + // subsequent requests, within the specified time, no preflight request has to be made. + $response->headers->set('Access-Control-Max-Age', Config::get('cors.max_age', 32000)); + } + // The Access-Control-Allow-Headers header indicates, as part of the response to a preflight request, + // which header field names can be used during the actual request + $response->headers->set('Access-Control-Allow-Headers', $this->allowed_headers); + + //The Access-Control-Allow-Methods header indicates, as part of the response to a preflight request, + // which methods can be used during the actual request. + $response->headers->set('Access-Control-Allow-Methods', $this->allowed_methods); + // The Access-Control-Request-Headers header indicates which headers will be used in the actual request + // as part of the preflight request. + $headers = $request->headers->get('Access-Control-Request-Headers'); + if ($headers) { + $headers = trim(strtolower($headers)); + $allow_headers = explode(', ', $this->allowed_headers); + foreach (preg_split('{, *}', $headers) as $header) { + //if they are simple headers then skip them + if (in_array($header, self::$simple_headers, true)) { + continue; + } + //check is the requested header is on the list of allowed headers + if (!in_array($header, $allow_headers, true)) { + $response->setStatusCode(400); + $response->setContent('Unauthorized header ' . $header); + break; + } + } + } + //OK - No Content + $response->setStatusCode(204); + return $response; + } + + /** + * @param Request $request + * @returns bool + */ + private function isValidCORSRequest(Request $request) + { + /** + * The presence of the Origin header does not necessarily mean that the request is a cross-origin request. + * While all cross-origin requests will contain an Origin header, + * Origin header on same-origin requests. But Chrome and Safari include an Origin header on + * same-origin POST/PUT/DELETE requests (same-origin GET requests will not have an Origin header). + */ + return $request->headers->has('Origin'); + } + + /** + * https://www.owasp.org/index.php/CORS_OriginHeaderScrutiny + * Filter that will ensure the following points for each incoming HTTP CORS requests: + * - Have only one and non empty instance of the origin header, + * - Have only one and non empty instance of the host header, + * - The value of the origin header is present in a internal allowed domains list (white list). As we act before the + * step 2 of the CORS HTTP requests/responses exchange process, allowed domains list is yet provided to client, + * - Cache IP of the sender for 1 hour. If the sender send one time a origin domain that is not in the white list + * then all is requests will return an HTTP 403 response (protract allowed domain guessing). + * We use the method above because it's not possible to identify up to 100% that the request come from one expected + * client application, since: + * - All information of a HTTP request can be faked, + * - It's the browser (or others tools) that send the HTTP request then the IP address that we have access to is the + * client IP address. + * @param Request $request + * @return bool + */ + private function testOriginHeaderScrutiny(Request $request) + { + /* Step 0 : Check presence of client IP in black list */ + $client_ip = $request->getClientIp(); + if (Cache::has(self::CORS_IP_BLACKLIST_PREFIX . $client_ip)) { + return false; + } + /* Step 1 : Check that we have only one and non empty instance of the "Origin" header */ + $origin = $request->headers->get('Origin', null, false); + if (is_array($origin) && count($origin) > 1) { + // If we reach this point it means that we have multiple instance of the "Origin" header + // Add client IP address to black listed client + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } + /* Step 2 : Check that we have only one and non empty instance of the "Host" header */ + $host = $request->headers->get('Host', null, false); + //Have only one and non empty instance of the host header, + if (is_array($host) && count($host) > 1) { + // If we reach this point it means that we have multiple instance of the "Host" header + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } + /* Step 3 : Perform analysis - Origin header is required */ + + $origin = $request->headers->get('Origin'); + $host = $request->headers->get('Host'); + $server_name = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; + + + // check origin not empty and allowed + + if (!$this->isAllowedOrigin($origin)) { + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } + + if (is_null($host) || $server_name != $host) { + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } + + /* Step 4 : Finalize request next step */ + return true; + } + + private function checkEndPoint($endpoint_path, $http_method) + { + $this->current_endpoint = $this->endpoint_repository->getApiEndpointByUrlAndMethod($endpoint_path, $http_method); + if (is_null($this->current_endpoint)) { + return false; + } + if (!$this->current_endpoint->supportCORS() || !$this->current_endpoint->isActive()) { + return false; + } + return true; + } + + /** + * @param string $origin + * @return bool + */ + private function isAllowedOrigin($origin) + { + return true; + } + + private static function getRequestType(Request $request) + { + + $type = CORSRequestPreflightType::UNKNOWN; + $http_method = $request->getMethod(); + $content_type = strtolower($request->getContentType()); + $http_method = strtoupper($http_method); + + if ($http_method === 'OPTIONS' && $request->headers->has('Access-Control-Request-Method')) { + $type = CORSRequestPreflightType::REQUEST_FOR_PREFLIGHT; + } else { + if (self::hasCustomHeaders($request)) { + $type = CORSRequestPreflightType::COMPLEX_REQUEST; + } elseif ($http_method === 'POST' && !in_array($content_type, self::$simple_content_header_values, true)) { + $type = CORSRequestPreflightType::COMPLEX_REQUEST; + } elseif (!in_array($http_method, self::$simple_http_methods, true)) { + $type = CORSRequestPreflightType::COMPLEX_REQUEST; + } else { + $type = CORSRequestPreflightType::SIMPLE_REQUEST; + } + } + return $type; + } + + + private static function getCustomHeaders(Request $request) + { + $custom_headers = array(); + foreach ($request->headers->all() as $k => $h) { + if (starts_with('X-', strtoupper(trim($k)))) { + array_push($custom_headers, strtoupper(trim($k))); + } + } + return $custom_headers; + } + + private static function hasCustomHeaders(Request $request) + { + return count(self::getCustomHeaders($request)) > 0; + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CORSRequestPreflightData.php b/app/Http/Middleware/CORSRequestPreflightData.php new file mode 100644 index 00000000..899dad76 --- /dev/null +++ b/app/Http/Middleware/CORSRequestPreflightData.php @@ -0,0 +1,82 @@ +sender = $request->getClientIp(); + $this->uri = $request->getRequestUri(); + $this->origin = $request->headers->get('Origin'); + $this->expected_method = $request->headers->get('Access-Control-Request-Method'); + $this->allows_credentials = $allows_credentials; + + $tmp = $request->headers->get("Access-Control-Request-Headers"); + if (!empty($tmp)) + { + $hs = explode(',', $tmp); + foreach ($hs as $h) + { + array_push($this->expected_custom_headers, strtoupper(trim($h))); + } + } + } + + /** + * @return array + */ + public function toArray() + { + $res = array(); + $res['sender'] = $this->sender; + $res['uri'] = $this->uri; + $res['origin'] = $this->origin; + $res['allows_credentials'] = $this->allows_credentials; + $res['expected_method'] = $this->expected_method; + $res['expected_custom_headers'] = implode(',', $this->expected_custom_headers); + return $res; + } + +} \ No newline at end of file diff --git a/app/Http/Middleware/CORSRequestPreflightType.php b/app/Http/Middleware/CORSRequestPreflightType.php new file mode 100644 index 00000000..4dcf2a82 --- /dev/null +++ b/app/Http/Middleware/CORSRequestPreflightType.php @@ -0,0 +1,36 @@ +client_repository = $client_repository; + $this->auth_service = $auth_service; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string|null $guard + * @return mixed + */ + public function handle($request, Closure $next, $guard = null) + { + try{ + $route = Route::getCurrentRoute(); + $client_id = $route->getParameter('id'); + + if(is_null($client_id)) + $client_id = $route->getParameter('client_id'); + + if(is_null($client_id)) + $client_id = Input::get('client_id',null);; + + $client = $this->client_repository->getClientByIdentifier($client_id); + $user = $this->auth_service->getCurrentUser(); + + if (is_null($client) || !$client->candEdit($user)) + throw new Exception('invalid client id for current user'); + + } catch (Exception $ex) { + Log::error($ex); + return Response::json(array('error' => 'operation not allowed.'), 400); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CurrentUserCheckRouteParams.php b/app/Http/Middleware/CurrentUserCheckRouteParams.php new file mode 100644 index 00000000..b8e96733 --- /dev/null +++ b/app/Http/Middleware/CurrentUserCheckRouteParams.php @@ -0,0 +1,63 @@ +getService(UtilsServiceCatalog::AuthenticationService); + $used_id = Input::get('user_id',null); + + if(is_null($used_id)) + $used_id = Input::get('id',null); + + if(is_null($used_id)) + $used_id = $route->getParameter('user_id'); + + if(is_null($used_id)) + $used_id = $route->getParameter('id'); + + $user = $authentication_service->getCurrentUser(); + if (is_null($used_id) || intval($used_id) !== intval($user->getId())) + throw new Exception(sprintf('user id %s does not match with current user id %s',$used_id,$user->getId())); + + } catch (Exception $ex) { + Log::error($ex); + return Response::json(array('error' => 'operation not allowed.'), 400); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CurrentUserIsOAuth2ServerAdmin.php b/app/Http/Middleware/CurrentUserIsOAuth2ServerAdmin.php new file mode 100644 index 00000000..2cc0ad3e --- /dev/null +++ b/app/Http/Middleware/CurrentUserIsOAuth2ServerAdmin.php @@ -0,0 +1,44 @@ +guest()) + { + return Response::view('errors.404', array(), 404); + } + if(!Auth::user()->isOAuth2ServerAdmin()) + { + return Response::view('errors.404', array(), 404); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CurrentUserIsOAuth2ServerAdminJson.php b/app/Http/Middleware/CurrentUserIsOAuth2ServerAdminJson.php new file mode 100644 index 00000000..10faf622 --- /dev/null +++ b/app/Http/Middleware/CurrentUserIsOAuth2ServerAdminJson.php @@ -0,0 +1,45 @@ +guest()) + { + return Response::json(array('error' => 'you are not allowed to perform this operation'), 403); + } + if(!Auth::user()->isOAuth2ServerAdmin()) + { + return Response::json(array('error' => 'you are not allowed to perform this operation'), 403); + } + + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CurrentUserIsOpenIdServerAdmin.php b/app/Http/Middleware/CurrentUserIsOpenIdServerAdmin.php new file mode 100644 index 00000000..37ff9325 --- /dev/null +++ b/app/Http/Middleware/CurrentUserIsOpenIdServerAdmin.php @@ -0,0 +1,44 @@ +guest()) + { + return Response::view('errors.404', array(), 404); + } + if(!Auth::user()->isOpenstackIdAdmin()) + { + return Response::view('errors.404', array(), 404); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CurrentUserIsOpenIdServerAdminJson.php b/app/Http/Middleware/CurrentUserIsOpenIdServerAdminJson.php new file mode 100644 index 00000000..8a7f6b6f --- /dev/null +++ b/app/Http/Middleware/CurrentUserIsOpenIdServerAdminJson.php @@ -0,0 +1,44 @@ +guest()) + { + return Response::json(array('error' => 'you are not allowed to perform this operation')); + } + if(!Auth::user()->isOpenstackIdAdmin()) + { + return Response::json(array('error' => 'you are not allowed to perform this operation')); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CurrentUserOwnsOAuth2Client.php b/app/Http/Middleware/CurrentUserOwnsOAuth2Client.php new file mode 100644 index 00000000..e175fff3 --- /dev/null +++ b/app/Http/Middleware/CurrentUserOwnsOAuth2Client.php @@ -0,0 +1,80 @@ +client_repository = $client_repository; + $this->auth_service = $auth_service; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string|null $guard + * @return mixed + */ + public function handle($request, Closure $next, $guard = null) + { + try{ + $route = Route::getCurrentRoute(); + $client_id = $route->getParameter('id'); + + if(is_null($client_id)) + $client_id = $route->getParameter('client_id'); + + if(is_null($client_id)) + $client_id = Input::get('client_id',null);; + + $client = $this->client_repository->getClientByIdentifier($client_id); + $user = $this->auth_service->getCurrentUser(); + if (is_null($client) || !$client->isOwner($user)) + throw new Exception('invalid client id for current user'); + + } catch (Exception $ex) { + Log::error($ex); + return Response::json(array('error' => 'operation not allowed.'), 400); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/ETagsMiddleware.php b/app/Http/Middleware/ETagsMiddleware.php new file mode 100644 index 00000000..f7c4abf1 --- /dev/null +++ b/app/Http/Middleware/ETagsMiddleware.php @@ -0,0 +1,51 @@ +getStatusCode() === 200 && $request->getMethod() === 'GET') + { + $etag = md5($response->getContent()); + $requestETag = str_replace('"', '', $request->getETags()); + $requestETag = str_replace('-gzip', '', $requestETag); + + if ($requestETag && $requestETag[0] == $etag) + { + Log::debug('ETAG 304'); + $response->setNotModified(); + } + $response->setEtag($etag); + } + + return $response; + } +} \ No newline at end of file diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php new file mode 100644 index 00000000..d01d0f76 --- /dev/null +++ b/app/Http/Middleware/EncryptCookies.php @@ -0,0 +1,19 @@ + $value){ - $headers[strtolower($name)] = $value; - } - } else { - // @codeCoverageIgnoreEnd - foreach ($_SERVER as $name => $value) { - if (substr($name, 0, 5) == 'HTTP_') { - $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))); - $headers[strtolower($name)] = $value; - } - } - - foreach(Request::header() as $name => $value){ - if(!array_key_exists($name,$headers)) - $headers[strtolower($name)] = $value[0]; - } - } - return $headers; - } +final class OAuth2BearerAccessTokenRequestValidator +{ /** - * @var IApiEndpointService + * @var IResourceServerContext */ - private $api_endpoint_service; + private $context; + + /** + * @var array + */ + private $headers; + + /** + * @var IApiEndpointRepository + */ + private $endpoint_repository; + /** * @var ITokenService */ private $token_service; + + /** + * @var IClientRepository + */ + private $client_repository; + /** * @var ILogService */ @@ -66,124 +78,111 @@ final class OAuth2BearerAccessTokenRequestValidator { * @var ICheckPointService */ private $checkpoint_service; - /** - * @var IResourceServerContext - */ - private $resource_server_context; - /** - * @var array - */ - private $headers; - /** - * @var IClientService - */ - private $client_service; /** - * @param IResourceServerContext $resource_server_context - * @param IApiEndpointService $api_endpoint_service + * OAuth2BearerAccessTokenRequestValidator constructor. + * @param IResourceServerContext $context + * @param IApiEndpointRepository $endpoint_repository * @param ITokenService $token_service + * @param IClientRepository $client_repository * @param ILogService $log_service * @param ICheckPointService $checkpoint_service - * @param IClientService $client_service */ - public function __construct - ( - IResourceServerContext $resource_server_context, - IApiEndpointService $api_endpoint_service, + public function __construct( + IResourceServerContext $context, + IApiEndpointRepository $endpoint_repository, ITokenService $token_service, + IClientRepository $client_repository, ILogService $log_service, - ICheckPointService $checkpoint_service, - IClientService $client_service - ) - { - $this->api_endpoint_service = $api_endpoint_service; - $this->token_service = $token_service; - $this->log_service = $log_service; - $this->checkpoint_service = $checkpoint_service; - $this->resource_server_context = $resource_server_context; - $this->headers = $this->getHeaders(); - $this->client_service = $client_service; + ICheckPointService $checkpoint_service + ) { + $this->context = $context; + $this->headers = $this->getHeaders(); + $this->endpoint_repository = $endpoint_repository; + $this->token_service = $token_service; + $this->client_repository = $client_repository; + $this->log_service = $log_service; + $this->checkpoint_service = $checkpoint_service; } /** - * @param $route - * @param $request + * @param \Illuminate\Http\Request $request + * @param Closure $next + * @return OAuth2WWWAuthenticateErrorResponse */ - public function filter($route, $request) + public function handle($request, Closure $next) { - $url = $route->getPath(); + $url = $request->getRequestUri(); + $method = $request->getMethod(); + $realm = $request->getHost(); - if(strpos($url, '/') != 0) - { - $url = '/'.$url; - } - $method = $request->getMethod(); - $realm = $request->getHost(); - // http://tools.ietf.org/id/draft-abarth-origin-03.html - $origin = $request->headers->has('Origin') ? $request->headers->get('Origin') : null; + try { + $route_path = Route::getCurrentRoute()->getPath(); + if (strpos($route_path, '/') != 0) + $route_path = '/' . $route_path; - try - { - $endpoint = $this->api_endpoint_service->getApiEndpointByUrlAndMethod($url, $method); - - //api endpoint must be registered on db and active - if(is_null($endpoint) || !$endpoint->isActive()) - { - throw new OAuth2ResourceServerException - ( + if (!$route_path) { + throw new OAuth2ResourceServerException( 400, OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest, - sprintf - ( - 'API endpoint does not exits! (%s:%s)', - $url, - $method - ) + sprintf('API endpoint does not exits! (%s:%s)', $url, $method) ); } - //check first http basic auth header - $auth_header = isset($this->headers['authorization'])?$this->headers['authorization']:null; + Log::debug($request->headers->__toString()); + // http://tools.ietf.org/id/draft-abarth-origin-03.html + $origin = $request->headers->has('Origin') ? $request->headers->get('Origin') : null; + if (!empty($origin)) { + $nm = new Normalizer($origin); + $origin = $nm->normalize(); + } - if(!is_null($auth_header) && !empty($auth_header)) + //check first http basic auth header + $auth_header = isset($this->headers['authorization']) ? $this->headers['authorization'] : null; + if (!is_null($auth_header) && !empty($auth_header)) { $access_token_value = BearerAccessTokenAuthorizationHeaderParser::getInstance()->parse($auth_header); - else - { + } else { // http://tools.ietf.org/html/rfc6750#section-2- 2 // if access token is not on authorization header check on POST/GET params $access_token_value = Input::get(OAuth2Protocol::OAuth2Protocol_AccessToken, ''); } - if(is_null($access_token_value) || empty($access_token_value)) - { + if (is_null($access_token_value) || empty($access_token_value)) { //if access token value is not set, then error - throw new OAuth2ResourceServerException - ( + throw new OAuth2ResourceServerException( 400, OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest, 'missing access token' ); } - // get access token from service - $access_token = $this->token_service->getAccessToken($access_token_value); - if(is_null($access_token)) - throw new ExpiredAccessTokenException(sprintf('Access token %s is expired!', $access_token_value)); - //check token audience - $audience = explode(' ', $access_token->getAudience()); + $endpoint = $this->endpoint_repository->getApiEndpointByUrlAndMethod($route_path, $method); - if((!in_array($realm , $audience))) - throw new OAuth2ResourceServerException - ( - 401, - OAuth2Protocol::OAuth2Protocol_Error_InvalidToken, - sprintf('access token audience does not match - current_realm %s - access token audience %s',$realm, $access_token->getAudience()) + //api endpoint must be registered on db and active + if (is_null($endpoint) || !$endpoint->isActive()) { + throw new OAuth2ResourceServerException( + 400, + OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest, + sprintf('API endpoint does not exits! (%s:%s)', $route_path, $method) ); + } + + $access_token = $this->token_service->getAccessToken($access_token_value); + //check lifetime + if (is_null($access_token)) { + throw new InvalidGrantTypeException(OAuth2Protocol::OAuth2Protocol_Error_InvalidToken); + } + Log::debug(sprintf("token lifetime %s", $access_token->getRemainingLifetime())); + //check token audience + Log::debug('checking token audience ...'); + $audience = explode(' ', $access_token->getAudience()); + if ((!in_array($realm, $audience))) { + throw new InvalidGrantTypeException(OAuth2Protocol::OAuth2Protocol_Error_InvalidToken); + } //check client existence $client_id = $access_token->getClientId(); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); if(is_null($client)) throw new OAuth2ResourceServerException @@ -192,7 +191,6 @@ final class OAuth2BearerAccessTokenRequestValidator { OAuth2Protocol::OAuth2Protocol_Error_InvalidRequest, 'invalid client' ); - //if js client , then check if the origin is allowed .... if($client->getApplicationType() == IClient::ApplicationType_JS_Client) { @@ -205,49 +203,51 @@ final class OAuth2BearerAccessTokenRequestValidator { ); } //check scopes - $endpoint_scopes = explode(' ',$endpoint->getScope()); - $token_scopes = explode(' ',$access_token->getScope()); + Log::debug('checking token scopes ...'); + $endpoint_scopes = explode(' ', $endpoint->getScope()); + $token_scopes = explode(' ', $access_token->getScope()); //check token available scopes vs. endpoint scopes - if (count(array_intersect($endpoint_scopes, $token_scopes)) == 0) - { - $this->log_service->error_msg - ( - sprintf - ( + if (count(array_intersect($endpoint_scopes, $token_scopes)) == 0) { + Log::warning( + sprintf( 'access token scopes (%s) does not allow to access to api url %s , needed scopes %s', $access_token->getScope(), $url, - implode(' OR ',$endpoint_scopes) + implode(' OR ', $endpoint_scopes) ) ); - throw new OAuth2ResourceServerException - ( + throw new OAuth2ResourceServerException( 403, OAuth2Protocol::OAuth2Protocol_Error_InsufficientScope, 'the request requires higher privileges than provided by the access token', - implode(' ',$endpoint_scopes) + implode(' ', $endpoint_scopes) ); } - + Log::debug('setting resource server context ...'); + //set context for api and continue processing $context = array ( - 'access_token' => $access_token_value, - 'expires_in' => $access_token->getRemainingLifetime(), - 'client_id' => $client_id, - 'scope' => $access_token->getScope() + 'access_token' => $access_token_value, + 'expires_in' => $access_token->getRemainingLifetime(), + 'client_id' => $client_id, + 'scope' => $access_token->getScope(), + 'application_type' => $client->getApplicationType() ); - if(!is_null($access_token->getUserId())) - $context['user_id'] = $access_token->getUserId(); + if (!is_null($access_token->getUserId())) + { + $context['user_id'] = $access_token->getUserId(); + //$context['user_external_id'] = $access_token->getUserExternalId(); + } - $this->resource_server_context->setAuthorizationContext($context); + $this->context->setAuthorizationContext($context); } catch(OAuth2ResourceServerException $ex1) { - $this->log_service->error($ex1); + $this->log_service->warning($ex1); $this->checkpoint_service->trackException($ex1); $response = new OAuth2WWWAuthenticateErrorResponse($realm, $ex1->getError(), @@ -261,7 +261,7 @@ final class OAuth2BearerAccessTokenRequestValidator { } catch(InvalidGrantTypeException $ex2) { - $this->log_service->error($ex2); + $this->log_service->warning($ex2); $this->checkpoint_service->trackException($ex2); $response = new OAuth2WWWAuthenticateErrorResponse($realm, OAuth2Protocol::OAuth2Protocol_Error_InvalidToken, @@ -275,7 +275,7 @@ final class OAuth2BearerAccessTokenRequestValidator { } catch(ExpiredAccessTokenException $ex3) { - $this->log_service->error($ex3); + $this->log_service->warning($ex3); $this->checkpoint_service->trackException($ex3); $response = new OAuth2WWWAuthenticateErrorResponse($realm, OAuth2Protocol::OAuth2Protocol_Error_InvalidToken, @@ -289,7 +289,7 @@ final class OAuth2BearerAccessTokenRequestValidator { } catch(RevokedAccessTokenException $ex4) { - $this->log_service->error($ex4); + $this->log_service->warning($ex4); $this->checkpoint_service->trackException($ex4); $response = new OAuth2WWWAuthenticateErrorResponse($realm, OAuth2Protocol::OAuth2Protocol_Error_InvalidToken, @@ -315,5 +315,36 @@ final class OAuth2BearerAccessTokenRequestValidator { $http_response->header('WWW-Authenticate',$response->getWWWAuthenticateHeaderValue()); return $http_response; } + $response = $next($request); + + return $response; + } + + /** + * @return array + */ + protected function getHeaders() + { + $headers = array(); + if (function_exists('getallheaders')) { + foreach (getallheaders() as $name => $value) { + $headers[strtolower($name)] = $value; + } + } else { + // @codeCoverageIgnoreEnd + foreach ($_SERVER as $name => $value) { + if (substr($name, 0, 5) == 'HTTP_') { + $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))); + $headers[strtolower($name)] = $value; + } + } + foreach (Request::header() as $name => $value) { + if (!array_key_exists($name, $headers)) { + $headers[strtolower($name)] = $value[0]; + } + } + } + + return $headers; } } \ No newline at end of file diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php new file mode 100644 index 00000000..1b129f19 --- /dev/null +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -0,0 +1,40 @@ +check()) { + return redirect('/'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/SSLMiddleware.php b/app/Http/Middleware/SSLMiddleware.php new file mode 100644 index 00000000..d8513aa8 --- /dev/null +++ b/app/Http/Middleware/SSLMiddleware.php @@ -0,0 +1,33 @@ +headers->set('X-content-type-options','nosniff'); + $response->headers->set('X-xss-protection','1; mode=block'); + //cache + $response->headers->set('pragma','no-cache'); + $response->headers->set('Expires','-1'); + $response->headers->set('cache-control','no-store, must-revalidate, no-cache'); + return $response; + } +} \ No newline at end of file diff --git a/app/Http/Middleware/SingleAccessPoint.php b/app/Http/Middleware/SingleAccessPoint.php new file mode 100644 index 00000000..5228d9c3 --- /dev/null +++ b/app/Http/Middleware/SingleAccessPoint.php @@ -0,0 +1,46 @@ +getService(UtilsServiceCatalog::CheckPointService); + if ($checkpoint_service instanceof ICheckPointService && !$checkpoint_service->check()) { + return Response::view('errors.404', array(), 404); + } + } catch (Exception $ex) { + Log::error($ex); + return Response::view('errors.404', array(), 404); + } + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php new file mode 100644 index 00000000..a2c35414 --- /dev/null +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -0,0 +1,17 @@ + 'App\Http\Controllers', 'middleware' => 'web' ], function() { + + // openid endpoints + Route::group(array('middleware' => ['ssl']), function () { + + Route::get('/', "HomeController@index"); + + // OpenId endpoints + + Route::group(['namespace' => 'OpenId' ], function() { + + Route::get('/discovery', "DiscoveryController@idp"); + Route::get("/discovery/users/{identifier}","DiscoveryController@user")->where(array('identifier' => '[\d\w\.\#]+')); + //op endpoint url + Route::post('/accounts/openid2', 'OpenIdProviderController@endpoint'); + Route::get('/accounts/openid2', 'OpenIdProviderController@endpoint'); + }); + + /* + * If the Claimed Identifier was not previously discovered by the Relying Party + * (the "openid.identity" in the request was "http://specs.openid.net/auth/2.0/identifier_select" + * or a different Identifier, or if the OP is sending an unsolicited positive assertion), + * the Relying Party MUST perform discovery on the Claimed Identifier in + * the response to make sure that the OP is authorized to make assertions about the Claimed Identifier. + */ + Route::get("/{identifier}", "UserController@getIdentity"); + //user interaction + Route::get('/accounts/user/login', "UserController@getLogin"); + Route::post('/accounts/user/login', ['middleware' => 'csrf', 'uses' => 'UserController@postLogin']); + Route::get('/accounts/user/login/cancel', "UserController@cancelLogin"); + }); + + //oauth2 endpoints + + Route::group(['namespace'=> 'OAuth2', 'middleware' => ['ssl']], function () { + Route::get('/.well-known/openid-configuration', "OAuth2ProviderController@discovery"); + }); + + Route::group(['namespace' => 'OAuth2' , 'prefix' => 'oauth2', 'middleware' => ['ssl']], function () { + Route::get('/check-session', "OAuth2ProviderController@checkSessionIFrame"); + Route::get('/end-session', "OAuth2ProviderController@endSession"); + Route::get('/end-session/cancel', "OAuth2ProviderController@cancelLogout"); + Route::post('/end-session', "OAuth2ProviderController@endSession"); + + //authorization endpoint + Route::any('/auth', "OAuth2ProviderController@auth"); + // OIDC + // certificates + Route::get('/certs', "OAuth2ProviderController@certs"); + // discovery document + Route::get('/.well-known/openid-configuration', "OAuth2ProviderController@discovery"); + //token endpoint + Route::group(array('prefix' => 'token'), function () { + Route::post('/', "OAuth2ProviderController@token"); + Route::post('/revoke', "OAuth2ProviderController@revoke"); + Route::post('/introspection', "OAuth2ProviderController@introspection"); + }); + }); + + Route::group(array('middleware' => ['ssl', 'auth']), function () { + Route::get('/accounts/user/consent', "UserController@getConsent"); + Route::post('/accounts/user/consent', ['middleware' => 'csrf', 'uses' => 'UserController@postConsent']); + Route::any("/accounts/user/logout", "UserController@logout"); + Route::any("/accounts/user/profile", "UserController@getProfile"); + Route::any("/accounts/user/profile/trusted_site/delete/{id}", "UserController@deleteTrustedSite"); + Route::post('/accounts/user/profile/update', 'UserController@postUserProfileOptions'); + }); + + Route::group(['prefix' => 'admin', 'middleware' => ['ssl', 'auth']], function () { + //client admin UI + Route::get('clients/edit/{id}', ['middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'AdminController@editRegisteredClient']); + Route::get('clients', 'AdminController@listOAuth2Clients'); + Route::get('/grants', 'AdminController@editIssuedGrants'); + + //oauth2 server admin UI + Route::group(array('middleware' => ['oauth2.currentuser.serveradmin']), function () { + Route::get('/api-scope-groups', 'AdminController@listApiScopeGroups'); + Route::get('/api-scope-groups/{id}', 'AdminController@editApiScopeGroup'); + Route::get('/resource-servers', 'AdminController@listResourceServers'); + Route::get('/resource-server/{id}', 'AdminController@editResourceServer'); + Route::get('/api/{id}', 'AdminController@editApi'); + Route::get('/scope/{id}', 'AdminController@editScope'); + Route::get('/endpoint/{id}', 'AdminController@editEndpoint'); + Route::get('/locked-clients', 'AdminController@listLockedClients'); + // server private keys + Route::get('/private-keys', 'AdminController@listServerPrivateKeys'); + }); + + Route::group(array('middleware' => ['openstackid.currentuser.serveradmin']), function () { + Route::get('/locked-users', 'AdminController@listLockedUsers'); + Route::get('/server-config', 'AdminController@listServerConfig'); + Route::post('/server-config', 'AdminController@saveServerConfig'); + Route::get('/banned-ips', 'AdminController@listBannedIPs'); + }); + }); + + //Admin Backend API + + Route::group([ + 'namespace' => 'Api', + 'prefix' => 'admin/api/v1', + 'middleware' => ['ssl', 'auth']], function () { + + Route::group(array('prefix' => 'users'), function () { + Route::delete('/{id}/locked', array('middleware' => ['openstackid.currentuser.serveradmin.json'], 'uses' => 'UserApiController@unlock')); + Route::delete('/{id}/token/{value}', array('middleware' => ['currentuser.checkroute'], 'uses' => 'UserApiController@revokeToken')); + Route::get('/fetch', array('uses' => "UserApiController@fetch")); + }); + + Route::group(array('prefix' => 'banned-ips', 'middleware' => ['openstackid.currentuser.serveradmin.json']), function () { + Route::get('/{id}', "ApiBannedIPController@get"); + Route::get('/', "ApiBannedIPController@getByPage"); + Route::delete('/{id?}', "ApiBannedIPController@delete"); + }); + + //client api + Route::group(array('prefix' => 'clients'), function () { + + // public keys + Route::post('/{id}/public_keys', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientPublicKeyApiController@create')); + Route::get('/{id}/public_keys', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientPublicKeyApiController@getByPage')); + Route::delete('/{id}/public_keys/{public_key_id}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientPublicKeyApiController@delete')); + Route::put('/{id}/public_keys/{public_key_id}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientPublicKeyApiController@update')); + + Route::post('/', array('middleware' => ['currentuser.checkroute'], 'uses' => 'ClientApiController@create')); + Route::put('/', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@update')); + Route::get('/{id}', "ClientApiController@get"); + Route::get('/', array('middleware' => ['currentuser.checkroute'], 'uses' => 'ClientApiController@getByPage')); + Route::delete('/{id}', array('middleware' => ['oauth2.currentuser.owns.client'], 'uses' => 'ClientApiController@delete')); + //allowed redirect uris endpoints + Route::get('/{id}/uris', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@getRegisteredUris')); + Route::post('/{id}/uris', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@addAllowedRedirectUri')); + Route::delete('/{id}/uris/{uri_id}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@deleteClientAllowedUri')); + + //allowedApiResourceServerControllert('/{id}/origins', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@geAllowedOrigins')); + Route::post('/{id}/origins', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@addAllowedOrigin')); + Route::delete('/{id}/origins/{origin_id}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@deleteClientAllowedOrigin')); + Route::delete('/{id}/lock', array('middleware' => ['openstackid.currentuser.serveradmin.json'], 'uses' => 'ClientApiController@unlock')); + Route::put('/{id}/secret', array('middleware' => ['oauth2.currentuser.owns.client'], 'uses' => 'ClientApiController@regenerateClientSecret')); + Route::put('/{id}/use-refresh-token', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@setRefreshTokenClient')); + Route::put('/{id}/rotate-refresh-token', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@setRotateRefreshTokenPolicy')); + Route::get('/{id}/access-token', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@getAccessTokens')); + Route::get('/{id}/refresh-token', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@getRefreshTokens')); + Route::get('/me/access-tokens', array('middleware' => [], 'uses' => 'ClientApiController@getAccessTokensByCurrentUser')); + Route::get('/me/refresh-tokens', array('middleware' => [], 'uses' => 'ClientApiController@getRefreshTokensByCurrentUser')); + Route::delete('/{id}/token/{value}/{hint}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@revokeToken')); + Route::put('/{id}/scopes/{scope_id}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@addAllowedScope')); + Route::delete('/{id}/scopes/{scope_id}', array('middleware' => ['oauth2.currentuser.allow.client.edition'], 'uses' => 'ClientApiController@removeAllowedScope')); + Route::put('/{id}/active', array('middleware' => ['oauth2.currentuser.owns.client'], 'uses' => 'ClientApiController@activate')); + Route::delete('/{id}/active', array('middleware' => ['oauth2.currentuser.owns.client'], 'uses' => 'ClientApiController@deactivate')); + + }); + + // resource servers + Route::group(array('prefix' => 'resource-servers', 'middleware' => ['oauth2.currentuser.serveradmin.json']), function () { + Route::get('/{id}', "ApiResourceServerController@get"); + Route::get('/', "ApiResourceServerController@getByPage"); + Route::post('/', "ApiResourceServerController@create"); + Route::delete('/{id}', "ApiResourceServerController@delete"); + Route::put('/', "ApiResourceServerController@update"); + Route::put('/{id}/client-secret', "ApiResourceServerController@regenerateClientSecret"); + Route::put('/{id}/active', "ApiResourceServerController@activate"); + Route::delete('/{id}/active', "ApiResourceServerController@deactivate"); + }); + + // api scope groups + Route::group(array('prefix' => 'api-scope-groups', 'middleware' => ['oauth2.currentuser.serveradmin.json']), function () { + Route::get('/{id}', "ApiScopeGroupController@get"); + Route::get('/', "ApiScopeGroupController@getByPage"); + Route::put('/', "ApiScopeGroupController@update"); + Route::post('/', "ApiScopeGroupController@create"); + Route::delete('/{id}', "ApiScopeGroupController@delete"); + Route::put('/{id}/active', "ApiScopeGroupController@activate"); + Route::delete('/{id}/active', "ApiScopeGroupController@deactivate"); + }); + + // apis + Route::group(array('prefix' => 'apis', 'middleware' => ['oauth2.currentuser.serveradmin.json']), function () { + Route::get('/{id}', "ApiController@get"); + Route::get('/', "ApiController@getByPage"); + Route::post('/', "ApiController@create"); + Route::delete('/{id}', "ApiController@delete"); + Route::put('/', "ApiController@update"); + Route::put('/{id}/active', "ApiController@activate"); + Route::delete('/{id}/active', "ApiController@deactivate"); + }); + + // scopes + Route::group(array('prefix' => 'scopes', 'middleware' => ['oauth2.currentuser.serveradmin.json']), function () { + Route::get('/{id}', "ApiScopeController@get"); + Route::get('/', "ApiScopeController@getByPage"); + Route::post('/', "ApiScopeController@create"); + Route::delete('/{id}', "ApiScopeController@delete"); + Route::put('/', "ApiScopeController@update"); + Route::put('/{id}/active', "ApiScopeController@activate"); + Route::delete('/{id}/active', "ApiScopeController@deactivate"); + }); + + // endpoints + Route::group(array('prefix' => 'endpoints', 'middleware' => ['oauth2.currentuser.serveradmin.json']), function () { + Route::get('/{id}', "ApiEndpointController@get"); + Route::get('/', "ApiEndpointController@getByPage"); + Route::post('/', "ApiEndpointController@create"); + Route::delete('/{id}', "ApiEndpointController@delete"); + Route::put('/', "ApiEndpointController@update"); + Route::put('/{id}/scope/{scope_id}', "ApiEndpointController@addRequiredScope"); + Route::delete('/{id}/scope/{scope_id}', "ApiEndpointController@removeRequiredScope"); + Route::put('/{id}/active', "ApiEndpointController@activate"); + Route::delete('/{id}/active', "ApiEndpointController@deactivate"); + }); + + // private keys + Route::group(array('prefix' => 'private-keys', 'middleware' => ['oauth2.currentuser.serveradmin.json']), function () { + Route::get('/', "ServerPrivateKeyApiController@getByPage"); + Route::post('/', "ServerPrivateKeyApiController@create"); + Route::delete('/{id}', "ServerPrivateKeyApiController@delete"); + Route::put('/{id}', "ServerPrivateKeyApiController@update"); + }); + + }); +}); + +//OAuth2 Protected API +Route::group( + [ + 'namespace' => 'App\Http\Controllers\Api\OAuth2', + 'prefix' => 'api/v1', + 'middleware' => ['api'] + ], function () { + + Route::group(array('prefix' => 'users'), function () { + Route::get('/me', 'OAuth2UserApiController@me'); + Route::get('/info', 'OAuth2UserApiController@userInfo'); + Route::post('/info', 'OAuth2UserApiController@userInfo'); + }); +}); \ No newline at end of file diff --git a/app/Jobs/Job.php b/app/Jobs/Job.php new file mode 100644 index 00000000..55ece29a --- /dev/null +++ b/app/Jobs/Job.php @@ -0,0 +1,21 @@ +sql; + $bindings = $event->bindings; + + // Format binding data for sql insertion + foreach ($bindings as $i => $binding) { + if ($binding instanceof DateTime) { + $bindings[$i] = $binding->format('\'Y-m-d H:i:s\''); + } else { + if (is_string($binding)) { + $bindings[$i] = "'$binding'"; + } + } + } + + $time = $event->time; + $connection = $event->connectionName; + $data = compact('bindings', 'time', 'connection'); + // Insert bindings into query + $query = str_replace(array('%', '?'), array('%%', '%s'), $query); + $query = vsprintf($query, $bindings); + Log::info($query, $data); + + //trace + + /*$trace = ''; + $entries = debug_backtrace(); + unset($entries[0]); + foreach($entries as $entry){ + if(!isset($entry['file']) || !isset($entry['line'])) continue; + $trace .= $entry['file'].' '.$entry['line'].PHP_EOL; + } + Log::debug($trace);*/ + + } + } +} diff --git a/app/Models/BannedIP.php b/app/Models/BannedIP.php new file mode 100644 index 00000000..f1982423 --- /dev/null +++ b/app/Models/BannedIP.php @@ -0,0 +1,27 @@ +belongsTo('Auth\User'); + } +} \ No newline at end of file diff --git a/app/Models/Group.php b/app/Models/Group.php new file mode 100644 index 00000000..38663f90 --- /dev/null +++ b/app/Models/Group.php @@ -0,0 +1,23 @@ +Salt, $this->PasswordEncryption); @@ -26,8 +40,7 @@ class Member extends BaseModelEloquent public function groups() { - - return $this->belongsToMany('Group', 'Group_Members', 'MemberID', 'GroupID'); + return $this->belongsToMany('Models\Group', 'Group_Members', 'MemberID', 'GroupID'); } /** @@ -38,6 +51,9 @@ class Member extends BaseModelEloquent return $this->isEmailVerified() && $this->isActive(); } + /** + * @return bool + */ public function isActive(){ $attr = $this->getAttributes(); if(isset($attr['Active'])) diff --git a/app/Models/MemberPhoto.php b/app/Models/MemberPhoto.php new file mode 100644 index 00000000..5d0341cd --- /dev/null +++ b/app/Models/MemberPhoto.php @@ -0,0 +1,22 @@ +belongsTo('Models\OAuth2\RefreshToken'); + } + + /** + * @return RefreshToken + */ + public function getRefreshToken(){ + return Cache::remember + ( + 'refresh_token_'.$this->refresh_token_id, + Config::get("cache_regions.region_refresh_token_lifetime", 1140), + function() { + return $this->refresh_token()->first(); + } + ); + } + + public function client(){ + return $this->belongsTo('Models\OAuth2\Client'); + } + + /** + * @return IClient + */ + public function getClient(){ + return Cache::remember + ( + 'client_'.$this->client_id, + Config::get("cache_regions.region_clients_lifetime", 1140), + function() { + return $this->client()->first(); + } + ); + } + + public function user(){ + return $this->belongsTo('Auth\User'); + } + + /** + * @return User + */ + public function getUser(){ + return Cache::remember + ( + 'user_'.$this->user_id, + Config::get("cache_regions.region_users_lifetime", 1140), + function() { + return $this->user()->first(); + } + ); + } + + /** + * @return bool + */ + public function isVoid(){ + //check lifetime... + $created_at = $this->created_at; + $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); + $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); + return ($now > $created_at); + } + + /** + * @return mixed + */ + public function getFriendlyScopes(){ + return $this->friendly_scopes; + } + + /** + * @param $friendly_scopes + */ + public function setFriendlyScopes($friendly_scopes){ + $this->friendly_scopes = $friendly_scopes; + } + + /** + * @return int + */ + public function getRemainingLifetime() + { + //check is refresh token is stills alive... (ZERO is infinite lifetime) + if (intval($this->lifetime) == 0) return 0; + $created_at = new DateTime($this->created_at, new DateTimeZone("UTC")); + $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); + $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); + //check validity... + if ($now > $created_at) + return -1; + $seconds = abs($created_at->getTimestamp() - $now->getTimestamp());; + return $seconds; + } +} \ No newline at end of file diff --git a/app/models/oauth2/Api.php b/app/Models/OAuth2/Api.php similarity index 62% rename from app/models/oauth2/Api.php rename to app/Models/OAuth2/Api.php index 1f1db51c..1335f984 100644 --- a/app/models/oauth2/Api.php +++ b/app/Models/OAuth2/Api.php @@ -1,8 +1,25 @@ -hasMany('ApiScope', 'api_id'); + return $this->hasMany('Models\OAuth2\ApiScope', 'api_id'); } public function resource_server() { - return $this->belongsTo('ResourceServer'); + return $this->belongsTo('Models\OAuth2\ResourceServer'); } public function endpoints() { - return $this->hasMany('ApiEndpoint', 'api_id'); + return $this->hasMany('Models\OAuth2\ApiEndpoint', 'api_id'); } /** @@ -50,7 +67,14 @@ class Api extends BaseModelEloquent implements IApi */ public function getResourceServer() { - return $this->resource_server()->first(); + return Cache::remember + ( + 'resource_server_'.$this->resource_server_id, + Config::get("cache_regions.region_resource_server_lifetime", 60), + function() { + return $this->resource_server()->first(); + } + ); } public function getName() @@ -64,7 +88,6 @@ class Api extends BaseModelEloquent implements IApi return $url; } - public function getDescription() { return $this->description; diff --git a/app/models/oauth2/ApiEndpoint.php b/app/Models/OAuth2/ApiEndpoint.php similarity index 62% rename from app/models/oauth2/ApiEndpoint.php rename to app/Models/OAuth2/ApiEndpoint.php index 782dde0a..0dbe6416 100644 --- a/app/models/oauth2/ApiEndpoint.php +++ b/app/Models/OAuth2/ApiEndpoint.php @@ -1,9 +1,23 @@ -belongsTo('Api'); + return $this->belongsTo('Models\OAuth2\Api'); } public function getRoute() @@ -37,7 +51,7 @@ class ApiEndpoint extends BaseModelEloquent implements IApiEndpoint{ public function scopes() { - return $this->belongsToMany('ApiScope','oauth2_api_endpoint_api_scope','api_endpoint_id','scope_id'); + return $this->belongsToMany('Models\OAuth2\ApiScope','oauth2_api_endpoint_api_scope','api_endpoint_id','scope_id'); } public function getHttpMethod(){ @@ -100,4 +114,13 @@ class ApiEndpoint extends BaseModelEloquent implements IApiEndpoint{ { return $this->allow_cors; } + + /** + * @return bool + */ + public function supportCredentials() + { + // TODO: Implement supportCredentials() method. + return false; + } } \ No newline at end of file diff --git a/app/models/oauth2/ApiScope.php b/app/Models/OAuth2/ApiScope.php similarity index 53% rename from app/models/oauth2/ApiScope.php rename to app/Models/OAuth2/ApiScope.php index 5054ef66..e9f9b574 100644 --- a/app/models/oauth2/ApiScope.php +++ b/app/Models/OAuth2/ApiScope.php @@ -1,17 +1,32 @@ -attributes['active']; @@ -71,33 +86,39 @@ class ApiScope extends BaseModelEloquent implements IApiScope public function api() { - return $this->belongsTo('Api'); + return $this->belongsTo('Models\OAuth2\Api'); + } + + /** + * @return IApi + */ + public function getApi(){ + return Cache::remember + ( + 'api_'.$this->api_id, + Config::get("cache_regions.region_api_lifetime", 1140), + function() { + return $this->api()->first(); + } + ); } public function getApiName() { - $api = $this->api()->first(); + $api = $this->getApi(); return !is_null($api)?$api->name:''; } public function getApiDescription(){ - $api = $this->api()->first(); + $api = $this->getApi(); return !is_null($api)? $api->description:''; } public function getApiLogo(){ - $api = $this->api()->first(); + $api = $this->getApi(); return !is_null($api) ? $api->getLogo():asset('/assets/apis/server.png'); } - /** - * @return \oauth2\models\IApi - */ - public function getApi() - { - return $this->api(); - } - /** * @return bool */ diff --git a/app/models/oauth2/ApiScopeGroup.php b/app/Models/OAuth2/ApiScopeGroup.php similarity index 77% rename from app/models/oauth2/ApiScopeGroup.php rename to app/Models/OAuth2/ApiScopeGroup.php index a42eec6d..0e809d87 100644 --- a/app/models/oauth2/ApiScopeGroup.php +++ b/app/Models/OAuth2/ApiScopeGroup.php @@ -1,12 +1,6 @@ -belongsToMany('ApiScope','oauth2_api_scope_group_scope','group_id','scope_id'); + return $this->belongsToMany('Models\OAuth2\ApiScope','oauth2_api_scope_group_scope','group_id','scope_id'); } public function users() { - return $this->belongsToMany('auth\User','oauth2_api_scope_group_users','group_id','user_id'); + return $this->belongsToMany('Auth\User','oauth2_api_scope_group_users','group_id','user_id'); } /** * @param IApiScope $scope + * @return $this */ public function addScope(IApiScope $scope) { @@ -44,6 +47,7 @@ class ApiScopeGroup extends BaseModelEloquent implements IEntity /** * @param IOAuth2User $user + * @return $this */ public function addUser(IOAuth2User $user) { @@ -53,6 +57,7 @@ class ApiScopeGroup extends BaseModelEloquent implements IEntity /** * @param IOAuth2User $scope + * @return $this */ public function removeScope(IOAuth2User $scope) { @@ -60,6 +65,9 @@ class ApiScopeGroup extends BaseModelEloquent implements IEntity return $this; } + /** + * @return $this + */ public function removeAllScopes() { $this->scopes()->detach(); @@ -68,6 +76,7 @@ class ApiScopeGroup extends BaseModelEloquent implements IEntity /** * @param IOAuth2User $user + * @return $this */ public function removeUser(IOAuth2User $user) { diff --git a/app/models/oauth2/AssymetricKey.php b/app/Models/OAuth2/AsymmetricKey.php similarity index 86% rename from app/models/oauth2/AssymetricKey.php rename to app/Models/OAuth2/AsymmetricKey.php index a31327e1..13c2330a 100644 --- a/app/models/oauth2/AssymetricKey.php +++ b/app/Models/OAuth2/AsymmetricKey.php @@ -1,7 +1,6 @@ -valid_from <= $now && $this->valid_to >= $now); } diff --git a/app/models/oauth2/Client.php b/app/Models/OAuth2/Client.php similarity index 82% rename from app/models/oauth2/Client.php rename to app/Models/OAuth2/Client.php index 5480712e..c1bd9baa 100644 --- a/app/models/oauth2/Client.php +++ b/app/Models/OAuth2/Client.php @@ -1,20 +1,37 @@ -hasMany('ClientPublicKey','oauth2_client_id','id'); + return $this->hasMany('Models\OAuth2\ClientPublicKey','oauth2_client_id','id'); } /** @@ -109,7 +126,7 @@ class Client extends BaseModelEloquent implements IClient */ public function admin_users() { - return $this->belongsToMany('auth\User','oauth2_client_admin_users','oauth2_client_id','user_id'); + return $this->belongsToMany('Auth\User','oauth2_client_admin_users','oauth2_client_id','user_id'); } /** @@ -140,32 +157,32 @@ class Client extends BaseModelEloquent implements IClient public function access_tokens() { - return $this->hasMany('AccessToken'); + return $this->hasMany('Models\OAuth2\AccessToken'); } public function refresh_tokens() { - return $this->hasMany('RefreshToken'); + return $this->hasMany('Models\OAuth2\RefreshToken'); } public function user() { - return $this->belongsTo('auth\User'); + return $this->belongsTo('Auth\User'); } public function edited_by() { - return $this->belongsTo('auth\User','edited_by_id'); + return $this->belongsTo('Auth\User','edited_by_id'); } public function resource_server() { - return $this->belongsTo('ResourceServer'); + return $this->belongsTo('Models\OAuth2\ResourceServer'); } public function scopes() { - return $this->belongsToMany('ApiScope','oauth2_client_api_scope','client_id','scope_id'); + return $this->belongsToMany('Models\OAuth2\ApiScope','oauth2_client_api_scope','client_id','scope_id'); } /** @@ -219,13 +236,14 @@ class Client extends BaseModelEloquent implements IClient public function isScopeAllowed($scope) { - $res = true; + $res = true; $desired_scopes = explode(" ",$scope); foreach($desired_scopes as $desired_scope){ //check if desired scope belongs to application given scopes - $db_scope = $this->scopes()->where('name', '=', $desired_scope)->where('active', '=', true)->first(); - $api = !is_null($db_scope)?$db_scope->api()->first():null; - $resource_server = !is_null($api) ? $api->resource_server()->first():null; + $db_scope = $this->getActiveScope($desired_scope); + $api = !is_null($db_scope) ? $db_scope->getApi() : null; + $resource_server = !is_null($api) ? $api->getResourceServer() : null; + if(is_null($db_scope) ||(!is_null($api) && !$api->active) || (!is_null($resource_server) && !$resource_server->active)){ $res = false; break; @@ -234,6 +252,21 @@ class Client extends BaseModelEloquent implements IClient return $res; } + /** + * @param string $name + * @return IApiScope + */ + public function getActiveScope($name){ + return Cache::remember + ( + 'api_scope_'.$this->id.'_'.$name, + Config::get("cache_regions.region_api_scope_lifetime", 1140), + function() use($name){ + return $this->scopes()->where('name', '=', $name)->where('active', '=', true)->first(); + } + ); + } + public function isUriAllowed($uri) { if(!filter_var($uri, FILTER_VALIDATE_URL)) return false; @@ -314,7 +347,13 @@ class Client extends BaseModelEloquent implements IClient public function getResourceServer() { - return $this->resource_server()->first(); + return Cache::remember + ( + 'resource_server_'.$this->resource_server_id, + Config::get("cache_regions.region_resource_server_lifetime", 60), + function() { + return $this->resource_server()->first(); + }); } public function getApplicationType() @@ -382,16 +421,16 @@ class Client extends BaseModelEloquent implements IClient } /** - * @return \DateTime + * @return DateTime */ public function getClientSecretExpiration() { $exp_date = $this->client_secret_expires_at; if(is_null($exp_date)) return null; - if($exp_date instanceof \DateTime) + if($exp_date instanceof DateTime) return $exp_date; - return new \DateTime($exp_date); + return new DateTime($exp_date); } /** @@ -399,7 +438,7 @@ class Client extends BaseModelEloquent implements IClient */ public function isClientSecretExpired() { - $now = new \DateTime(); + $now = new DateTime(); $exp_date = $this->getClientSecretExpiration(); if(is_null($exp_date)) return false; @@ -610,7 +649,8 @@ class Client extends BaseModelEloquent implements IClient } /** - * @param mixed $user + * @param $user + * @return $this */ public function addAdminUser($user) { @@ -619,7 +659,8 @@ class Client extends BaseModelEloquent implements IClient } /** - * @param mixed $user + * @param $user + * @return $this */ public function removeAdminUser($user) { @@ -627,6 +668,9 @@ class Client extends BaseModelEloquent implements IClient return $this; } + /** + * @return $this + */ public function removeAllAdminUsers(){ $this->admin_users()->detach(); return $this; @@ -657,6 +701,10 @@ class Client extends BaseModelEloquent implements IClient return intval($this->user_id) === intval($user->id); } + /** + * @param $user + * @return $this + */ public function setOwner($user) { $this->user()->associate($user); @@ -693,4 +741,28 @@ class Client extends BaseModelEloquent implements IClient $user = $this->user()->first(); return is_null($user)? 'N/A':$user->getEmail(); } + + /** + * @return bool + */ + public function useRefreshToken() + { + return (bool)$this->use_refresh_token; + } + + /** + * @return bool + */ + public function useRotateRefreshTokenPolicy() + { + return (bool)$this->rotate_refresh_token; + } + + /** + * @return AccessToken[] + */ + public function getValidAccessTokens() + { + return $this->access_tokens()->whereRaw(" DATE_ADD(created_at, INTERVAL lifetime second) >= UTC_TIMESTAMP() ")->get(); + } } \ No newline at end of file diff --git a/app/models/oauth2/ClientPublicKey.php b/app/Models/OAuth2/ClientPublicKey.php similarity index 63% rename from app/models/oauth2/ClientPublicKey.php rename to app/Models/OAuth2/ClientPublicKey.php index 219b90db..62582aa6 100644 --- a/app/models/oauth2/ClientPublicKey.php +++ b/app/Models/OAuth2/ClientPublicKey.php @@ -1,27 +1,25 @@ -belongsTo('Client'); + return $this->belongsTo('Models\OAuth2\Client'); } /** diff --git a/app/Models/OAuth2/OAuth2TrailException.php b/app/Models/OAuth2/OAuth2TrailException.php new file mode 100644 index 00000000..34a5651a --- /dev/null +++ b/app/Models/OAuth2/OAuth2TrailException.php @@ -0,0 +1,22 @@ +hasMany('Models\OAuth2\AccessToken'); + } + + public function client(){ + return $this->belongsTo('Models\OAuth2\Client'); + } + + /** + * @return IClient + */ + public function getClient(){ + return Cache::remember + ( + 'client_'.$this->client_id, + Config::get("cache_regions.region_clients_lifetime", 1140), + function() { + return $this->client()->first(); + } + ); + } + + public function user(){ + return $this->belongsTo('Auth\User'); + } + + /** + * @return User + */ + public function getUser(){ + return Cache::remember + ( + 'user_'.$this->user_id, + Config::get("cache_regions.region_users_lifetime", 1140), + function() { + return $this->user()->first(); + } + ); + } + + /** + * @return bool + */ + public function isVoid(){ + if(intval($this->lifetime) == 0) return false; + //check lifetime... + $created_at = $this->created_at; + $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); + $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); + return ($now > $created_at); + } + + /** + * @return int + */ + public function getRemainingLifetime() + { + //check is refresh token is stills alive... (ZERO is infinite lifetime) + if (intval($this->lifetime) == 0) return 0; + $created_at = new DateTime($this->created_at, new DateTimeZone("UTC")); + $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); + $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); + //check validity... + if ($now > $created_at) + return -1; + $seconds = abs($created_at->getTimestamp() - $now->getTimestamp());; + return $seconds; + } + + public function getFriendlyScopes(){ + return $this->friendly_scopes; + } + + public function setFriendlyScopes($friendly_scopes){ + $this->friendly_scopes = $friendly_scopes; + } + + public function setVoid(){ + $this->void = true; + } +} \ No newline at end of file diff --git a/app/models/oauth2/ResourceServer.php b/app/Models/OAuth2/ResourceServer.php similarity index 66% rename from app/models/oauth2/ResourceServer.php rename to app/Models/OAuth2/ResourceServer.php index fe7c19a0..f20299eb 100644 --- a/app/models/oauth2/ResourceServer.php +++ b/app/Models/OAuth2/ResourceServer.php @@ -1,10 +1,23 @@ -hasMany('Api', 'resource_server_id'); + return $this->hasMany('Models\OAuth2\Api', 'resource_server_id'); } public function client() { - return $this->hasOne('Client'); + return $this->hasOne('Models\OAuth2\Client'); } /** diff --git a/app/models/oauth2/ServerPrivateKey.php b/app/Models/OAuth2/ServerPrivateKey.php similarity index 71% rename from app/models/oauth2/ServerPrivateKey.php rename to app/Models/OAuth2/ServerPrivateKey.php index 65cde246..b1ef27d1 100644 --- a/app/models/oauth2/ServerPrivateKey.php +++ b/app/Models/OAuth2/ServerPrivateKey.php @@ -1,27 +1,28 @@ -kid = $kid; diff --git a/app/Models/OAuth2/UserConsent.php b/app/Models/OAuth2/UserConsent.php new file mode 100644 index 00000000..e840e291 --- /dev/null +++ b/app/Models/OAuth2/UserConsent.php @@ -0,0 +1,59 @@ +belongsTo('Auth\User'); + } + + public function client() + { + return $this->belongsTo('Models\OAuth2\Client'); + } + + /** + * @return string + */ + public function getScope() + { + return $this->scope; + } + + /** + * @return IClient + */ + public function getClient() + { + return $this->client()->first(); + } + + /** + * @return User + */ + public function getUser() + { + return $this->user()->first(); + } +} \ No newline at end of file diff --git a/app/models/openid/OpenIdAssociation.php b/app/Models/OpenId/OpenIdAssociation.php similarity index 66% rename from app/models/openid/OpenIdAssociation.php rename to app/Models/OpenId/OpenIdAssociation.php index 6d65517e..61bd3277 100644 --- a/app/models/openid/OpenIdAssociation.php +++ b/app/Models/OpenId/OpenIdAssociation.php @@ -1,16 +1,35 @@ -mac_function; @@ -21,6 +40,9 @@ class OpenIdAssociation extends Eloquent implements IAssociation // TODO: Implement setMacFunction() method. } + /** + * @return string + */ public function getSecret() { return $this->secret; diff --git a/app/Models/OpenId/OpenIdTrustedSite.php b/app/Models/OpenId/OpenIdTrustedSite.php new file mode 100644 index 00000000..498faf5a --- /dev/null +++ b/app/Models/OpenId/OpenIdTrustedSite.php @@ -0,0 +1,71 @@ +realm; + } + + public function getUITrustedData() + { + $data = $this->getData(); + $str = ''; + foreach ($data as $val) { + $str .= $val . ', '; + } + return trim($str, ', '); + } + + public function getData() + { + $res = is_null($this->data)?'[]':$this->data; + return json_decode($res); + } + + public function getUser() + { + return $this->user(); + } + + public function user() + { + return $this->belongsTo('Auth\User'); + } + + /** + * @return string + */ + public function getAuthorizationPolicy() + { + return $this->policy; + } + +} \ No newline at end of file diff --git a/app/Models/OpenId/ServerExtension.php b/app/Models/OpenId/ServerExtension.php new file mode 100644 index 00000000..b24bc6c8 --- /dev/null +++ b/app/Models/OpenId/ServerExtension.php @@ -0,0 +1,24 @@ +belongsTo('Auth\User'); } - } \ No newline at end of file diff --git a/app/Models/UserExceptionTrail.php b/app/Models/UserExceptionTrail.php new file mode 100644 index 00000000..49350a59 --- /dev/null +++ b/app/Models/UserExceptionTrail.php @@ -0,0 +1,21 @@ +getHandlers() as $handler) { + $handler->setLevel(Config::get('log.level', 'error')); + } + + //set email log + $to = Config::get('log.to_email'); + $from = Config::get('log.from_email'); + + if (!empty($to) && !empty($from)) { + + $subject = 'openstackid error'; + $mono_log = Log::getMonolog(); + $handler = new NativeMailerHandler($to, $subject, $from); + + $handler->setLevel(Config::get('log.email_level', 'error')); + $mono_log->pushHandler($handler); + } + + + Validator::resolver(function($translator, $data, $rules, $messages) + { + return new CustomValidator($translator, $data, $rules, $messages); + }); + } + + /** + * Register any application services. + * + * @return void + */ + public function register() + { + // + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php new file mode 100644 index 00000000..140fb6c0 --- /dev/null +++ b/app/Providers/AuthServiceProvider.php @@ -0,0 +1,43 @@ + 'App\Policies\ModelPolicy', + ]; + + /** + * Register any application authentication / authorization services. + * + * @param \Illuminate\Contracts\Auth\Access\Gate $gate + * @return void + */ + public function boot(GateContract $gate) + { + $this->registerPolicies($gate); + + // + } +} diff --git a/app/Providers/CustomAuthProvider.php b/app/Providers/CustomAuthProvider.php new file mode 100644 index 00000000..4438a07d --- /dev/null +++ b/app/Providers/CustomAuthProvider.php @@ -0,0 +1,56 @@ + [ + 'App\Listeners\QueryExecutedListener', + ], + ]; + + /** + * Register any other events for your application. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + */ + public function boot(DispatcherContract $events) + { + parent::boot($events); + + // + } +} diff --git a/app/Providers/OAuth2/ClientAuthContextValidatorFactoryProvider.php b/app/Providers/OAuth2/ClientAuthContextValidatorFactoryProvider.php new file mode 100644 index 00000000..2caeefa6 --- /dev/null +++ b/app/Providers/OAuth2/ClientAuthContextValidatorFactoryProvider.php @@ -0,0 +1,48 @@ +cache_base_key.'_'.$entity->value); + return parent::add($entity); + } + + function update(IEntity $entity) + { + Cache::forget($this->cache_base_key.'_'.$entity->value); + return parent::update($entity); + } + + function delete(IEntity $entity) + { + Cache::forget($this->cache_base_key.'_'.$entity->value); + return parent::delete($entity); + } + + /** + * @param int $client_identifier + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + function getAllByClientIdentifier($client_identifier, $page_nbr = 1, $page_size = 10) + { + return $this->repository->getAllByClientIdentifier($client_identifier, $page_nbr, $page_size); + } + + /** + * @param int $client_identifier + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + function getAllValidByClientIdentifier($client_identifier, $page_nbr = 1, $page_size = 10) + { + return $this->repository->getAllValidByClientIdentifier($client_identifier, $page_nbr, $page_size ); + } + + /** + * @param int $user_id + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + function getAllByUserId($user_id, $page_nbr = 1, $page_size = 10) + { + return $this->repository->getAllByUserId($user_id, $page_nbr, $page_size); + } + + /** + * @param int $user_id + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + function getAllValidByUserId($user_id, $page_nbr = 1, $page_size = 10) + { + return $this->repository->getAllValidByUserId($user_id, $page_nbr, $page_size); + } +} \ No newline at end of file diff --git a/app/repositories/AbstractEloquentEntityRepository.php b/app/Repositories/AbstractEloquentEntityRepository.php similarity index 86% rename from app/repositories/AbstractEloquentEntityRepository.php rename to app/Repositories/AbstractEloquentEntityRepository.php index 0d60ec00..8fda82bc 100644 --- a/app/repositories/AbstractEloquentEntityRepository.php +++ b/app/Repositories/AbstractEloquentEntityRepository.php @@ -1,4 +1,4 @@ -setCurrentPage($page_nbr); - - return $this->entity->Filter($filters)->paginate($page_size, $fields); + return $this->entity->Filter($filters)->paginate($page_size, $fields, $pageName = 'Page', $page_nbr); } /** @@ -47,7 +42,7 @@ abstract class AbstractEloquentEntityRepository implements IBaseRepository */ public function update(IEntity $entity) { - return $entity->Save(); + return $entity->save(); } /** diff --git a/app/Repositories/AbstractEloquentOAuth2TokenRepository.php b/app/Repositories/AbstractEloquentOAuth2TokenRepository.php new file mode 100644 index 00000000..65ed1889 --- /dev/null +++ b/app/Repositories/AbstractEloquentOAuth2TokenRepository.php @@ -0,0 +1,80 @@ +getAll($page_nbr, $page_size, [['name' => 'client_id', 'op' => '=','value' => $client_identifier]]); + } + + /** + * @param int $user_id + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + public function getAllByUserId($user_id, $page_nbr = 1, $page_size = 10){ + return $this->getAll($page_nbr, $page_size, [['name' => 'user_id', 'op' => '=','value' => $user_id]]); + } + + /** + * @param int $client_identifier + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + function getAllValidByClientIdentifier($client_identifier, $page_nbr = 1, $page_size = 10) + { + return $this->getAll($page_nbr, $page_size, [ + ['name' => 'client_id', 'op' => '=','value' => $client_identifier ], + ['raw' => 'DATE_ADD(created_at, INTERVAL lifetime second) >= UTC_TIMESTAMP()'], + ]); + } + + /** + * @param int $user_id + * @param int $page_nbr + * @param int $page_size + * @return LengthAwarePaginator + */ + function getAllValidByUserId($user_id, $page_nbr = 1, $page_size = 10) + { + return $this->getAll($page_nbr, $page_size, [ + ['name' => 'user_id', 'op' => '=','value' => $user_id ], + ['raw' => 'DATE_ADD(created_at, INTERVAL lifetime second) >= UTC_TIMESTAMP()'], + ]); + } + + /** + * @param $hashed_value + * @return mixed + */ + function getByValue($hashed_value) + { + return $this->entity->where('value', '=', $hashed_value)->first(); + } + +} \ No newline at end of file diff --git a/app/Repositories/BaseCacheRepository.php b/app/Repositories/BaseCacheRepository.php new file mode 100644 index 00000000..452b3958 --- /dev/null +++ b/app/Repositories/BaseCacheRepository.php @@ -0,0 +1,98 @@ +repository = $repository; + } + + /** + * @param int $id + * @return IEntity + */ + public function get($id) + { + return Cache::remember($this->cache_base_key.'_'.$id, $this->cache_minutes_lifetime, function() use($id) { + return $this->repository->get($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 $fields = ['*']) + { + return $this->repository->getAll($page_nbr, $page_size, $filters, $fields); + } + + /** + * @param IEntity $entity + * @return bool + */ + public function update(IEntity $entity) + { + return $this->repository->update($entity); + } + + /** + * @param IEntity $entity + * @return bool + */ + public function add(IEntity $entity) + { + return $this->repository->add($entity); + } + + /** + * @param IEntity $entity + * @return bool + */ + public function delete(IEntity $entity) + { + return $this->repository->delete($entity); + } + +} \ No newline at end of file diff --git a/app/Repositories/CacheAccessTokenRepository.php b/app/Repositories/CacheAccessTokenRepository.php new file mode 100644 index 00000000..9b1cb199 --- /dev/null +++ b/app/Repositories/CacheAccessTokenRepository.php @@ -0,0 +1,69 @@ +cache_base_key = 'access_token'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_access_token_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param string $hashed_value + * @return AccessToken + */ + function getByValue($hashed_value) + { + return Cache::remember($this->cache_base_key.'_'.$hashed_value, $this->cache_minutes_lifetime, function() use($hashed_value) { + return $this->repository->getByValue($hashed_value); + }); + } + + /** + * @param string $hashed_value + * @return AccessToken + */ + function getByAuthCode($hashed_value) + { + return Cache::remember($this->cache_base_key.'_'.$hashed_value, $this->cache_minutes_lifetime, function() use($hashed_value) { + return $this->repository->getByAuthCode($hashed_value); + }); + } + + /** + * @param int $refresh_token_id + * @return AccessToken[] + */ + function getByRefreshToken($refresh_token_id) + { + return $this->repository->getByRefreshToken($refresh_token_id); + } + +} \ No newline at end of file diff --git a/app/Repositories/CacheApiEndpointRepository.php b/app/Repositories/CacheApiEndpointRepository.php new file mode 100644 index 00000000..dfd3cdf7 --- /dev/null +++ b/app/Repositories/CacheApiEndpointRepository.php @@ -0,0 +1,68 @@ +cache_base_key = 'api_endpoint'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_api_endpoint_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param string $url + * @param string $http_method + * @return IApiEndpoint + */ + public function getApiEndpointByUrlAndMethod($url, $http_method) + { + return Cache::remember($this->cache_base_key.'_'.$url.'_'.$http_method, $this->cache_minutes_lifetime, function() use($url, $http_method) { + return $this->repository->getApiEndpointByUrlAndMethod($url, $http_method); + }); + } + + /** + * @param string $url + * @param string $http_method + * @param int $api_id + * @return IApiEndpoint + */ + public function getApiEndpointByUrlAndMethodAndApi($url, $http_method, $api_id) + { + return Cache::remember($this->cache_base_key.'_'.$url.'_'.$http_method.'_'.$api_id, $this->cache_minutes_lifetime, function() use($url, $http_method, $api_id) { + return $this->repository->getApiEndpointByUrlAndMethodAndApi($url, $http_method, $api_id); + }); + } + + /** + * @param string $url + * @return IApiEndpoint + */ + public function getApiEndpointByUrl($url) + { + return Cache::remember($this->cache_base_key.'_'.$url, $this->cache_minutes_lifetime, function() use($url) { + return $this->repository->getApiEndpointByUrl($url); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/CacheApiRepository.php b/app/Repositories/CacheApiRepository.php new file mode 100644 index 00000000..a26fa515 --- /dev/null +++ b/app/Repositories/CacheApiRepository.php @@ -0,0 +1,55 @@ +cache_base_key = 'api'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_api_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param string $api_name + * @return IApi + */ + public function getByName($api_name) + { + return Cache::remember($this->cache_base_key.'_'.$api_name, $this->cache_minutes_lifetime, function() use($api_name) { + return $this->repository->getByName($api_name); + }); + } + + /** + * @param string $api_name + * @param int $resource_server_id + * @return IApi + */ + public function getByNameAndResourceServer($api_name, $resource_server_id) + { + return Cache::remember($this->cache_base_key.'_'.$api_name.'_'.$resource_server_id, $this->cache_minutes_lifetime, function() use($api_name, $resource_server_id) { + return $this->repository->getByNameAndResourceServer($api_name, $resource_server_id); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/CacheApiScopeRepository.php b/app/Repositories/CacheApiScopeRepository.php new file mode 100644 index 00000000..d1e60473 --- /dev/null +++ b/app/Repositories/CacheApiScopeRepository.php @@ -0,0 +1,73 @@ +cache_base_key = 'api_scope'; + $this->cache_minutes_lifetime = $this->cache_minutes_lifetime = Config::get("cache_regions.region_api_scope_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param array $scopes_names + * @return IApiScope[] + */ + public function getByName(array $scopes_names) + { + return Cache::remember($this->cache_base_key.'_'.join('_', $scopes_names), $this->cache_minutes_lifetime, function() use($scopes_names) { + return $this->repository->getByName($scopes_names); + }); + } + + /** + * @return IApiScope[] + */ + public function getDefaults() + { + return Cache::remember($this->cache_base_key.'_defaults', $this->cache_minutes_lifetime, function() { + return $this->repository->getDefaults(); + }); + } + + /** + * @return IApiScope[] + */ + public function getActives() + { + return Cache::remember($this->cache_base_key.'_actives', $this->cache_minutes_lifetime, function() { + return $this->repository->getActives(); + }); + } + + /** + * @return IApiScope[] + */ + public function getAssignableByGroups() + { + return Cache::remember($this->cache_base_key.'_assignables_by_groups', $this->cache_minutes_lifetime, function() { + return $this->repository->getAssignableByGroups(); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/CacheClientRepository.php b/app/Repositories/CacheClientRepository.php new file mode 100644 index 00000000..b79b8549 --- /dev/null +++ b/app/Repositories/CacheClientRepository.php @@ -0,0 +1,77 @@ +cache_base_key = 'client'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_clients_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param string $app_name + * @return IClient + */ + public function getByApplicationName($app_name) + { + return Cache::remember($this->cache_base_key.'_'.$app_name, $this->cache_minutes_lifetime, function() use($app_name) { + return $this->repository->getByApplicationName($app_name); + }); + } + + /** + * @param string $client_id + * @return IClient + */ + public function getClientById($client_id) + { + return Cache::remember($this->cache_base_key.'_'.$client_id, $this->cache_minutes_lifetime, function() use($client_id) { + return $this->repository->getClientById($client_id); + }); + } + + /** + * @param int $id + * @return IClient + */ + public function getClientByIdentifier($id) + { + return Cache::remember($this->cache_base_key.'_'.$id, $this->cache_minutes_lifetime, function() use($id) { + return $this->repository->getClientByIdentifier($id); + }); + } + + /** + * @param string $origin + * @return IClient + */ + public function getByOrigin($origin) + { + return Cache::remember($this->cache_base_key.'_'.$origin, $this->cache_minutes_lifetime, function() use($origin) { + return $this->repository->getByOrigin($origin); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/CacheRefreshTokenRepository.php b/app/Repositories/CacheRefreshTokenRepository.php new file mode 100644 index 00000000..848dac09 --- /dev/null +++ b/app/Repositories/CacheRefreshTokenRepository.php @@ -0,0 +1,48 @@ +cache_base_key = 'refresh_token'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_refresh_token_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param $hashed_value + * @return RefreshToken + */ + function getByValue($hashed_value) + { + return Cache::remember($this->cache_base_key.'_'.$hashed_value, $this->cache_minutes_lifetime, function() use($hashed_value) { + return $this->repository->getByValue($hashed_value); + }); + } + +} \ No newline at end of file diff --git a/app/Repositories/CacheResourceServerRepository.php b/app/Repositories/CacheResourceServerRepository.php new file mode 100644 index 00000000..c3ec5f60 --- /dev/null +++ b/app/Repositories/CacheResourceServerRepository.php @@ -0,0 +1,77 @@ +cache_base_key = 'resource_server'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_resource_server_lifetime", 1140); + parent::__construct($repository); + } + + /** + * @param string $host + * @return IResourceServer + */ + public function getByHost($host) + { + return Cache::remember($this->cache_base_key.'_'.$host, $this->cache_minutes_lifetime, function() use($host) { + return $this->repository->getByHost($host); + }); + } + + /** + * @param string $ip + * @return IResourceServer + */ + public function getByIp($ip) + { + return Cache::remember($this->cache_base_key.'_'.$ip, $this->cache_minutes_lifetime, function() use($ip) { + return $this->repository->getByIp($ip); + }); + } + + /** + * @param string $name + * @return IResourceServer + */ + public function getByFriendlyName($name) + { + return Cache::remember($this->cache_base_key.'_'.$name, $this->cache_minutes_lifetime, function() use($name) { + return $this->repository->getByFriendlyName($name); + }); + } + + /** + * @param array $audience + * @param string $ip + * @return IResourceServer + */ + public function getByAudienceAndIpAndActive(array $audience, $ip) + { + return Cache::remember($this->cache_base_key.'_'.join("_", $audience).'_'.$ip, $this->cache_minutes_lifetime, function() use($audience, $ip) { + return $this->repository->getByAudienceAndIpAndActive($audience, $ip); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/CacheUserRepository.php b/app/Repositories/CacheUserRepository.php new file mode 100644 index 00000000..d786f139 --- /dev/null +++ b/app/Repositories/CacheUserRepository.php @@ -0,0 +1,112 @@ +cache_base_key = 'user'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_users_lifetime", 30); + parent::__construct($repository); + } + + /** + * @param $external_id + * @return User + */ + public function getByExternalId($external_id) + { + return Cache::remember($this->cache_base_key.'_'.$external_id, $this->cache_minutes_lifetime, function() use($external_id) { + return $this->repository->getByExternalId($external_id); + }); + } + + /** + * @param $filters + * @return array + */ + public function getByCriteria($filters) + { + return $this->repository->getByCriteria($filters); + } + + /** + * @param $filters + * @return User + */ + public function getOneByCriteria($filters) + { + return $this->repository->getOneByCriteria($filters); + } + + /** + * @param array $filters + * @return int + */ + public function getCount(array $filters = array()) + { + return $this->repository->getCount($filters); + } + + /** + * @param mixed $identifier + * @param string $token + * @return User + */ + public function getByToken($identifier, $token) + { + return $this->repository->getByToken($identifier, $token); + } + + /** + * @param string $term + * @return array + */ + public function getByEmailOrName($term) + { + return Cache::remember($this->cache_base_key.'_'.$term, $this->cache_minutes_lifetime, function() use($term) { + return $this->repository->getByEmailOrName($term); + }); + } + + /** + * @param string $user_identifier + * @return User + */ + public function getByIdentifier($user_identifier) + { + return Cache::remember($this->cache_base_key.'_'.$user_identifier, $this->cache_minutes_lifetime, function() use($user_identifier) { + return $this->repository->getByIdentifier($user_identifier); + }); + } + + /** + * @param $id + * @return User + */ + public function get($id) + { + return Cache::remember($this->cache_base_key.'_'.$id, $this->cache_minutes_lifetime, function() use($id) { + return $this->repository->get($id); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/CacheWhiteListedIPRepository.php b/app/Repositories/CacheWhiteListedIPRepository.php new file mode 100644 index 00000000..84ae4ba8 --- /dev/null +++ b/app/Repositories/CacheWhiteListedIPRepository.php @@ -0,0 +1,45 @@ +cache_base_key = 'white_listed_ip'; + $this->cache_minutes_lifetime = Config::get("cache_regions.region_white_listed_ip_lifetime", 1140); + parent::__construct($repository); + } + + + /** + * @param string $ip + * @return WhiteListedIP + */ + function getByIp($ip) + { + return Cache::remember($this->cache_base_key.'_'.$ip, $this->cache_minutes_lifetime, function() use($ip) { + return $this->repository->getByIp($ip); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/EloquentAccessTokenRepository.php b/app/Repositories/EloquentAccessTokenRepository.php new file mode 100644 index 00000000..430bd978 --- /dev/null +++ b/app/Repositories/EloquentAccessTokenRepository.php @@ -0,0 +1,50 @@ +entity = $entity; + $this->log_service = $log_service; + } + + /** + * @param string $hashed_value + * @return AccessToken + */ + function getByAuthCode($hashed_value) + { + return $this->entity->where('associated_authorization_code', '=', $hashed_value)->first(); + } + + /** + * @param int $refresh_token_id + * @return AccessToken[] + */ + function getByRefreshToken($refresh_token_id) + { + return $this->entity->where('refresh_token_id', '=', $refresh_token_id)->get(); + } +} \ No newline at end of file diff --git a/app/Repositories/EloquentApiEndpointRepository.php b/app/Repositories/EloquentApiEndpointRepository.php new file mode 100644 index 00000000..56d08121 --- /dev/null +++ b/app/Repositories/EloquentApiEndpointRepository.php @@ -0,0 +1,75 @@ +entity = $endpoint; + } + + /** + * @param string $url + * @param string $http_method + * @return IApiEndpoint + */ + public function getApiEndpointByUrlAndMethod($url, $http_method) + { + return $this->entity->Filter(array( + array( + 'name' => 'route', + 'op' => '=', + 'value' => $url + ), + array( + 'name' => 'http_method', + 'op' => '=', + 'value' => $http_method + ) + ))->first(); + } + + /** + * @param string $url + * @return IApiEndpoint + */ + public function getApiEndpointByUrl($url) + { + return $this->entity->where('route','=',$url)->first(); + } + + /** + * @param string $url + * @param string $http_method + * @param int $api_id + * @return IApiEndpoint + */ + public function getApiEndpointByUrlAndMethodAndApi($url, $http_method, $api_id) + { + return $this->entity + ->where('http_method', '=' , $http_method) + ->where('route', '=' , $url) + ->where('api_id', '=' ,$api_id) + ->first(); + } +} \ No newline at end of file diff --git a/app/Repositories/EloquentApiRepository.php b/app/Repositories/EloquentApiRepository.php new file mode 100644 index 00000000..ca83fd14 --- /dev/null +++ b/app/Repositories/EloquentApiRepository.php @@ -0,0 +1,50 @@ +entity = $api; + } + + /** + * @param string $api_name + * @return IApi + */ + public function getByName($api_name) + { + return $this->entity->where('name','=',$api_name)->first(); + } + + /** + * @param string $api_name + * @param int $resource_server_id + * @return IApi + */ + public function getByNameAndResourceServer($api_name, $resource_server_id) + { + return $this->entity->where('name','=',$api_name)->where('resource_server_id','=',$resource_server_id)->first(); + } +} \ No newline at end of file diff --git a/app/repositories/EloquentApiScopeGroupRepository.php b/app/Repositories/EloquentApiScopeGroupRepository.php similarity index 77% rename from app/repositories/EloquentApiScopeGroupRepository.php rename to app/Repositories/EloquentApiScopeGroupRepository.php index 4ed8e5e8..f72a570f 100644 --- a/app/repositories/EloquentApiScopeGroupRepository.php +++ b/app/Repositories/EloquentApiScopeGroupRepository.php @@ -1,4 +1,4 @@ -log_service = $log_service; } + /** + * @param string $name + * @return ApiScopeGroup + */ + public function getByName($name) + { + return $this->entity->where('name', '=', $name)->first(); + } } \ No newline at end of file diff --git a/app/Repositories/EloquentApiScopeRepository.php b/app/Repositories/EloquentApiScopeRepository.php new file mode 100644 index 00000000..01cc87fd --- /dev/null +++ b/app/Repositories/EloquentApiScopeRepository.php @@ -0,0 +1,72 @@ +entity = $scope; + } + + /** + * @param array $scopes_names + * @return IApiScope[] + */ + public function getByName(array $scopes_names) + { + return $this->entity->where('active', '=', true)->whereIn('name', $scopes_names)->get(); + } + + /** + * @return IApiScope[] + */ + public function getDefaults() + { + return $this->entity->where('default', '=', true)->where('active', '=', true)->get(); + } + + /** + * @return IApiScope[] + */ + public function getActives(){ + return $this->entity + ->with('api') + ->with('api.resource_server') + ->where('active', '=', true) + ->orderBy('api_id')->get(); + } + + /** + * @return IApiScope[] + */ + public function getAssignableByGroups(){ + return $this->entity + ->with('api') + ->with('api.resource_server') + ->where('active', '=', true) + ->where('assigned_by_groups', '=', true) + ->orderBy('api_id')->get(); + } +} \ No newline at end of file diff --git a/app/repositories/EloquentAssymetricKeyRepository.php b/app/Repositories/EloquentAsymmetricKeyRepository.php similarity index 63% rename from app/repositories/EloquentAssymetricKeyRepository.php rename to app/Repositories/EloquentAsymmetricKeyRepository.php index 40068deb..119d9a4f 100644 --- a/app/repositories/EloquentAssymetricKeyRepository.php +++ b/app/Repositories/EloquentAsymmetricKeyRepository.php @@ -1,4 +1,4 @@ -key->where('kid','=',$kid)->first(); - } - - /** - * @param IAssymetricKey $key - * @return void - */ - public function add(IAssymetricKey $key) - { - $key->save(); - } - - /** - * @param IAssymetricKey $key - * @return void - */ - public function delete(IAssymetricKey $key) - { - $key->delete(); + return $this->entity->where('kid','=',$kid)->first(); } /** * @param int $id - * @return IAssymetricKey + * @return IAsymmetricKey */ public function getById($id) { - return $this->key->find($id); + return $this->entity->find($id); } /** * @param string $pem - * @return IAssymetricKey + * @return IAsymmetricKey */ public function getByPEM($pem) { - return $this->key->where('pem_content','=',$pem)->first(); + return $this->entity->where('pem_content','=',$pem)->first(); } /** * @param string $type * @param string $usage * @params string $alg - * @param \DateTime $valid_from - * @param \DateTime $valid_to + * @param DateTime $valid_from + * @param DateTime $valid_to * @param int|null $owner_id - * @return IAssymetricKey + * @return IAsymmetricKey */ - public function getByValidityRange($type, $usage, $alg, \DateTime $valid_from, \DateTime $valid_to, $owner_id = null) + public function getByValidityRange($type, $usage, $alg, DateTime $valid_from, DateTime $valid_to, $owner_id = null) { // (StartA <= EndB) and (EndA >= StartB) - $query = $this->key + $query = $this->entity ->where('type','=',$type) ->where('usage','=',$usage) ->where('alg','=',$alg) @@ -113,21 +86,20 @@ abstract class EloquentAssymetricKeyRepository implements IAssymetricKeyReposito * @param int $page_size * @param array $filters * @param array $fields - * @return IAssymetricKey[] + * @return IAsymmetricKey[] */ public function getAll($page_nbr = 1, $page_size = 10, array $filters = array(), array $fields = array('*')) { - DB::getPaginator()->setCurrentPage($page_nbr); - return $this->key->Filter($filters)->paginate($page_size, $fields); + return $this->entity->Filter($filters)->paginate($page_size, $fields, $pageName = 'page', $page_nbr); } /** - * @return IAssymetricKey[] + * @return IAsymmetricKey[] */ public function getActives() { - $now = new \DateTime(); - return $this->key + $now = new DateTime(); + return $this->entity ->where('active','=', true) ->where('valid_from','<=',$now) ->where('valid_to','>=',$now) @@ -139,12 +111,12 @@ abstract class EloquentAssymetricKeyRepository implements IAssymetricKeyReposito * @param string $usage * @param string $alg * @param int|null $owner_id - * @return IAssymetricKey + * @return IAsymmetricKey */ public function getActiveByCriteria($type, $usage, $alg, $owner_id = null) { - $now = new \DateTime(); - $query = $this->key + $now = new DateTime(); + $query = $this->entity ->where('active','=', true) ->where('valid_from','<=',$now) ->where('valid_to','>=',$now) diff --git a/app/repositories/EloquentClientPublicKeyRepository.php b/app/Repositories/EloquentClientPublicKeyRepository.php similarity index 75% rename from app/repositories/EloquentClientPublicKeyRepository.php rename to app/Repositories/EloquentClientPublicKeyRepository.php index ee629968..f5f67304 100644 --- a/app/repositories/EloquentClientPublicKeyRepository.php +++ b/app/Repositories/EloquentClientPublicKeyRepository.php @@ -1,4 +1,4 @@ -key = $public_key; + $this->entity = $public_key; $this->log_service = $log_service; } } \ No newline at end of file diff --git a/app/repositories/EloquentClientRepository.php b/app/Repositories/EloquentClientRepository.php similarity index 56% rename from app/repositories/EloquentClientRepository.php rename to app/Repositories/EloquentClientRepository.php index dac8f4a5..1dbeaac0 100644 --- a/app/repositories/EloquentClientRepository.php +++ b/app/Repositories/EloquentClientRepository.php @@ -1,4 +1,4 @@ -client = $client; + $this->entity = $client; $this->log_service = $log_service; } - /** - * @param int id - * @return IClient - */ - public function get($id) - { - return $this->client->find($id); - } - - /** - * @param IClient $client - * @return void - */ - public function add(IClient $client) - { - $client->save(); - } - - /** - * @param IClient $client - * @return void - */ - public function delete(IClient $client) - { - $client->delete(); - } - /** * @param string $app_name * @return IClient */ public function getByApplicationName($app_name) { - return $this->client->where('app_name', '=', trim($app_name))->first(); + return $this->entity->where('app_name', '=', trim($app_name))->first(); + } + + /** + * @param string $client_id + * @return IClient + */ + public function getClientById($client_id) + { + return $this->entity->where('client_id', '=', $client_id)->first(); + } + + /** + * @param int $id + * @return IClient + */ + public function getClientByIdentifier($id) + { + return $this->entity->where('id', '=', $id)->first(); + } + + /** + * @param string $origin + * @return IClient + */ + public function getByOrigin($origin) + { + return $this->entity->where('allowed_origins', 'like', '%'.$origin.'%')->first(); } } \ No newline at end of file diff --git a/app/Repositories/EloquentMemberRepository.php b/app/Repositories/EloquentMemberRepository.php new file mode 100644 index 00000000..0990b88b --- /dev/null +++ b/app/Repositories/EloquentMemberRepository.php @@ -0,0 +1,48 @@ +entity = $member; + $this->log_service = $log_service; + } + + /** + * @param $email + * @return Member + */ + public function getByEmail($email) + { + return $this->entity->where('Email', '=', $email)->first(); + } +} \ No newline at end of file diff --git a/app/Repositories/EloquentOpenIdAssociationRepository.php b/app/Repositories/EloquentOpenIdAssociationRepository.php new file mode 100644 index 00000000..620a47ee --- /dev/null +++ b/app/Repositories/EloquentOpenIdAssociationRepository.php @@ -0,0 +1,40 @@ +entity = $association; + } + + public function deleteById($id) + { + return $this->delete($this->get($id)); + } + + public function getByHandle($handle) + { + return $this->entity->where('identifier', '=', $handle)->first(); + } +} \ No newline at end of file diff --git a/app/Repositories/EloquentOpenIdTrustedSiteRepository.php b/app/Repositories/EloquentOpenIdTrustedSiteRepository.php new file mode 100644 index 00000000..4d077347 --- /dev/null +++ b/app/Repositories/EloquentOpenIdTrustedSiteRepository.php @@ -0,0 +1,66 @@ +entity = $openid_trusted_site; + } + + /** + * @param int $id + * @return bool + */ + public function deleteById($id) + { + return $this->delete($this->get($id)); + } + + /** + * @param int $user_id + * @param array $sub_domains + * @param array $data + * @return array + */ + public function getMatchingOnesByUserId($user_id, array $sub_domains, array $data) + { + $query = $this->entity->where("user_id", "=", intval($user_id)); + //add or condition for all given sub-domains + if (count($sub_domains)) { + $query = $query->where(function ($query) use ($sub_domains) { + foreach ($sub_domains as $sub_domain) { + $query = $query->orWhere(function ($query_aux) use ($sub_domain) { + $query_aux->where('realm', '=', $sub_domain); + }); + } + }); + } + //add conditions for all possible pre approved data + foreach ($data as $value) { + $query = $query->where("data", "LIKE", '%"' . $value . '"%'); + } + return $query->get(); + } +} \ No newline at end of file diff --git a/app/Repositories/EloquentRefreshTokenRepository.php b/app/Repositories/EloquentRefreshTokenRepository.php new file mode 100644 index 00000000..d78415bb --- /dev/null +++ b/app/Repositories/EloquentRefreshTokenRepository.php @@ -0,0 +1,34 @@ +entity = $entity; + $this->log_service = $log_service; + } + +} \ No newline at end of file diff --git a/app/Repositories/EloquentResourceServerRepository.php b/app/Repositories/EloquentResourceServerRepository.php new file mode 100644 index 00000000..fdb887bd --- /dev/null +++ b/app/Repositories/EloquentResourceServerRepository.php @@ -0,0 +1,73 @@ +entity = $entity; + } + + /** + * @param string $host + * @return IResourceServer + */ + public function getByHost($host) + { + return $this->entity->whereIn('host', $host)->first(); + } + + /** + * @param string $ip + * @return IResourceServer + */ + public function getByIp($ip) + { + return $this->entity->where('ips', 'like', '%' . $ip . '%')->first(); + } + + /** + * @param array $audience + * @param string $ip + * @return IResourceServer + */ + public function getByAudienceAndIpAndActive(array $audience, $ip){ + return $this->entity->where('ips','like', '%'.$ip.'%') + ->where('active', '=', true) + ->whereIn('host', $audience)->first(); + } + + /** + * @param string $name + * @return IResourceServer + */ + public function getByFriendlyName($name) + { + return $this->entity->where('friendly_name', '=', $name)->first(); + } +} \ No newline at end of file diff --git a/app/repositories/EloquentServerPrivateKeyRepository.php b/app/Repositories/EloquentServerPrivateKeyRepository.php similarity index 71% rename from app/repositories/EloquentServerPrivateKeyRepository.php rename to app/Repositories/EloquentServerPrivateKeyRepository.php index e6eaa437..f1b0de08 100644 --- a/app/repositories/EloquentServerPrivateKeyRepository.php +++ b/app/Repositories/EloquentServerPrivateKeyRepository.php @@ -1,4 +1,4 @@ -key = $private_key; + $this->entity = $private_key; $this->log_service = $log_service; } } \ No newline at end of file diff --git a/app/repositories/EloquentUserRepository.php b/app/Repositories/EloquentUserRepository.php similarity index 74% rename from app/repositories/EloquentUserRepository.php rename to app/Repositories/EloquentUserRepository.php index f71f59ef..a1db70ff 100644 --- a/app/repositories/EloquentUserRepository.php +++ b/app/Repositories/EloquentUserRepository.php @@ -1,13 +1,20 @@ -paginate(10); - foreach($members->getItems() as $m) + foreach($members->items() as $m) { $user = $this->getByExternalId(intval($m->ID)); if(!is_null($user)) diff --git a/app/Repositories/EloquentWhiteListedIPRepository.php b/app/Repositories/EloquentWhiteListedIPRepository.php new file mode 100644 index 00000000..c7c3b81f --- /dev/null +++ b/app/Repositories/EloquentWhiteListedIPRepository.php @@ -0,0 +1,40 @@ +entity = $entity; + } + + /** + * @param string $ip + * @return WhiteListedIP + */ + function getByIp($ip) + { + return $this->entity->where('ip','=', $ip)->first(); + } +} \ No newline at end of file diff --git a/app/Repositories/RepositoriesProvider.php b/app/Repositories/RepositoriesProvider.php new file mode 100644 index 00000000..e12370c5 --- /dev/null +++ b/app/Repositories/RepositoriesProvider.php @@ -0,0 +1,131 @@ +tx_service = $tx_service; + $this->repository = $repository; + $this->scope_repository = $scope_repository; + } + + + /** + * Adds a new api endpoint to an existent api + * @param string $name + * @param string $description + * @param boolean $active + * @param boolean $allow_cors + * @param string $route + * @param string $http_method + * @param integer $api_id + * @param integer $rate_limit + * @return IApiEndpoint + */ + public function add($name, $description, $active,$allow_cors, $route, $http_method, $api_id, $rate_limit) + { + return $this->tx_service->transaction(function () use ($name, $description, $active, $allow_cors, $route, $http_method, $api_id, $rate_limit) { + + //check that does not exists an endpoint with same http method and same route + + $former_endpoint = $this->repository->getApiEndpointByUrlAndMethodAndApi($route, $http_method, $api_id); + + if(!is_null($former_endpoint)) + throw new InvalidApiEndpoint + ( + sprintf + ( + 'there is already an endpoint api with route %s and http method %s', + $route, + $http_method + ) + ); + // todo: move to factory + $instance = new ApiEndpoint( + [ + 'name' => $name, + 'description' => $description, + 'active' => $active, + 'route' => $route, + 'http_method' => $http_method, + 'api_id' => $api_id, + 'allow_cors' => $allow_cors, + 'rate_limit' => (int)$rate_limit, + ] + ); + + $this->repository->add($instance); + }); + + } + + /** + * @param int $id + * @param array $params + * @return bool + * @throws EntityNotFoundException + * @throws InvalidApiEndpoint + */ + public function update($id, array $params){ + + return $this->tx_service->transaction(function () use ($id, $params){ + $endpoint = $this->repository->get($id); + + if(is_null($endpoint)) + throw new EntityNotFoundException(sprintf('api endpoint id %s does not exists!', $id)); + + $allowed_update_params = ['name','description','active','route','http_method','allow_cors', 'rate_limit']; + + foreach($allowed_update_params as $param){ + if(array_key_exists($param,$params)){ + $endpoint->{$param} = $params[$param]; + } + } + + //check that does not exists an endpoint with same http method and same route + $former_endpoint = $this->repository->getApiEndpointByUrlAndMethodAndApi + ( + $endpoint->route, + $endpoint->http_method, + $endpoint->api_id + ); + + if(!is_null($former_endpoint) && $former_endpoint->id != $endpoint->id) + throw new InvalidApiEndpoint + ( + sprintf + ( + 'there is already an endpoint api with route %s and http method %s', + $endpoint->route, + $endpoint->http_method + ) + ); + + return true; + }); + } + + /** + * Adds a new required scope to a given api endpoint, + * given scope must belongs to owner api of the given endpoint + * @param int $api_endpoint_id + * @param int $scope_id + * @return boolean + * @throws InvalidApiScope + * @throws EntityNotFoundException + * @throws InvalidApiEndpoint + */ + public function addRequiredScope($api_endpoint_id, $scope_id) + { + + return $this->tx_service->transaction(function () use($api_endpoint_id, $scope_id){ + + $api_endpoint = $this->repository->get($api_endpoint_id); + + if(is_null($api_endpoint)) + throw new EntityNotFoundException(sprintf("api endpoint id %s does not exists!.",$api_endpoint_id)); + + $scope = $this->scope_repository->get($scope_id); + + if(is_null($scope)) + throw new InvalidApiScope(sprintf("api scope id %s does not exists!.", $scope_id)); + + if($scope->api_id != $api_endpoint->api_id) + throw new InvalidApiScope(sprintf("api scope id %s does not belong to api id %s !.",$scope_id,$api_endpoint->api_id)); + + $res = $api_endpoint->scopes()->where('id', '=' , $scope_id)->count(); + + if($res > 0) + throw new InvalidApiScope(sprintf("api scope id %s already belongs to endpoint id %s!.",$scope_id,$api_endpoint->id)); + + $api_endpoint->scopes()->attach($scope_id); + + return true; + }); + } + + + /** + * Removes a required scope to a given api endpoint, + * given scope must belongs to owner api of the given endpoint + * @param int $api_endpoint_id + * @param int $scope_id + * @return boolean + * @throws InvalidApiScope + * @throws InvalidApiEndpoint + * @throws EntityNotFoundException + */ + public function removeRequiredScope($api_endpoint_id, $scope_id) + { + + $res = false; + + $this->tx_service->transaction(function () use($api_endpoint_id, $scope_id,&$res){ + + $api_endpoint = $this->repository->get($api_endpoint_id); + + if(is_null($api_endpoint)) + throw new EntityNotFoundException(sprintf("api endpoint id %s does not exists!.",$api_endpoint_id)); + + $scope = $this->scope_repository->get($scope_id); + + if(is_null($scope)) + throw new InvalidApiScope(sprintf("api scope id %s does not exists!.",$scope_id)); + + if($scope->api_id !== $api_endpoint->api_id) + throw new InvalidApiScope(sprintf("api scope id %s does not belongs to api id %s!.",$scope_id,$api_endpoint->api_id)); + + $res = $api_endpoint->scopes()->where('id','=',$scope_id)->count(); + + if($res==0) + throw new InvalidApiScope(sprintf("api scope id %s does not belongs to endpoint id %s !.",$scope_id,$api_endpoint->id)); + + $api_endpoint->scopes()->detach($scope_id); + + $res = true; + }); + return $res; + } + + /** + * deletes a given api endpoint + * @param int $id + * @return boolean + * @throws EntityNotFoundException + */ + public function delete($id) + { + return $this->tx_service->transaction(function () use ($id) { + $endpoint = $this->repository->get($id); + if(is_null($endpoint)) throw new EntityNotFoundException(); + $this->repository->delete($endpoint); + return true; + }); + } + + /** + * @param int $id + * @param boolean $active + * @return boolean + * @throws EntityNotFoundException + */ + public function setStatus($id, $active) + { + return $this->tx_service->transaction(function () use ($id, $active) { + $endpoint = $this->repository->get($id); + if(is_null($endpoint)) throw new EntityNotFoundException(); + $endpoint->active = $active; + $this->repository->add($endpoint); + return true; + }); + } +} \ No newline at end of file diff --git a/app/services/oauth2/ApiScopeGroupService.php b/app/Services/OAuth2/ApiScopeGroupService.php similarity index 77% rename from app/services/oauth2/ApiScopeGroupService.php rename to app/Services/OAuth2/ApiScopeGroupService.php index ff7f9021..69917833 100644 --- a/app/services/oauth2/ApiScopeGroupService.php +++ b/app/Services/OAuth2/ApiScopeGroupService.php @@ -1,6 +1,6 @@ -log_service = $log_service; - $this->repository = $repository; - $this->user_repository = $user_repository; - $this->scope_service = $scope_service; - $this->tx_service = $tx_service; + $this->log_service = $log_service; + $this->repository = $repository; + $this->user_repository = $user_repository; + $this->scope_service = $scope_service; + $this->scope_repository = $scope_repository; + $this->tx_service = $tx_service; } public function update($id, array $params) @@ -82,7 +88,7 @@ final class ApiScopeGroupService implements IApiScopeGroupService return $this->tx_service->transaction(function () use ($id, $params, $repository, $scope_service, $user_repository) { - $group = ApiScopeGroup::find($id); + $group = $repository->get($id); if (is_null($group)) { @@ -98,7 +104,8 @@ final class ApiScopeGroupService implements IApiScopeGroupService if ($param == 'name') { - if (ApiScopeGroup::where('name', '=', $params[$param])->where('id', '<>', $id)->count() > 0) + $older_group = $repository->getByName($params[$param]); + if(!is_null($older_group) && $older_group->id != $id) { throw new InvalidApiScopeGroup(sprintf('there is already another api scope group name (%s).', $params[$param])); } @@ -110,7 +117,7 @@ final class ApiScopeGroupService implements IApiScopeGroupService $scopes = explode(',', $params['scopes']); foreach($scopes as $scope_id) { - $scope = $scope_service->get(intval($scope_id)); + $scope = $this->scope_repository->get(intval($scope_id)); if(is_null($scope)) throw new EntityNotFoundException(sprintf('scope %s not found.',$scope_id)); $group->addScope($scope); } @@ -141,7 +148,12 @@ final class ApiScopeGroupService implements IApiScopeGroupService */ public function setStatus($id, $status) { - return ApiScopeGroup::find($id)->update(array('active' => $status)); + $this->tx_service->transaction(function() use($id, $status){ + $group = $this->repository->get($id); + if(is_null($group)) return; + $group->active = $status; + $this->repository->add($group); + }); } /** @@ -172,6 +184,7 @@ final class ApiScopeGroupService implements IApiScopeGroupService throw new InvalidApiScopeGroup(sprintf('there is already another group with that name (%s).', $name)); } + // todo : move to factory $repository->add($instance = new ApiScopeGroup ( array @@ -186,7 +199,7 @@ final class ApiScopeGroupService implements IApiScopeGroupService $users = explode(',', $users); foreach($scopes as $scope_id) { - $scope = $scope_service->get(intval($scope_id)); + $scope = $this->scope_repository->get(intval($scope_id)); if(is_null($scope)) throw new EntityNotFoundException(sprintf('scope %s not found.',$scope_id)); $instance->addScope($scope); } diff --git a/app/services/oauth2/ApiScopeService.php b/app/Services/OAuth2/ApiScopeService.php similarity index 57% rename from app/services/oauth2/ApiScopeService.php rename to app/Services/OAuth2/ApiScopeService.php index cdaa5ef0..01818e52 100644 --- a/app/services/oauth2/ApiScopeService.php +++ b/app/Services/OAuth2/ApiScopeService.php @@ -1,40 +1,66 @@ -tx_service = $tx_service; - } + private $repository; /** - * @param array $scopes_names - * @return mixed + * @var IApiRepository */ - public function getScopesByName(array $scopes_names) + private $api_repository; + + /** + * ApiScopeService constructor. + * @param ITransactionService $tx_service + * @param IApiScopeRepository $repository + * @param IApiRepository $api_repository + */ + public function __construct + ( + ITransactionService $tx_service, + IApiScopeRepository $repository, + IApiRepository $api_repository + ) { - return ApiScope::where('active', '=', true)->whereIn('name', $scopes_names)->get(); + $this->tx_service = $tx_service; + $this->repository = $repository; + $this->api_repository = $api_repository; } /** @@ -54,13 +80,8 @@ final class ApiScopeService implements IApiScopeService */ public function getAvailableScopes($system = false, $assigned_by_groups = false) { - $scopes = ApiScope - ::with('api') - ->with('api.resource_server') - ->where('active', '=', true) - ->orderBy('api_id')->get(); - - $res = array(); + $res = []; + $scopes = $this->repository->getActives(); foreach ($scopes as $scope) { @@ -72,7 +93,7 @@ final class ApiScopeService implements IApiScopeService if ($scope->assigned_by_groups && !$assigned_by_groups) { continue; } - array_push($res, $scope); + $res[] = $scope; } } @@ -85,11 +106,11 @@ final class ApiScopeService implements IApiScopeService */ public function getAudienceByScopeNames(array $scopes_names) { - $scopes = $this->getScopesByName($scopes_names); - $audience = array(); + $scopes = $this->repository->getByName($scopes_names); + $audience = []; foreach ($scopes as $scope) { - $api = $scope->api()->first(); - $resource_server = !is_null($api) ? $api->resource_server()->first() : null; + $api = $scope->getApi(); + $resource_server = !is_null($api) ? $api->getResourceServer() : null; if (!is_null($resource_server) && !array_key_exists($resource_server->host, $audience)) { $audience[$resource_server->host] = $resource_server->ip; } @@ -114,60 +135,22 @@ final class ApiScopeService implements IApiScopeService return $audience; } - /** - * gets an api scope by id - * @param $id id of api scope - * @return IApiScope - */ - public function get($id) - { - return ApiScope::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 ApiScope::Filter($filters)->paginate($page_size, $fields); - } - - /** - * @param IApiScope $scope - * @return bool - */ - public function save(IApiScope $scope) - { - if (!$scope->exists() || count($scope->getDirty()) > 0) { - return $scope->Save(); - } - - return true; - } - /** * @param $id * @param array $params * @return bool - * @throws \oauth2\exceptions\InvalidApiScope + * @throws InvalidApiScope + * @throws EntityNotFoundException */ public function update($id, array $params) { - $res = false; - $this_var = $this; - $this->tx_service->transaction(function () use ($id, $params, &$res, &$this_var) { + return $this->tx_service->transaction(function () use ($id, $params) { //check that scope exists... - $scope = ApiScope::find($id); + $scope = $this->repository->get($id); if (is_null($scope)) { - throw new InvalidApiScope(sprintf('scope id %s does not exists!', $id)); + throw new EntityNotFoundException(sprintf('scope id %s does not exists!', $id)); } $allowed_update_params = array('name', 'description', 'short_description', 'active', 'system', 'default', 'assigned_by_groups'); @@ -177,7 +160,9 @@ final class ApiScopeService implements IApiScopeService if ($param == 'name') { //check if we have a former scope with selected name - if (ApiScope::where('name', '=', $params[$param])->where('id', '<>', $id)->count() > 0) { + $former_scope = $this->repository->getByName($params[$param]); + + if (!is_null($former_scope) && $former_scope->id != $id) { throw new InvalidApiScope(sprintf('scope name %s already exists!', $params[$param])); } } @@ -185,48 +170,49 @@ final class ApiScopeService implements IApiScopeService $scope->{$param} = $params[$param]; } } - $res = $this_var->save($scope); + + $this->repository->add($scope); + return true; }); - return $res; } - /** - * sets api scope status (active/deactivated) - * @param \oauth2\services\id $id - * @param bool $status - * @throws \oauth2\exceptions\InvalidApiScope + * @param int $id + * @param bool $active + * @return bool + * @throws EntityNotFoundException */ public function setStatus($id, $active) { - $scope = ApiScope::find($id); - if (is_null($scope)) { - throw new InvalidApiScope(sprintf('scope id %s does not exists!', $id)); - } + return $this->tx_service->transaction(function() use($id, $active){ + //check that scope exists... + $scope = $this->repository->get($id); + if (is_null($scope)) { + throw new EntityNotFoundException(sprintf('scope id %s does not exists!', $id)); + } + $scope->active = $active; + $this->repository->add($scope); + return true; + }); - return $scope->update(array('active' => $active)); } /** - * deletes an api scope - * @param $id id of api scope + * @param int $id * @return bool + * @throws EntityNotFoundException */ public function delete($id) { - $res = false; - $this->tx_service->transaction(function () use ($id, &$res) { - - $scope = ApiScope::find($id); + return $this->tx_service->transaction(function () use ($id) { + $scope = $this->repository->get($id); if (is_null($scope)) { - throw new InvalidApiScope(sprintf('scope id %s does not exists!', $id)); + throw new EntityNotFoundException(sprintf('scope id %s does not exists!', $id)); } - - $res = $scope->delete(); + $this->repository->delete($scope); + return true; }); - - return $res; } /** @@ -239,7 +225,7 @@ final class ApiScopeService implements IApiScopeService * @param $system * @param $api_id * @param $assigned_by_groups - * @throws \oauth2\exceptions\InvalidApi + * @throws InvalidApi * @return IApiScope */ public function add($name, $short_description, $description, $active, $default, $system, $api_id, $assigned_by_groups) @@ -257,16 +243,18 @@ final class ApiScopeService implements IApiScopeService &$instance ) { + $api = $this->api_repository->get($api_id); // check if api exists... - if (is_null(Api::find($api_id))) { + if (is_null($api)) { throw new InvalidApi(sprintf('api id %s does not exists!.', $api_id)); } + $former_scopes = $this->repository->getByName([$name]); //check if we have a former scope with selected name - if (ApiScope::where('name', '=', $name)->count() > 0) { + if ($former_scopes->count() > 0) { throw new InvalidApiScope(sprintf('scope name %s not allowed.', $name)); } - + // todo : move to factory $instance = new ApiScope ( array @@ -282,39 +270,23 @@ final class ApiScopeService implements IApiScopeService ) ); - $instance->Save(); + $this->repository->add($instance); }); return $instance; } - /** - * @return mixed - */ - public function getDefaultScopes() - { - return $scopes = ApiScope::where('default', '=', true)->where('active', '=', true)->get(array('id')); - } - /** * @return mixed */ public function getAssignedByGroups() { - $scopes = ApiScope - ::with('api') - ->with('api.resource_server') - ->where('active', '=', true) - ->where('assigned_by_groups', '=', true) - ->orderBy('api_id')->get(); - - $res = array(); - - foreach ($scopes as $scope) + $res = []; + foreach ($this->repository->getAssignableByGroups() as $scope) { $api = $scope->api()->first(); if (!is_null($api) && $api->resource_server()->first()->active && $api->active) { - array_push($res, $scope); + $res[] = $scope; } } diff --git a/app/Services/OAuth2/ApiService.php b/app/Services/OAuth2/ApiService.php new file mode 100644 index 00000000..863e52ce --- /dev/null +++ b/app/Services/OAuth2/ApiService.php @@ -0,0 +1,164 @@ +repository = $repository; + $this->tx_service = $tx_service; + } + + /** + * @param int $id + * @return bool + * @throws EntityNotFoundException + */ + public function delete($id) + { + + return $this->tx_service->transaction(function () use ($id) { + $api = $this->repository->get($id); + if(is_null($api)) throw new EntityNotFoundException(); + $this->repository->delete($api); + return true; + }); + + } + + /** + * @param $name + * @param $description + * @param $active + * @param $resource_server_id + * @return null|IApi + */ + public function add($name, $description, $active, $resource_server_id) + { + + if(is_string($active)){ + $active = strtoupper($active) == 'TRUE' ? true : false; + } + + return $this->tx_service->transaction(function () use ($name, $description, $active, $resource_server_id ) { + + $former_api = $this->repository->getByNameAndResourceServer($name, $resource_server_id); + if(!is_null($former_api)) + throw new InvalidApi(sprintf('api name %s already exists!',$name)); + // todo : move to factory + $instance = new Api( + [ + 'name' => $name, + 'description' => $description, + 'active' => $active, + 'resource_server_id' => $resource_server_id + ] + ); + + $this->repository->add($instance); + + return $instance; + }); + + } + + /** + * @param $id + * @param array $params + * @return bool + * @throws EntityNotFoundException + * @throws InvalidApi + */ + public function update($id, array $params){ + + + return $this->tx_service->transaction(function () use ($id,$params) { + + $api = $this->repository->get($id); + if(is_null($api)) + throw new EntityNotFoundException(sprintf('api id %s does not exists!', $id)); + + $allowed_update_params = ['name','description','active']; + foreach($allowed_update_params as $param){ + if(array_key_exists($param,$params)){ + + if($param=='name'){ + $former_api = $this->repository->getByNameAndResourceServer($params[$param], $api->resource_server_id); + if(!is_null($former_api) && $former_api->id != $id ) + throw new InvalidApi(sprintf('api name %s already exists!', $params[$param])); + } + + $api->{$param} = $params[$param]; + } + } + + $this->repository->add($api); + return true; + }); + + } + + /** + * @param int $id + * @param bool $active + * @return bool + * @throws EntityNotFoundException + */ + public function setStatus($id, $active) + { + return $this->tx_service->transaction(function() use($id, $active){ + + $api = $this->repository->get($id); + + if(is_null($api)) + throw new EntityNotFoundException(sprintf('api id %s does not exists!', $id)); + + $api->active = $active; + + $this->repository->add($api); + + return true; + }); + } +} \ No newline at end of file diff --git a/app/services/oauth2/AssymetricKeyService.php b/app/Services/OAuth2/AsymmetricKeyService.php similarity index 85% rename from app/services/oauth2/AssymetricKeyService.php rename to app/Services/OAuth2/AsymmetricKeyService.php index 28b9c28b..e876a938 100644 --- a/app/services/oauth2/AssymetricKeyService.php +++ b/app/Services/OAuth2/AsymmetricKeyService.php @@ -1,6 +1,6 @@ -tx_service = $tx_service; @@ -41,7 +42,7 @@ abstract class AssymetricKeyService /** * @param array $params - * @return IAssymetricKey + * @return IAsymmetricKey */ abstract public function register(array $params); @@ -82,8 +83,6 @@ abstract class AssymetricKeyService return false; } - $owner_id = $key->oauth2_client_id; - $key_active = $repository->getActiveByCriteria($key->getType(), $key->getUse(), $key->getAlg()->getName()); if($key_active && $params['active'] === true) @@ -108,5 +107,4 @@ abstract class AssymetricKeyService }); } - } \ No newline at end of file diff --git a/app/services/oauth2/ClientCrendentialGenerator.php b/app/Services/OAuth2/ClientCredentialGenerator.php similarity index 60% rename from app/services/oauth2/ClientCrendentialGenerator.php rename to app/Services/OAuth2/ClientCredentialGenerator.php index 9d2801c6..c9999813 100644 --- a/app/services/oauth2/ClientCrendentialGenerator.php +++ b/app/Services/OAuth2/ClientCredentialGenerator.php @@ -1,6 +1,6 @@ -client_id = Rand::getString(32, OAuth2Protocol::VsChar, true) . '.openstack.client'; + $client->client_id = Rand::getString(32, OAuth2Protocol::VsChar, true) . IClientCredentialGenerator::ClientSuffix; if ($client->client_type === IClient::ClientType_Confidential) { - $now = new \DateTime(); - $client->client_secret = Rand::getString(64, OAuth2Protocol::VsChar, true); + $now = new DateTime(); + $client->client_secret = Rand::getString(64, OAuth2Protocol::VsChar, true); // default 6 months - $client->client_secret_expires_at = $now->add( new \DateInterval('P6M')); + $client->client_secret_expires_at = $now->add( new DateInterval('P6M')); } return $client; } diff --git a/app/services/oauth2/ClienPublicKeyService.php b/app/Services/OAuth2/ClientPublicKeyService.php similarity index 58% rename from app/services/oauth2/ClienPublicKeyService.php rename to app/Services/OAuth2/ClientPublicKeyService.php index a3487c64..8e3fbff7 100644 --- a/app/services/oauth2/ClienPublicKeyService.php +++ b/app/Services/OAuth2/ClientPublicKeyService.php @@ -1,34 +1,32 @@ -client_repository = $client_repository; $this->auth_service = $auth_service; - parent::__construct($repository, $tx_service); + } /** * @param array $params - * @return IAssymetricKey + * @return IAsymmetricKey */ public function register(array $params) { $client_repository = $this->client_repository; $repository = $this->repository; $auth_service = $this->auth_service; + return $this->tx_service->transaction(function() use($params, $repository, $client_repository, $auth_service) { @@ -86,8 +94,8 @@ final class ClienPublicKeyService extends AssymetricKeyService implements IClien ->where('type','=', $params['type']) ->where('usage','=', $params['usage']) ->where('alg','=', $params['alg']) - ->where('valid_from','<=',new \DateTime($params['valid_to'])) - ->where('valid_to','>=', new \DateTime($params['valid_from'])) + ->where('valid_from','<=',new DateTime($params['valid_to'])) + ->where('valid_to','>=', new DateTime($params['valid_from'])) ->first(); $public_key = ClientPublicKey::buildFromPEM @@ -98,8 +106,8 @@ final class ClienPublicKeyService extends AssymetricKeyService implements IClien $params['pem_content'], $params['alg'], $old_key_active ? false : $params['active'], - new \DateTime($params['valid_from']), - new \DateTime($params['valid_to']) + new DateTime($params['valid_from']), + new DateTime($params['valid_to']) ); $client->addPublicKey($public_key); diff --git a/app/services/oauth2/ClientService.php b/app/Services/OAuth2/ClientService.php similarity index 60% rename from app/services/oauth2/ClientService.php rename to app/Services/OAuth2/ClientService.php index 31fc78bd..ff98014f 100644 --- a/app/services/oauth2/ClientService.php +++ b/app/Services/OAuth2/ClientService.php @@ -1,39 +1,48 @@ -auth_service = $auth_service; - $this->user_repository = $user_repository; + $this->user_repository = $user_repository; $this->scope_service = $scope_service; $this->client_credential_generator = $client_credential_generator; $this->client_repository = $client_repository; + $this->scope_repository = $scope_repository; $this->client_factory = $client_factory; $this->tx_service = $tx_service; } @@ -93,8 +119,8 @@ class ClientService implements IClientService * 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 - * implementation of http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication + * implementation of @see http://tools.ietf.org/html/rfc6749#section-2.3.1 + * implementation of @see http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication * @throws InvalidClientAuthMethodException * @throws MissingClientAuthorizationInfo * @return ClientAuthenticationContext @@ -166,15 +192,16 @@ class ClientService implements IClientService * @param array $admin_users * @param string $app_logo * @return IClient + * @throws ValidationException */ - public function addClient + public function register ( $application_type, $app_name, $app_description, - $app_url = null, - array $admin_users = array(), - $app_logo = '' + $app_url = null, + array $admin_users = [], + $app_logo = '' ) { $scope_service = $this->scope_service; @@ -199,17 +226,21 @@ class ClientService implements IClientService $client_credential_generator ) { - $client = $client_factory->build($app_name,$current_user, $application_type); + if($this->client_repository->getByApplicationName($app_name) != null){ + throw new ValidationException('there is already another application with that name, please choose another one.'); + } + + $client = $client_factory->build($app_name, $current_user, $application_type); $client = $client_credential_generator->generate($client); $client->app_logo = $app_logo; $client->app_description = $app_description; $client->website = $app_url; + $client_repository->add($client); //add default scopes - $default_scopes = $scope_service->getDefaultScopes(); - foreach ($default_scopes as $default_scope) { + foreach ($this->scope_repository->getDefaults() as $default_scope) { if ( $default_scope->name === OAuth2Protocol::OfflineAccess_Scope && @@ -237,36 +268,35 @@ class ClientService implements IClientService /** - * @param $id + * @param int $id * @param array $params - * @throws AbsentClientException - * @throws \ValidationException - * @return mixed + * @throws ValidationException + * @throws EntityNotFoundException + * @return IClient */ public function update($id, array $params) { - $this_var = $this; $client_repository = $this->client_repository; $user_repository = $this->user_repository; $editing_user = $this->auth_service->getCurrentUser(); - return $this->tx_service->transaction(function () use ($id, $editing_user, $params, $client_repository, $user_repository, &$this_var) { + return $this->tx_service->transaction(function () use ($id, $editing_user, $params, $client_repository, $user_repository) { $client = $client_repository->get($id); if (is_null($client)) { - throw new AbsentClientException(sprintf('client id %s does not exists.', $id)); + throw new EntityNotFoundException(sprintf('client id %s does not exists.', $id)); } $app_name = isset($params['app_name']) ? trim($params['app_name']) : null; if(!empty($app_name)) { $old_client = $client_repository->getByApplicationName($app_name); if(!is_null($old_client) && $old_client->id !== $client->id) - throw new \ValidationException('there is already another application with that name, please choose another one.'); + throw new ValidationException('there is already another application with that name, please choose another one.'); } $current_app_type = $client->getApplicationType(); if($current_app_type !== $params['application_type']) { - throw new \ValidationException('application type does not match.'); + throw new ValidationException('application type does not match.'); } // validate uris @@ -280,18 +310,18 @@ class ClientService implements IClientService foreach ($redirect_uris as $uri) { $uri = @parse_url($uri); if (!isset($uri['scheme'])) { - throw new \ValidationException('invalid scheme on redirect uri.'); + throw new ValidationException('invalid scheme on redirect uri.'); } if (HttpUtils::isCustomSchema($uri['scheme'])) { $already_has_schema_registered = Client::where('redirect_uris', 'like', '%' . $uri['scheme'] . '://%')->where('id', '<>', $id)->count(); if ($already_has_schema_registered > 0) { - throw new \ValidationException(sprintf('schema %s:// already registered for another client.', + throw new ValidationException(sprintf('schema %s:// already registered for another client.', $uri['scheme'])); } } else { if (!HttpUtils::isHttpSchema($uri['scheme'])) { - throw new \ValidationException(sprintf('scheme %s:// is invalid.', + throw new ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); } } @@ -308,10 +338,10 @@ class ClientService implements IClientService foreach ($redirect_uris as $uri) { $uri = @parse_url($uri); if (!isset($uri['scheme'])) { - throw new \ValidationException('invalid scheme on redirect uri.'); + throw new ValidationException('invalid scheme on redirect uri.'); } if (!HttpUtils::isHttpsSchema($uri['scheme'])) { - throw new \ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); + throw new ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); } } } @@ -321,10 +351,10 @@ class ClientService implements IClientService foreach ($allowed_origins as $uri) { $uri = @parse_url($uri); if (!isset($uri['scheme'])) { - throw new \ValidationException('invalid scheme on allowed origin uri.'); + throw new ValidationException('invalid scheme on allowed origin uri.'); } if (!HttpUtils::isHttpsSchema($uri['scheme'])) { - throw new \ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); + throw new ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); } } } @@ -422,66 +452,90 @@ class ClientService implements IClientService }); } + /** + * @param int $id + * @param int $scope_id + * @return IClient + * @throws EntityNotFoundException + */ public function addClientScope($id, $scope_id) { - $client = Client::find($id); - if (is_null($client)) { - throw new EntityNotFoundException(sprintf("client id %s not found!.", $id)); - } - $scope = $this->scope_service->get(intval($scope_id)); - if(is_null($scope)) throw new EntityNotFoundException(sprintf("scope %s not found!.", $scope_id)); - $user = $client->user()->first(); - - if($scope->isAssignableByGroups()) { - - $allowed = false; - foreach($user->getGroupScopes() as $group_scope) - { - if(intval($group_scope->id) === intval($scope_id)) - { - $allowed = true; break; - } + return $this->tx_service->transaction(function() use ($id, $scope_id){ + $client = $this->client_repository->get($id); + if (is_null($client)) { + throw new EntityNotFoundException(sprintf("client id %s not found!.", $id)); } - if(!$allowed) throw new InvalidApiScope(sprintf('you cant assign to this client api scope %s', $scope_id)); - } - if($scope->isSystem() && !$user->canUseSystemScopes()) - throw new InvalidApiScope(sprintf('you cant assign to this client api scope %s', $scope_id)); - $client->scopes()->attach($scope_id); - $client->setEditedBy($this->auth_service->getCurrentUser()); - $client->save(); - return $client; + $scope = $this->scope_repository->get(intval($scope_id)); + if(is_null($scope)) throw new EntityNotFoundException(sprintf("scope %s not found!.", $scope_id)); + $user = $client->user()->first(); + + if($scope->isAssignableByGroups()) { + + $allowed = false; + foreach($user->getGroupScopes() as $group_scope) + { + if(intval($group_scope->id) === intval($scope_id)) + { + $allowed = true; break; + } + } + if(!$allowed) throw new InvalidApiScope(sprintf('you cant assign to this client api scope %s', $scope_id)); + } + if($scope->isSystem() && !$user->canUseSystemScopes()) + throw new InvalidApiScope(sprintf('you cant assign to this client api scope %s', $scope_id)); + $client->scopes()->attach($scope_id); + $client->setEditedBy($this->auth_service->getCurrentUser()); + + $this->client_repository->add($client); + return $client; + }); } + /** + * @param $id + * @param $scope_id + * @return IClient + * @throws EntityNotFoundException + */ 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)); - } - $client->scopes()->detach($scope_id); - $client->setEditedBy($this->auth_service->getCurrentUser()); - $client->save(); - return $client; + return $this->tx_service->transaction(function() use ($id, $scope_id){ + $client = $this->client_repository->get($id); + if (is_null($client)) { + throw new EntityNotFoundException(sprintf("client id %s does not exists!", $id)); + } + $client->scopes()->detach($scope_id); + $client->setEditedBy($this->auth_service->getCurrentUser()); + $this->client_repository->add($client); + return $client; + }); + } + /** + * @param int $id + * @return bool + * @throws EntityNotFoundException + */ public function deleteClientByIdentifier($id) { - $res = false; - $this->tx_service->transaction(function () use ($id, &$res) { - $client = Client::find($id); - if (!is_null($client)) { - $client->scopes()->detach(); - Event::fire('oauth2.client.delete', array($client->client_id)); - $res = $client->delete(); + return $this->tx_service->transaction(function () use ($id) { + $client = $this->client_repository->get($id); + if (is_null($client)) { + throw new EntityNotFoundException(sprintf("client id %s does not exists!", $id)); } + $client->scopes()->detach(); + Event::fire('oauth2.client.delete', array($client->client_id)); + $this->client_repository->delete($client); + true; }); - return $res; } /** * Regenerates Client Secret * @param $id client id * @return IClient + * @throws EntityNotFoundException */ public function regenerateClientSecret($id) { @@ -491,11 +545,11 @@ class ClientService implements IClientService return $this->tx_service->transaction(function () use ($id, $current_user, $client_credential_generator) { - $client = Client::find($id); + $client = $this->client_repository->get($id); if (is_null($client)) { - throw new AbsentClientException(sprintf("client id %d does not exists!.", $id)); + throw new EntityNotFoundException(sprintf("client id %d does not exists!.", $id)); } if ($client->client_type != IClient::ClientType_Confidential) @@ -512,7 +566,7 @@ class ClientService implements IClientService $client = $client_credential_generator->generate($client, true); $client->setEditedBy($current_user); - $client->save(); + $this->client_repository->add($client); Event::fire('oauth2.client.regenerate.secret', array($client->client_id)); return $client; @@ -522,136 +576,104 @@ class ClientService implements IClientService /** * @param client $client_id * @return mixed - * @throws \oauth2\exceptions\AbsentClientException + * @throws EntityNotFoundException */ public function lockClient($client_id) { - $res = false; - $this_var = $this; + return $this->tx_service->transaction(function () use ($client_id) { - $this->tx_service->transaction(function () use ($client_id, &$res, &$this_var) { - - $client = $this_var->getClientByIdentifier($client_id); + $client = $this->client_repository($client_id); if (is_null($client)) { - throw new AbsentClientException($client_id, sprintf("client id %s does not exists!", $client_id)); + throw new EntityNotFoundException($client_id, sprintf("client id %s does not exists!", $client_id)); } $client->locked = true; - $res = $client->Save(); + $this->client_repository->update($client); + return true; }); - return $res; } /** - * @param client $client_id - * @return mixed - * @throws \oauth2\exceptions\AbsentClientException + * @param int $id + * @return bool + * @throws EntityNotFoundException */ - public function unlockClient($client_id) + public function unlockClient($id) { - $res = false; - $this_var = $this; + return $this->tx_service->transaction(function () use ($id) { - $this->tx_service->transaction(function () use ($client_id, &$res, &$this_var) { - - $client = $this_var->getClientByIdentifier($client_id); + $client = $this->client_repository->getClientByIdentifier($id); if (is_null($client)) { - throw new AbsentClientException($client_id, sprintf("client id %s does not exists!", $client_id)); + throw new EntityNotFoundException($id, sprintf("client id %s does not exists!", $id)); } $client->locked = false; - $res = $client->Save(); + $this->client_repository->update($client); + return true; }); - return $res; } /** - * @param $client_id - * @return IClient + * @param int $id + * @param bool $active + * @return bool + * @throws EntityNotFoundException */ - 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; + return $this->tx_service->transaction(function () use ($id, $active) { + + $client = $this->client_repository->getClientByIdentifier($id); + if (is_null($client)) { + throw new EntityNotFoundException($id, sprintf("client id %s does not exists!", $id)); + } + $client->active = $active; + $this->client_repository->update($client); + return true; + }); } + /** + * @param int $id + * @param bool $use_refresh_token + * @return bool + * @throws EntityNotFoundException + */ 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; - $client->setEditedBy($this->auth_service->getCurrentUser()); - return $client->Save(); + return $this->tx_service->transaction(function () use ($id, $use_refresh_token) { + + $client = $this->client_repository->getClientByIdentifier($id); + if (is_null($client)) { + throw new EntityNotFoundException($id, sprintf("client id %s does not exists!", $id)); + } + $client->use_refresh_token = $use_refresh_token; + $client->setEditedBy($this->auth_service->getCurrentUser()); + $this->client_repository->update($client); + return true; + }); } + /** + * @param int $id + * @param bool $rotate_refresh_token + * @return bool + * @throws EntityNotFoundException + */ 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)); - } + return $this->tx_service->transaction(function () use ($id, $rotate_refresh_token) { - $client->rotate_refresh_token = $rotate_refresh_token; - $client->setEditedBy($this->auth_service->getCurrentUser()); - return $client->Save(); - } + $client = $this->client_repository->getClientByIdentifier($id); + if (is_null($client)) { + throw new EntityNotFoundException($id, sprintf("client id %s does not exists!", $id)); + } - 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 string $origin - * @return IClient - */ - public function getByOrigin($origin) - { - return Client::where('allowed_origins', 'like', '%'.$origin.'%')->first(); + $client->rotate_refresh_token = $rotate_refresh_token; + $client->setEditedBy($this->auth_service->getCurrentUser()); + $this->client_repository->update($client); + return true; + }); } } \ No newline at end of file diff --git a/app/Services/OAuth2/HttpIClientJWKSetReader.php b/app/Services/OAuth2/HttpIClientJWKSetReader.php new file mode 100644 index 00000000..7edafae7 --- /dev/null +++ b/app/Services/OAuth2/HttpIClientJWKSetReader.php @@ -0,0 +1,60 @@ +getJWKSUri(); + if (empty($jwk_set_uri)) return null; + + $client = new HttpClient([ + 'defaults' => [ + 'timeout' => Config::get('curl.timeout', 60), + 'allow_redirects' => Config::get('curl.allow_redirects', false), + 'verify' => Config::get('curl.verify_ssl_cert', true) + ] + ]); + + $response = $client->get($jwk_set_uri); + if ($response->getStatusCode() !== 200) return null; + $content_type = $response->getHeader('content-type'); + if (is_null($content_type)) return null; + if (!$content_type->hasValue(HttpContentType::Json)) return null; + return JWKSet::fromJson($response->getBody()); + } + catch (HttpRequestException $ex) + { + Log::warning($ex->getMessage()); + return null; + } + } +} \ No newline at end of file diff --git a/app/services/oauth2/IdTokenBuilderImpl.php b/app/Services/OAuth2/IdTokenBuilderImpl.php similarity index 82% rename from app/services/oauth2/IdTokenBuilderImpl.php rename to app/Services/OAuth2/IdTokenBuilderImpl.php index f52ef39e..b55ba0ef 100644 --- a/app/services/oauth2/IdTokenBuilderImpl.php +++ b/app/Services/OAuth2/IdTokenBuilderImpl.php @@ -1,6 +1,6 @@ -user_service = $user_service; $this->configuration_service = $configuration_service; - $this->client_service = $client_service; + $this->client_repository = $client_repository; $this->auth_service = $auth_service; + $this->user_repository = $user_repository; } /** @@ -74,14 +102,16 @@ class UserService extends OAuth2ProtectedService implements IUserService try { - $me = $this->resource_server_context->getCurrentUserId(); + $current_user_id = $this->resource_server_context->getCurrentUserId(); - if (is_null($me)) { + if (is_null($current_user_id)) { throw new Exception('me is no set!.'); } - $current_user = $this->user_service->get($me); - $scopes = $this->resource_server_context->getCurrentScope(); + $current_user = $this->user_repository->get($current_user_id); + if(is_null($current_user)) throw new EntityNotFoundException(); + + $scopes = $this->resource_server_context->getCurrentScope(); if (in_array(self::UserProfileScope_Address, $scopes)) { // Address Claims @@ -94,8 +124,8 @@ class UserService extends OAuth2ProtectedService implements IUserService if (in_array(self::UserProfileScope_Profile, $scopes)) { // Profile Claims $assets_url = $this->configuration_service->getConfigValue('Assets.Url'); - $pic_url = $current_user->getPic(); - $pic_url = str_contains($pic_url, 'http') ? $pic_url : $assets_url . $pic_url; + $pic_url = $current_user->getPic(); + $pic_url = str_contains($pic_url, 'http') ? $pic_url : $assets_url . $pic_url; $data[StandardClaims::Name] = $current_user->getFullName(); $data[StandardClaims::GivenName] = $current_user->getFirstName(); @@ -127,16 +157,17 @@ class UserService extends OAuth2ProtectedService implements IUserService try { - $me = $this->resource_server_context->getCurrentUserId(); - $client_id = $this->resource_server_context->getCurrentClientId(); - $client = $this->client_service->getClientById($client_id); + $current_user_id = $this->resource_server_context->getCurrentUserId(); + $client_id = $this->resource_server_context->getCurrentClientId(); + $client = $this->client_repository->getClientById($client_id); - if (is_null($me)) + if (is_null($current_user_id)) { throw new Exception('me is no set!.'); } - $current_user = $this->user_service->get($me); + $current_user = $this->user_repository->get($current_user_id); + if(is_null($current_user)) throw new EntityNotFoundException(); $scopes = $this->resource_server_context->getCurrentScope(); $claim_set = new JWTClaimSet @@ -171,8 +202,8 @@ class UserService extends OAuth2ProtectedService implements IUserService { // Profile Claims $assets_url = $this->configuration_service->getConfigValue('Assets.Url'); - $pic_url = $current_user->getPic(); - $pic_url = str_contains($pic_url, 'http') ? $pic_url : $assets_url . $pic_url; + $pic_url = $current_user->getPic(); + $pic_url = str_contains($pic_url, 'http') ? $pic_url : $assets_url . $pic_url; $claim_set->addClaim(new JWTClaim(StandardClaims::Name, new StringOrURI($current_user->getFullName()))); $claim_set->addClaim(new JWTClaim(StandardClaims::GivenName, new StringOrURI($current_user->getFirstName()))); diff --git a/app/services/oauth2/ResourceServerContext.php b/app/Services/OAuth2/ResourceServerContext.php similarity index 57% rename from app/services/oauth2/ResourceServerContext.php rename to app/Services/OAuth2/ResourceServerContext.php index 84bc537c..56995d33 100644 --- a/app/services/oauth2/ResourceServerContext.php +++ b/app/Services/OAuth2/ResourceServerContext.php @@ -1,15 +1,28 @@ -auth_context = $auth_context; + return $this; } } \ No newline at end of file diff --git a/app/Services/OAuth2/ResourceServerService.php b/app/Services/OAuth2/ResourceServerService.php new file mode 100644 index 00000000..f8aef983 --- /dev/null +++ b/app/Services/OAuth2/ResourceServerService.php @@ -0,0 +1,278 @@ +client_service = $client_service; + $this->repository = $repository; + $this->client_repository = $client_repository; + $this->tx_service = $tx_service; + } + + /** + * @param string $host + * @param string $ips + * @param string $friendly_name + * @param bool $active + * @return IResourceServer + * @throws InvalidResourceServer + */ + public function add($host, $ips, $friendly_name, $active) + { + + $client_service = $this->client_service; + + if (is_string($active)) { + $active = strtoupper($active) == 'TRUE' ? true : false; + } + + return $this->tx_service->transaction(function () use ( + $host, + $ips, + $friendly_name, + $active, + $client_service + ) { + + if ($this->repository->getByHost($host) != null) { + throw new InvalidResourceServer + ( + sprintf('there is already another resource server with that hostname (%s).',$host) + ); + } + + if ($this->repository->getByIp($ips) != null) { + throw new InvalidResourceServer + ( + sprintf('there is already another resource server with that ip (%s).', $ips) + ); + } + + if ($this->repository->getByFriendlyName($friendly_name) != null) { + throw new InvalidResourceServer + ( + sprintf('there is already another resource server with that friendly name (%s).', $friendly_name) + ); + } + + // todo : move to factory + $instance = new ResourceServer + ( + [ + 'host' => $host, + 'ips' => $ips, + 'active' => $active, + 'friendly_name' => $friendly_name + ] + ); + + $this->repository->add($instance); + + // creates a new client for this brand new resource server + $new_client = $client_service->register + ( + IClient::ApplicationType_Service, + $host . '.confidential.application', + $friendly_name . ' confidential oauth2 application' + ); + + $new_client->resource_server()->associate($instance); + // does not expires ... + $new_client->client_secret_expires_at = null; + $this->client_repository->add($new_client); + return $instance; + }); + + } + + /** + * @param int $id + * @param array $params + * @return bool + * @throws InvalidResourceServer + * @throws EntityNotFoundException + */ + public function update($id, array $params) + { + + + return $this->tx_service->transaction(function () use ($id, $params) { + + $resource_server = $this->repository->get($id); + + if (is_null($resource_server)) { + throw new EntityNotFoundException(sprintf('resource server id %s does not exists!', $id)); + } + + $allowed_update_params = array('host', 'ips', 'active', 'friendly_name'); + + foreach ($allowed_update_params as $param) { + if (array_key_exists($param, $params)) { + + if ($param == 'host') { + $former_resource_server = $this->repository->getByHost($params[$param]); + if (!is_null($former_resource_server) && $former_resource_server->id != $id) { + throw new InvalidResourceServer + ( + sprintf('there is already another resource server with that hostname (%s).',$params[$param]) + ); + } + } + + if ($param == 'friendly_name') { + $former_resource_server = $this->repository->getByFriendlyName($params[$param]); + if (!is_null($former_resource_server) && $former_resource_server->id != $id) { + throw new InvalidResourceServer + ( + sprintf('there is already another resource server with that friendly name (%s).', $params[$param]) + ); + } + } + + $resource_server->{$param} = $params[$param]; + } + } + $this->repository->add($resource_server); + return true; + }); + } + + + /** + * @param int $id + * @param bool $active + * @return bool + * @throws EntityNotFoundException + */ + public function setStatus($id, $active) + { + return $this->tx_service->transaction(function () use ($id, $active) { + $resource_server = $this->repository->get($id); + + if (is_null($resource_server)) { + throw new EntityNotFoundException(sprintf('resource server id %s does not exists!', $id)); + } + $resource_server->active = $active; + $this->repository->add($resource_server); + return true; + }); + } + + /** + * @param int $id + * @return bool + * @throws EntityNotFoundException + */ + public function delete($id) + { + + + return $this->tx_service->transaction(function () use ($id) { + + $resource_server = $this->repository->get($id); + + if (is_null($resource_server)) { + throw new EntityNotFoundException(sprintf('resource server id %s does not exists!', $id)); + } + + $client = $resource_server->client()->first(); + if (!is_null($client)) { + $this->client_repository->delete($client); + } + + $this->repository->delete($resource_server); + return true; + }); + + } + + /** + * @param int $id + * @return string + * @throws EntityNotFoundException + */ + public function regenerateClientSecret($id) + { + + return $this->tx_service->transaction(function () use ($id) { + + $resource_server = $this->repository->get($id); + + if (is_null($resource_server)) { + throw new EntityNotFoundException(sprintf('resource server id %s does not exists!', $id)); + } + + $client = $resource_server->client()->first(); + if (is_null($client)) + throw new EntityNotFoundException(sprintf('client not found for resource server id %s!', $id)); + + $client = $this->client_service->regenerateClientSecret($client->id); + + return $client->getClientSecret(); + + }); + } + +} diff --git a/app/services/oauth2/SecurityContextService.php b/app/Services/OAuth2/SecurityContextService.php similarity index 86% rename from app/services/oauth2/SecurityContextService.php rename to app/Services/OAuth2/SecurityContextService.php index 362df5b1..7803d3e5 100644 --- a/app/services/oauth2/SecurityContextService.php +++ b/app/Services/OAuth2/SecurityContextService.php @@ -1,6 +1,6 @@ -getRequestedUserId()); Session::put(self::RequestedAuthTime, $security_context->isAuthTimeRequired()); Session::save(); + return $this; } /** @@ -66,5 +64,6 @@ final class SecurityContextService implements ISecurityContextService Session::remove(self::RequestedUserIdParam); Session::remove(self::RequestedAuthTime); Session::save(); + return $this; } } \ No newline at end of file diff --git a/app/services/oauth2/ServerPrivateKeyService.php b/app/Services/OAuth2/ServerPrivateKeyService.php similarity index 69% rename from app/services/oauth2/ServerPrivateKeyService.php rename to app/Services/OAuth2/ServerPrivateKeyService.php index 94ca4df4..fd84d73e 100644 --- a/app/services/oauth2/ServerPrivateKeyService.php +++ b/app/Services/OAuth2/ServerPrivateKeyService.php @@ -1,6 +1,6 @@ -tx_service->transaction(function() use($params, $rsa, $repository) { - $pem = isset($params['pem_content']) ? $params['pem_content'] : ''; - $password = $params['password']; + $pem = isset($params['pem_content']) ? trim($params['pem_content']) : ''; + $password = isset($params['password'])? trim($params['password']) : ''; $old_active_key = $repository->getByValidityRange ( $params['type'], $params['usage'], $params['alg'], - new \DateTime($params['valid_from']), - new \DateTime($params['valid_to']) + new DateTime($params['valid_from']), + new DateTime($params['valid_to']) )->first(); - if(empty($pem)) { if(!empty($password)) @@ -86,12 +87,11 @@ final class ServerPrivateKeyService extends AssymetricKeyService implements ISer $pem = $res['privatekey']; } - $key = ServerPrivateKey::build ( $params['kid'], - new \DateTime($params['valid_from']), - new \DateTime($params['valid_to']), + new DateTime($params['valid_from']), + new DateTime($params['valid_to']), $params['type'], $params['usage'], $params['alg'], diff --git a/app/services/oauth2/TokenService.php b/app/Services/OAuth2/TokenService.php similarity index 71% rename from app/services/oauth2/TokenService.php rename to app/Services/OAuth2/TokenService.php index 1aca01cd..5ae5b17d 100644 --- a/app/services/oauth2/TokenService.php +++ b/app/Services/OAuth2/TokenService.php @@ -1,6 +1,6 @@ -security_context_service = $security_context_service; $this->principal_service = $principal_service; $this->id_token_builder = $id_token_builder; + $this->client_repository = $client_repository; + $this->access_token_repository = $access_token_repository; + $this->refresh_token_repository = $refresh_token_repository; + $this->resource_server_repository = $resource_server_repository; $this->tx_service = $tx_service; - $this_var = $this; - - Event::listen('oauth2.client.delete', function ($client_id) use (&$this_var) { - $this_var->revokeClientRelatedTokens($client_id); + Event::listen('oauth2.client.delete', function ($client_id) { + $this->revokeClientRelatedTokens($client_id); }); - Event::listen('oauth2.client.regenerate.secret', function ($client_id) use (&$this_var) { - $this_var->revokeClientRelatedTokens($client_id); + Event::listen('oauth2.client.regenerate.secret', function ($client_id) { + $this->revokeClientRelatedTokens($client_id); }); } @@ -314,8 +321,8 @@ final class TokenService implements ITokenService /** * @param $value * @return AuthorizationCode - * @throws \oauth2\exceptions\ReplayAttackException - * @throws \oauth2\exceptions\InvalidAuthorizationCodeException + * @throws ReplayAttackException + * @throws InvalidAuthorizationCodeException */ public function getAuthorizationCode($value) { @@ -408,10 +415,11 @@ final class TokenService implements ITokenService ) ); - $cache_service = $this->cache_service; - $client_service = $this->client_service; - $auth_service = $this->auth_service; - $this_var = $this; + $cache_service = $this->cache_service; + $client_service = $this->client_service; + $auth_service = $this->auth_service; + $client_repository = $this->client_repository; + $access_token_repository = $this->access_token_repository; return $this->tx_service->transaction(function () use ( $auth_code, @@ -420,7 +428,8 @@ final class TokenService implements ITokenService $cache_service, $client_service, $auth_service, - $this_var + $client_repository, + $access_token_repository ) { $value = $access_token->getValue(); @@ -428,27 +437,29 @@ final class TokenService implements ITokenService //oauth2 client id $client_id = $access_token->getClientId(); $user_id = $access_token->getUserId(); - $client = $client_service->getClientById($client_id); + $client = $client_repository->getClientById($client_id); $user = $auth_service->getUserById($user_id); - $access_token_db = new DBAccessToken + // TODO; move to a factory + + $access_token_db = new AccessTokenDB ( - array - ( - 'value' => $hashed_value, - 'from_ip' => IPHelper::getUserIp(), + [ + 'value' => $hashed_value, + 'from_ip' => IPHelper::getUserIp(), 'associated_authorization_code' => Hash::compute('sha256', $auth_code->getValue()), - 'lifetime' => $access_token->getLifetime(), - 'scope' => $access_token->getScope(), - 'audience' => $access_token->getAudience() - ) + 'lifetime' => $access_token->getLifetime(), + 'scope' => $access_token->getScope(), + 'audience' => $access_token->getAudience() + ] ); $access_token_db->client()->associate($client); $access_token_db->user()->associate($user); - $access_token_db->save(); + $access_token_repository->add($access_token_db); + //check if use refresh tokens... Log::debug ( @@ -490,11 +501,11 @@ final class TokenService implements ITokenService ) { Log::debug('creating refresh token ....'); - $this_var->createRefreshToken($access_token); + $this->createRefreshToken($access_token); } } - $this_var->storesAccessTokenOnCache($access_token); + $this->storesAccessTokenOnCache($access_token); //stores brand new access token hash value on a set by client id... $cache_service->addMemberSet($client_id . TokenService::ClientAccessTokenPrefixList, $hashed_value); @@ -531,41 +542,41 @@ final class TokenService implements ITokenService ) ); - $cache_service = $this->cache_service; - $client_service = $this->client_service; - $auth_service = $this->auth_service; - $this_var = $this; + $cache_service = $this->cache_service; + $client_repository = $this->client_repository; + $auth_service = $this->auth_service; + $access_token_repository = $this->access_token_repository; - $this->tx_service->transaction(function () use ( + return $this->tx_service->transaction(function () use ( $client_id, $scope, $audience, $user_id, - &$access_token, - &$this_var, - &$cache_service, - &$client_service, - &$auth_service + $access_token, + $cache_service, + $client_repository, + $access_token_repository, + $auth_service ) { - $value = $access_token->getValue(); + $value = $access_token->getValue(); $hashed_value = Hash::compute('sha256', $value); - $this_var->storesAccessTokenOnCache($access_token); + $this->storesAccessTokenOnCache($access_token); $client_id = $access_token->getClientId(); - $client = $client_service->getClientById($client_id); + $client = $client_repository->getClientById($client_id); - //stores in DB - $access_token_db = new DBAccessToken( - array( - 'value' => $hashed_value, - 'from_ip' => IPHelper::getUserIp(), + // todo: move to a factory + $access_token_db = new AccessTokenDB( + [ + 'value' => $hashed_value, + 'from_ip' => IPHelper::getUserIp(), 'lifetime' => $access_token->getLifetime(), - 'scope' => $access_token->getScope(), + 'scope' => $access_token->getScope(), 'audience' => $access_token->getAudience() - ) + ] ); $access_token_db->client()->associate($client); @@ -575,16 +586,14 @@ final class TokenService implements ITokenService $access_token_db->user()->associate($user); } - $access_token_db->Save(); + $access_token_repository->add($access_token_db); //stores brand new access token hash value on a set by client id... $cache_service->addMemberSet($client_id . TokenService::ClientAccessTokenPrefixList, $hashed_value); - $cache_service->incCounter($client_id . TokenService::ClientAccessTokensQty, - TokenService::ClientAccessTokensQtyLifetime); - + $cache_service->incCounter($client_id . TokenService::ClientAccessTokensQty, TokenService::ClientAccessTokensQtyLifetime); + return $access_token; }); - return $access_token; } /** @@ -595,30 +604,29 @@ final class TokenService implements ITokenService public function createAccessTokenFromRefreshToken(RefreshToken $refresh_token, $scope = null) { - $cache_service = $this->cache_service; - $client_service = $this->client_service; - $configuration_service = $this->configuration_service; - $auth_service = $this->auth_service; - $access_token_generator = $this->access_token_generator; - $this_var = $this; - + $cache_service = $this->cache_service; + $client_repository = $this->client_repository; + $configuration_service = $this->configuration_service; + $auth_service = $this->auth_service; + $access_token_generator = $this->access_token_generator; + $access_token_repository = $this->access_token_repository; //preserve entire operation on db transaction... return $this->tx_service->transaction(function () use ( $refresh_token, $scope, - $this_var, $cache_service, - $client_service, + $client_repository, $auth_service, $configuration_service, + $access_token_repository, $access_token_generator ) { $refresh_token_value = $refresh_token->getValue(); - $refresh_token_hashed_value = Hash::compute('sha256', $refresh_token_value); + $refresh_token_hashed_value = Hash::compute('sha256', $refresh_token_value); //clear current access tokens as invalid - $this_var->clearAccessTokensForRefreshToken($refresh_token->getValue()); + $this->clearAccessTokensForRefreshToken($refresh_token->getValue()); //validate scope if present... if (!is_null($scope) && empty($scope)) @@ -658,19 +666,19 @@ final class TokenService implements ITokenService ) ); - $value = $access_token->getValue(); + $value = $access_token->getValue(); $hashed_value = Hash::compute('sha256', $value); - $this_var->storesAccessTokenOnCache($access_token); + $this->storesAccessTokenOnCache($access_token); //get user id $user_id = $access_token->getUserId(); //get current client $client_id = $access_token->getClientId(); - $client = $client_service->getClientById($client_id); + $client = $client_repository->getClientById($client_id); - //stores in DB - $access_token_db = new DBAccessToken + //todo : move to a factory + $access_token_db = new AccessTokenDB ( array ( @@ -683,7 +691,7 @@ final class TokenService implements ITokenService ); //save relationships - $refresh_token_db = DBRefreshToken::where('value', '=', $refresh_token_hashed_value)->first(); + $refresh_token_db = $this->refresh_token_repository->getByValue($refresh_token_hashed_value); $access_token_db->refresh_token()->associate($refresh_token_db); $access_token_db->client()->associate($client); @@ -694,7 +702,7 @@ final class TokenService implements ITokenService $access_token_db->user()->associate($user); } - $access_token_db->Save(); + $access_token_repository->add($access_token_db); //stores brand new access token hash value on a set by client id... $cache_service->addMemberSet($client_id . TokenService::ClientAccessTokenPrefixList, $hashed_value); @@ -709,13 +717,13 @@ final class TokenService implements ITokenService /** * @param AccessToken $access_token - * @throws \oauth2\exceptions\InvalidAccessTokenException + * @throws InvalidAccessTokenException */ public function storesAccessTokenOnCache(AccessToken $access_token) { //stores in REDIS - $value = $access_token->getValue(); + $value = $access_token->getValue(); $hashed_value = Hash::compute('sha256', $value); if ($this->cache_service->exists($hashed_value)) { @@ -724,11 +732,13 @@ final class TokenService implements ITokenService $auth_code = !is_null($access_token->getAuthCode()) ? Hash::compute('sha256', $access_token->getAuthCode()) : ''; + $refresh_token_value = !is_null($access_token->getRefreshToken()) ? Hash::compute('sha256', $access_token->getRefreshToken()->getValue()) : ''; + $user_id = !is_null($access_token->getUserId()) ? $access_token->getUserId() : 0; - $this->cache_service->storeHash($hashed_value, array( + $this->cache_service->storeHash($hashed_value, [ 'user_id' => $user_id, 'client_id' => $access_token->getClientId(), 'scope' => $access_token->getScope(), @@ -738,14 +748,14 @@ final class TokenService implements ITokenService 'audience' => $access_token->getAudience(), 'from_ip' => IPHelper::getUserIp(), 'refresh_token' => $refresh_token_value - ), intval($access_token->getLifetime())); + ], intval($access_token->getLifetime())); } /** - * @param DBAccessToken $access_token - * @throws \oauth2\exceptions\InvalidAccessTokenException + * @param AccessTokenDB $access_token + * @throws InvalidAccessTokenException */ - public function storesDBAccessTokenOnCache(DBAccessToken $access_token) + public function storeAccessTokenDBOnCache(AccessTokenDB $access_token) { //stores in Cache @@ -754,15 +764,16 @@ final class TokenService implements ITokenService } $refresh_token_value = ''; - $refresh_token_db = $access_token->refresh_token()->first(); + $refresh_token_db = $access_token->getRefreshToken(); + if (!is_null($refresh_token_db)) { $refresh_token_value = $refresh_token_db->value; } $user_id = !is_null($access_token->user_id) ? $access_token->user_id : 0; - $client = $access_token->client()->first(); + $client = $access_token->getClient(); - $this->cache_service->storeHash($access_token->value, array( + $this->cache_service->storeHash($access_token->value, [ 'user_id' => $user_id, 'client_id' => $client->client_id, 'scope' => $access_token->scope, @@ -772,8 +783,7 @@ final class TokenService implements ITokenService 'from_ip' => $access_token->from_ip, 'audience' => $access_token->audience, 'refresh_token' => $refresh_token_value - ) - , intval($access_token->lifetime)); + ], intval($access_token->lifetime)); } @@ -782,21 +792,21 @@ final class TokenService implements ITokenService * @param bool $is_hashed * @return AccessToken * @throws InvalidAccessTokenException - * @throws \Exception + * @throws Exception */ public function getAccessToken($value, $is_hashed = false) { - $cache_service = $this->cache_service; - $lock_manager_service = $this->lock_manager_service; - $configuration_service = $this->configuration_service; - $this_var = $this; + $cache_service = $this->cache_service; + $lock_manager_service = $this->lock_manager_service; + $configuration_service = $this->configuration_service; + $access_token_repository = $this->access_token_repository; return $this->tx_service->transaction(function () use ( - $this_var, $value, $is_hashed, $cache_service, $lock_manager_service, + $access_token_repository, $configuration_service ) { //hash the given value, bc tokens values are stored hashed on DB @@ -808,16 +818,16 @@ final class TokenService implements ITokenService // check cache ... if (!$cache_service->exists($hashed_value)) { - $lock_manager_service->lock('lock.get.accesstoken.' . $hashed_value, function() use($value, $hashed_value, $this_var){ + $lock_manager_service->lock('lock.get.accesstoken.' . $hashed_value, function() use($value, $hashed_value, $access_token_repository){ // check on DB... - $access_token_db = DBAccessToken::where('value', '=', $hashed_value)->first(); + $access_token_db = $access_token_repository->getByValue($hashed_value); if (is_null($access_token_db)) { - if($this_var->isAccessTokenRevoked($hashed_value)) + if($this->isAccessTokenRevoked($hashed_value)) { throw new RevokedAccessTokenException(sprintf('Access token %s is revoked!', $value)); } - else if($this_var->isAccessTokenVoid($hashed_value)) // check if its marked on cache as expired ... + else if($this->isAccessTokenVoid($hashed_value)) // check if its marked on cache as expired ... { throw new ExpiredAccessTokenException(sprintf('Access token %s is expired!', $value)); } @@ -833,7 +843,7 @@ final class TokenService implements ITokenService throw new ExpiredAccessTokenException(sprintf('Access token %s is expired!', $value)); } //reload on cache - $this_var->storesDBAccessTokenOnCache($access_token_db); + $this->storeAccessTokenDBOnCache($access_token_db); }); } @@ -862,8 +872,8 @@ final class TokenService implements ITokenService null, $configuration_service->getConfigValue('OAuth2.AuthorizationCode.Lifetime'), $cache_values['from_ip'], - $access_type = OAuth2Protocol::OAuth2Protocol_AccessType_Online, - $approval_prompt = OAuth2Protocol::OAuth2Protocol_Approval_Prompt_Auto, + $access_type = OAuth2Protocol::OAuth2Protocol_AccessType_Online, + $approval_prompt = OAuth2Protocol::OAuth2Protocol_Approval_Prompt_Auto, $has_previous_user_consent = false, null, null, @@ -880,13 +890,13 @@ final class TokenService implements ITokenService $refresh_token_value = $cache_values['refresh_token']; if (!empty($refresh_token_value)) { - $refresh_token = $this_var->getRefreshToken($refresh_token_value, true); + $refresh_token = $this->getRefreshToken($refresh_token_value, true); $access_token->setRefreshToken($refresh_token); } } catch (UnacquiredLockException $ex1) { - throw new InvalidAccessTokenException("access token %s ", $value); + throw new InvalidAccessTokenException(sprintf("access token %s ", $value)); } return $access_token; }); @@ -906,9 +916,9 @@ final class TokenService implements ITokenService if (!is_array($current_audience)) { $current_audience = array($current_audience); } - return \ResourceServer::where('ips','like', '%'.$current_ip.'%') - ->where('active', '=', true) - ->whereIn('host', $current_audience)->count() > 0; + + $resource_server = $this->resource_server_repository->getByAudienceAndIpAndActive($current_audience, $current_ip); + return !is_null($resource_server); } @@ -926,53 +936,60 @@ final class TokenService implements ITokenService ) ); - $client_service = $this->client_service; - $auth_service = $this->auth_service; - $cache_service = $this->cache_service; - $this_var = $this; + $client_repository = $this->client_repository; + $auth_service = $this->auth_service; + $cache_service = $this->cache_service; + $access_token_repository = $this->access_token_repository; + $refresh_token_repository = $this->refresh_token_repository; - $this->tx_service->transaction(function () use ( - &$refresh_token, - &$access_token, - &$this_var, - &$client_service, - &$auth_service, - &$cache_service + return $this->tx_service->transaction(function () use ( + $refresh_token, + $access_token, + $client_repository, + $auth_service, + $cache_service, + $access_token_repository, + $refresh_token_repository ) { - $value = $refresh_token->getValue(); + $value = $refresh_token->getValue(); //hash the given value, bc tokens values are stored hashed on DB $hashed_value = Hash::compute('sha256', $value); - $client_id = $refresh_token->getClientId(); - $user_id = $refresh_token->getUserId(); - $client = $client_service->getClientById($client_id); - $user = $auth_service->getUserById($user_id); - //stores in DB - $refresh_token_db = new DBRefreshToken ( - array( - 'value' => $hashed_value, + $client_id = $refresh_token->getClientId(); + $user_id = $refresh_token->getUserId(); + $client = $client_repository->getClientById($client_id); + $user = $auth_service->getUserById($user_id); + + // todo: move to a factory + $refresh_token_db = new RefreshTokenDB ( + [ + 'value' => $hashed_value, 'lifetime' => $refresh_token->getLifetime(), - 'scope' => $refresh_token->getScope(), - 'from_ip' => IPHelper::getUserIp(), + 'scope' => $refresh_token->getScope(), + 'from_ip' => IPHelper::getUserIp(), 'audience' => $access_token->getAudience(), - ) + ] ); $refresh_token_db->client()->associate($client); $refresh_token_db->user()->associate($user); - $refresh_token_db->Save(); + $refresh_token_repository->add($refresh_token_db); //associate current access token to refresh token on DB - $access_token_db = DBAccessToken::where('value', '=', - Hash::compute('sha256', $access_token->getValue()))->first(); + $access_token_db = $this->access_token_repository->getByValue(Hash::compute('sha256', $access_token->getValue())); $access_token_db->refresh_token()->associate($refresh_token_db); - $access_token_db->Save(); + + $access_token_repository->add($access_token_db); $access_token->setRefreshToken($refresh_token); - $cache_service->incCounter($client_id . TokenService::ClientRefreshTokensQty, - TokenService::ClientRefreshTokensQtyLifetime); + $cache_service->incCounter + ( + $client_id . TokenService::ClientRefreshTokensQty, + TokenService::ClientRefreshTokensQtyLifetime + ); + + return $refresh_token; }); - return $refresh_token; } /** @@ -988,7 +1005,7 @@ final class TokenService implements ITokenService //hash the given value, bc tokens values are stored hashed on DB $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; - $refresh_token_db = DBRefreshToken::where('value', '=', $hashed_value)->first(); + $refresh_token_db = $this->refresh_token_repository->getByValue($hashed_value); if (is_null($refresh_token_db)) { @@ -1017,7 +1034,7 @@ final class TokenService implements ITokenService throw new InvalidGrantTypeException(sprintf("refresh token %s is expired!", $value)); } - $client = $refresh_token_db->client()->first(); + $client = $refresh_token_db->getClient(); $refresh_token = RefreshToken::load ( @@ -1045,32 +1062,46 @@ final class TokenService implements ITokenService */ public function revokeAuthCodeRelatedTokens($auth_code) { - $auth_code_hashed_value = Hash::compute('sha256', $auth_code); - $cache_service = $this->cache_service; + $auth_code_hashed_value = Hash::compute('sha256', $auth_code); + $cache_service = $this->cache_service; + $access_token_repository = $this->access_token_repository; + $refresh_token_repository = $this->refresh_token_repository; - $this->tx_service->transaction(function () use ($auth_code_hashed_value, &$cache_service) { + $this->tx_service->transaction(function () use + ( + $auth_code_hashed_value, + $cache_service, + $access_token_repository, + $refresh_token_repository + ) { //get related access tokens - $db_access_tokens = DBAccessToken::where('associated_authorization_code', '=', - $auth_code_hashed_value)->get(); + $db_access_token = $access_token_repository->getByAuthCode($auth_code_hashed_value); + if(is_null($db_access_token)) return; - foreach ($db_access_tokens as $db_access_token) { - - $client = $db_access_token->client()->first(); - $access_token_value = $db_access_token->value; - $refresh_token_db = $db_access_token->refresh_token()->first(); - - if (!is_null($refresh_token_db)) { - $refresh_token_db->delete(); - } - //remove auth code from client list on cache - $cache_service->deleteMemberSet($client->client_id . TokenService::ClientAuthCodePrefixList, - $auth_code_hashed_value); + $client = $db_access_token->getClient(); + $access_token_value = $db_access_token->value; + $refresh_token_db = $db_access_token->refresh_token()->first(); + //remove auth code from client list on cache + $cache_service->deleteMemberSet + ( + $client->client_id . TokenService::ClientAuthCodePrefixList, + $auth_code_hashed_value + ); //remove access token from client list on cache - $cache_service->deleteMemberSet($client->client_id . TokenService::ClientAccessTokenPrefixList, - $access_token_value); - $cache_service->delete($access_token_value); - $db_access_token->delete(); + $cache_service->deleteMemberSet + ( + $client->client_id . TokenService::ClientAccessTokenPrefixList, + $access_token_value + ); + + $cache_service->delete($access_token_value); + + $access_token_repository->delete($db_access_token); + + if (!is_null($refresh_token_db)) { + $this->revokeRefreshToken($refresh_token_db->value, true); } + }); } @@ -1083,31 +1114,39 @@ final class TokenService implements ITokenService public function revokeAccessToken($value, $is_hashed = false) { - $cache_service = $this->cache_service; - $this_var = $this; + $cache_service = $this->cache_service; + $access_token_repository = $this->access_token_repository; + + return $this->tx_service->transaction(function () use + ( + $value, + $is_hashed, + $cache_service, + $access_token_repository + ) { - return $this->tx_service->transaction(function () use ($value, $is_hashed, $cache_service, $this_var) { - $res = 0; //hash the given value, bc tokens values are stored hashed on DB $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; - $access_token_db = DBAccessToken::where('value', '=', $hashed_value)->first(); + $access_token_db = $access_token_repository->getByValue($hashed_value); + if(is_null($access_token_db)) return false; - $client = $access_token_db->client()->first(); + + $client = $access_token_db->getClient(); //delete from cache - $res = $cache_service->delete($hashed_value); - $res = $cache_service->deleteMemberSet + $cache_service->delete($hashed_value); + $cache_service->deleteMemberSet ( $client->client_id . TokenService::ClientAccessTokenPrefixList, $access_token_db->value ); //check on DB... and delete it - $res = $access_token_db->delete(); + $access_token_repository->delete($access_token_db); - $this_var->markAccessTokenAsRevoked($hashed_value); + $this->markAccessTokenAsRevoked($hashed_value); - return $res > 0; + return true; }); } @@ -1119,31 +1158,37 @@ final class TokenService implements ITokenService */ public function expireAccessToken($value, $is_hashed = false) { - $cache_service = $this->cache_service; - $this_var = $this; + $cache_service = $this->cache_service; + $access_token_repository = $this->access_token_repository; - return $this->tx_service->transaction(function () use ($value, $is_hashed, $cache_service, $this_var) { - $res = 0; + return $this->tx_service->transaction(function () use + ( + $value, + $is_hashed, + $cache_service, + $access_token_repository + ) { //hash the given value, bc tokens values are stored hashed on DB $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; - $access_token_db = DBAccessToken::where('value', '=', $hashed_value)->first(); + $access_token_db = $access_token_repository->getByValue($hashed_value); + if(is_null($access_token_db)) return false; - $client = $access_token_db->client()->first(); + + $client = $access_token_db->getClient(); //delete from cache - $res = $cache_service->delete($hashed_value); - $res = $cache_service->deleteMemberSet + $cache_service->delete($hashed_value); + $cache_service->deleteMemberSet ( $client->client_id . TokenService::ClientAccessTokenPrefixList, $access_token_db->value ); - //check on DB... and delete it - $res = $access_token_db->delete(); + $access_token_repository->delete($access_token_db); - $this_var->markAccessTokenAsVoid($hashed_value); + $this->markAccessTokenAsVoid($hashed_value); - return $res > 0; + return true; }); } @@ -1154,23 +1199,22 @@ final class TokenService implements ITokenService public function revokeClientRelatedTokens($client_id) { //get client auth codes - $auth_codes = $this->cache_service->getSet($client_id . self::ClientAuthCodePrefixList); + $auth_codes = $this->cache_service->getSet($client_id . self::ClientAuthCodePrefixList); //get client access tokens - $access_tokens = $this->cache_service->getSet($client_id . self::ClientAccessTokenPrefixList); + $access_tokens = $this->cache_service->getSet($client_id . self::ClientAccessTokenPrefixList); + $client_repository = $this->client_repository; + $cache_service = $this->cache_service; - $client_service = $this->client_service; - $cache_service = $this->cache_service; - $this_var = $this; $this->tx_service->transaction(function () use ( $client_id, $auth_codes, $access_tokens, $cache_service, - $client_service, - $this_var + $client_repository + ) { - $client = $client_service->getClientById($client_id); + $client = $client_repository->getClientById($client_id); if (is_null($client)) { @@ -1182,12 +1226,12 @@ final class TokenService implements ITokenService //revoke on db foreach($client->access_tokens()->get() as $at) { - $this_var->markAccessTokenAsRevoked($at->value); + $this->markAccessTokenAsRevoked($at->value); } foreach($client->refresh_tokens()->get() as $rt) { - $this_var->markRefreshTokenAsRevoked($rt); + $this->markRefreshTokenAsRevoked($rt); } $client->access_tokens()->delete(); @@ -1272,9 +1316,12 @@ final class TokenService implements ITokenService */ public function invalidateRefreshToken($value, $is_hashed = false) { - $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; - $res = RefreshTokenDB::where('value', '=', $hashed_value)->update(array('void' => true)); - return $res > 0; + $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; + $refresh_token = $this->refresh_token_repository->getByValue($hashed_value); + if(is_null($refresh_token)) return false; + $refresh_token->setVoid(); + $this->refresh_token_repository->add($refresh_token); + return true; } /** @@ -1285,136 +1332,63 @@ final class TokenService implements ITokenService */ public function revokeRefreshToken($value, $is_hashed = false) { - $res = false; - $this_var = $this; - - $this->tx_service->transaction(function () use ($value, $is_hashed, &$res, &$this_var) { - $res = $this_var->invalidateRefreshToken($value, $is_hashed); - $res = $res && $this_var->clearAccessTokensForRefreshToken($value, $is_hashed); + return $this->tx_service->transaction(function () use ($value, $is_hashed) { + $res = $this->invalidateRefreshToken($value, $is_hashed); + return $res && $this->clearAccessTokensForRefreshToken($value, $is_hashed); }); - return $res; } /** * Revokes all access tokens for a give refresh token - * @param $value refresh token value + * @param string $value refresh token value * @param bool $is_hashed * @return bool|void */ public function clearAccessTokensForRefreshToken($value, $is_hashed = false) { - $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; - $cache_service = $this->cache_service; - $this_var = $this; + $hashed_value = !$is_hashed ? Hash::compute('sha256', $value) : $value; + $cache_service = $this->cache_service; + $access_token_repository = $this->access_token_repository; + $refresh_token_repository = $this->refresh_token_repository; - return $this->tx_service->transaction(function () use ($hashed_value, $cache_service, $this_var) { + return $this->tx_service->transaction(function () use + ( + $hashed_value, + $cache_service, + $access_token_repository, $refresh_token_repository) { - $res = false; - $refresh_token_db = DBRefreshToken::where('value', '=', $hashed_value)->first(); + $refresh_token_db = $refresh_token_repository->getByValue($hashed_value); if (!is_null($refresh_token_db)) { - $access_tokens_db = DBAccessToken::where('refresh_token_id', '=', $refresh_token_db->id)->get(); + $access_tokens_db = $access_token_repository->getByRefreshToken($refresh_token_db->id); - if (!count($access_tokens_db)) - { - $res = true; - } + if (count($access_tokens_db) == 0) return false; foreach ($access_tokens_db as $access_token_db) { - $res = $cache_service->delete($access_token_db->value); - $client = $access_token_db->client()->first(); - $res = $cache_service->deleteMemberSet - ( - $client->client_id . TokenService::ClientAccessTokenPrefixList, - $access_token_db->value - ); + $cache_service->delete($access_token_db->value); + $client = $access_token_db->getClient(); + $cache_service->deleteMemberSet + ( + $client->client_id . TokenService::ClientAccessTokenPrefixList, + $access_token_db->value + ); - $this_var->markAccessTokenAsRevoked($access_token_db->value); + $this->markAccessTokenAsRevoked($access_token_db->value); - $access_token_db->delete(); + $this->access_token_repository->delete($access_token_db); } } - return $res; + return true; }); } - public function getAccessTokenByClient($client_id) - { - $client = $this->client_service->getClientById($client_id); - if (is_null($client)) { - throw new AbsentClientException(sprintf("client id %d does not exists!", $client_id)); - } - $res = array(); - // not void condition - $access_tokens = $client->access_tokens()->whereRaw(" DATE_ADD(created_at, INTERVAL lifetime second) >= UTC_TIMESTAMP() ")->get(); - foreach ($access_tokens as $access_token) { - if (!$access_token->isVoid()) { - array_push($res, $access_token); - } - } - - return $res; - } - - public function getRefreshTokenByClient($client_id) - { - $client = $this->client_service->getClientById($client_id); - if (is_null($client)) - { - throw new AbsentClientException(sprintf("client id %d does not exists!", $client_id)); - } - $res = array(); - $refresh_tokens = $client->refresh_tokens()->where('void', '=', false)->get(); - foreach ($refresh_tokens as $refresh_token) { - if (!$refresh_token->isVoid()) { - array_push($res, $refresh_token); - } - } - - return $res; - } - - public function getAccessTokenByUserId($user_id) - { - $user = $this->auth_service->getUserById($user_id); - if (is_null($user)) { - throw new AbsentClientException(sprintf("user id %d does not exists!", $user_id)); - } - $res = array(); - $access_tokens = $user->access_tokens()->get(); - foreach ($access_tokens as $access_token) { - if (!$access_token->isVoid()) { - array_push($res, $access_token); - } - } - - return $res; - } - - public function getRefreshTokenByUserId($user_id) - { - $user = $this->auth_service->getUserById($user_id); - if (is_null($user)) { - throw new AbsentClientException(sprintf("user id %d does not exists!", $user_id)); - } - $res = array(); - $refresh_tokens = $user->refresh_tokens()->where('void', '=', false)->get(); - foreach ($refresh_tokens as $refresh_token) { - if (!$refresh_token->isVoid()) { - array_push($res, $refresh_token); - } - } - - return $res; - } - /** * @param string $nonce * @param string $client_id @@ -1438,7 +1412,7 @@ final class TokenService implements ITokenService $issuer = $this->configuration_service->getSiteUrl(); if(empty($issuer)) throw new ConfigurationException('missing idp url'); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); $id_token_lifetime = $this->configuration_service->getConfigValue('OAuth2.IdToken.Lifetime'); if (is_null($client)) @@ -1571,9 +1545,9 @@ final class TokenService implements ITokenService ) { - $ac = $auth_code->getValue(); - $ac_len = $hashing_alg->getHashKeyLen() / 2 ; - $encoder = new Base64UrlRepresentation(); + $ac = $auth_code->getValue(); + $ac_len = $hashing_alg->getHashKeyLen() / 2 ; + $encoder = new Base64UrlRepresentation(); if($ac_len > ByteUtil::bitLength(strlen($ac))) throw new InvalidClientCredentials('invalid auth code length!.'); @@ -1631,7 +1605,7 @@ final class TokenService implements ITokenService public function getAccessTokenByAuthCode(AuthorizationCode $auth_code) { $auth_code_value = Hash::compute('sha256', $auth_code->getValue()); - $db_access_token = DBAccessToken::where('associated_authorization_code', '=', $auth_code_value)->first(); + $db_access_token = $this->access_token_repository->getByAuthCode($auth_code_value); if(is_null($db_access_token)) return null; return $this->getAccessToken($db_access_token->value, true); } diff --git a/app/Services/OAuth2/UserConsentService.php b/app/Services/OAuth2/UserConsentService.php new file mode 100644 index 00000000..05695557 --- /dev/null +++ b/app/Services/OAuth2/UserConsentService.php @@ -0,0 +1,110 @@ +where('client_id', '=', $client_id); + + $query2 = UserConsent::where('user_id', '=', $user_id)->where('client_id', '=', $client_id); + + + $query1 = $query1->where(function ($query) use($perms) + { + foreach ($perms as $p) + { + $str = join(' ', $p); + $query = $query->orWhere('scopes', '=', $str); + } + + return $query; + }); + + + $query2 = $query2->where(function ($query) use($perms) + { + foreach ($perms as $p) + { + $str = join(' ', $p); + $query = $query->orWhere('scopes', 'like', '%'.$str.'%'); + } + + return $query; + }); + + + $consent = $query1->first(); + + if (is_null($consent)) { + $consent = $query2->first(); + } + + return $consent; + } + + /** + * @param int $user_id + * @param string $client_id + * @param string $scopes + * @return IUserConsent|void + * @throws EntityNotFoundException + */ + public function add($user_id, $client_id, $scopes) + { + $consent = new UserConsent(); + + if (is_null(Client::find($client_id))) { + throw new EntityNotFoundException(); + } + + $consent->client_id = $client_id; + $consent->user_id = $user_id; + $consent->scopes = $scopes; + $consent->Save(); + } +} \ No newline at end of file diff --git a/app/Services/OpenId/AssociationService.php b/app/Services/OpenId/AssociationService.php new file mode 100644 index 00000000..ca47b09a --- /dev/null +++ b/app/Services/OpenId/AssociationService.php @@ -0,0 +1,243 @@ +lock_manager_service = $lock_manager_service; + $this->cache_service = $cache_service; + $this->repository = $repository; + $this->tx_service = $tx_service; + } + + /** + * gets a given association by handle, and if association exists and its type is private, then lock it + * to prevent subsequent usage ( private association could be used once) + * @param $handle + * @param null $realm + * @return null|IAssociation + * @throws ReplayAttackException + * @throws InvalidAssociation + * @throws OpenIdInvalidRealmException + */ + public function getAssociation($handle, $realm = null) + { + + return $this->tx_service->transaction(function() use($handle, $realm) { + + $lock_name = 'lock.get.assoc.' . $handle; + + try { + // check if association is on cache + if (!$this->cache_service->exists($handle)) { + // if not , check on db + $assoc = $this->repository->getByHandle($handle); + if (is_null($assoc)) { + throw new InvalidAssociation(sprintf('openid association %s does not exists!', $handle)); + } + //check association lifetime ... + $remaining_lifetime = $assoc->getRemainingLifetime(); + if ($remaining_lifetime < 0) { + $this->deleteAssociation($handle); + + return null; + } + //convert secret to hexa representation + // bin2hex + $secret_unpack = \unpack('H*', $assoc->secret); + $secret_unpack = array_shift($secret_unpack); + //repopulate cache + $this->cache_service->storeHash($handle, [ + "type" => $assoc->type, + "mac_function" => $assoc->mac_function, + "issued" => $assoc->issued, + "lifetime" => $assoc->lifetime, + "secret" => $secret_unpack, + "realm" => $assoc->realm + ], $remaining_lifetime); + } + + //get hash from cache + $cache_values = $this->cache_service->getHash($handle, [ + "type", + "mac_function", + "issued", + "lifetime", + "secret", + "realm" + ]); + + if ($cache_values['type'] == IAssociation::TypePrivate) { + if (is_null($realm) || empty($realm) || $cache_values['realm'] != $realm) { + throw new OpenIdInvalidRealmException(sprintf(OpenIdErrorMessages::InvalidPrivateAssociationMessage, + $handle, $realm)); + } + // only one time we could use this handle + $this->lock_manager_service->acquireLock($lock_name); + } + + //convert hex 2 bin + $secret = \pack('H*', $cache_values['secret']); + $assoc = new OpenIdAssociation(); + + $assoc->type = $cache_values['type']; + $assoc->mac_function = $cache_values['mac_function']; + $assoc->issued = $cache_values['issued']; + $assoc->lifetime = intval($cache_values['lifetime']); + $assoc->secret = $secret; + $realm = $cache_values['realm']; + + if (!empty($realm)) { + $assoc->realm = $realm; + } + + return $assoc; + + } catch (UnacquiredLockException $ex1) { + throw new ReplayAttackException + ( + sprintf(OpenIdErrorMessages::ReplayAttackPrivateAssociationAlreadyUsed, $handle) + ); + } + }); + } + + /** + * @param $handle + * @return bool + */ + public function deleteAssociation($handle) + { + return $this->tx_service->transaction(function() use($handle){ + + $this->cache_service->delete($handle); + $assoc = $this->repository->getByHandle($handle); + if (!is_null($assoc)) { + return $this->repository->delete($assoc); + } + + return false; + }); + } + + /** + * @param IAssociation $association + * @return IAssociation + * @throws ReplayAttackException + */ + public function addAssociation(IAssociation $association) + { + return $this->tx_service->transaction(function() use($association){ + + $assoc = new OpenIdAssociation(); + try { + $lock_name = 'lock.add.assoc.' . $association->getHandle(); + + $this->lock_manager_service->acquireLock($lock_name); + + $assoc->identifier = $association->getHandle();; + $assoc->secret = $association->getSecret(); + $assoc->type = $association->getType();; + $assoc->mac_function = $association->getMacFunction(); + $assoc->lifetime = intval($association->getLifetime()); + $assoc->issued = $association->getIssued(); + + if (!is_null($association->getRealm())) { + $assoc->realm = $association->getRealm(); + } + + if ($association->getType() == IAssociation::TypeSession) { + $this->repository->add($assoc); + } + //convert secret to hexa representation + // bin2hex + $secret_unpack = \unpack('H*', $association->getSecret()); + $secret_unpack = array_shift($secret_unpack); + + $this->cache_service->storeHash($association->getHandle(), + [ + "type" => $association->getType(), + "mac_function" => $association->getMacFunction(), + "issued" => $association->getIssued(), + "lifetime" => intval($association->getLifetime()), + "secret" => $secret_unpack, + "realm" => !is_null($association->getRealm()) ? $association->getRealm() : '' + ], + intval($association->getLifetime()) + ); + + } catch (UnacquiredLockException $ex1) { + throw new ReplayAttackException + ( + sprintf + ( + OpenIdErrorMessages::ReplayAttackPrivateAssociationAlreadyUsed, + $association->getHandle() + ) + ); + } + + return $assoc; + + }); + } + +} \ No newline at end of file diff --git a/app/services/openid/NonceService.php b/app/Services/OpenId/NonceService.php similarity index 75% rename from app/services/openid/NonceService.php rename to app/Services/OpenId/NonceService.php index b4cebec6..f7964eaf 100644 --- a/app/services/openid/NonceService.php +++ b/app/Services/OpenId/NonceService.php @@ -1,23 +1,33 @@ -getRawFormat(); + $raw_nonce = $nonce->getRawFormat(); $lock_lifetime = $this->configuration_service->getConfigValue("Nonce.Lifetime"); try { $this->lock_manager_service->acquireLock('lock.nonce.' . $raw_nonce, $lock_lifetime); } catch (UnacquiredLockException $ex) { throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackNonceAlreadyUsed, $nonce->getRawFormat())); } + return $this; } + /** + * @param OpenIdNonce $nonce + * @return $this + */ public function unlockNonce(OpenIdNonce $nonce) { $raw_nonce = $nonce->getRawFormat(); $this->lock_manager_service->releaseLock('lock.nonce.' . $raw_nonce); + return $this; } @@ -95,19 +111,12 @@ final class NonceService implements INonceService return $this->nonce_generator->generate(new OpenIdNonce(255)); } - /** - * @return string - */ - private function makeNonceSalt(){ - return Rand::getString(self::NonceSaltLength, self::NoncePopulation, true); - } - /** * @param OpenIdNonce $nonce * @param string $signature * @param string $realm - * @return mixed|void - * @throws \openid\exceptions\ReplayAttackException + * @return $this + * @throws ReplayAttackException */ public function markNonceAsInvalid(OpenIdNonce $nonce, $signature, $realm) { @@ -126,12 +135,14 @@ final class NonceService implements INonceService $this->cache_service->delete($key); throw $ex; } + return $this; } /** * @param OpenIdNonce $nonce * @param string $signature * @param string $realm + * @return $this; */ public function associateNonce(OpenIdNonce $nonce, $signature, $realm) { @@ -142,5 +153,6 @@ final class NonceService implements INonceService } catch (Exception $ex) { Log::error($ex); } + return $this; } } \ No newline at end of file diff --git a/app/services/openid/OpenIdMementoSessionSerializerService.php b/app/Services/OpenId/OpenIdMementoSessionSerializerService.php similarity index 56% rename from app/services/openid/OpenIdMementoSessionSerializerService.php rename to app/Services/OpenId/OpenIdMementoSessionSerializerService.php index 00796b30..09480ec3 100644 --- a/app/services/openid/OpenIdMementoSessionSerializerService.php +++ b/app/Services/OpenId/OpenIdMementoSessionSerializerService.php @@ -1,15 +1,23 @@ -get(); + $res = []; + foreach ($extensions as $extension) { + $class_name = $extension->extension_class; + if (empty($class_name)) continue; + + $class = new ReflectionClass($class_name); + $constructor = $class->getConstructor(); + $constructor_params = $constructor->getParameters(); + + $deps = []; + + foreach($constructor_params as $constructor_param){ + $param_class = $constructor_param->getClass(); + $name = $constructor_param->getName(); + if(is_null($param_class)){ + $deps[] = $extension->$name; + } + else{ + $deps [] = ServiceLocator::getInstance()->getService($param_class->getName()); + } + } + + $res[] = $class->newInstanceArgs($deps);; + } + return $res; + } +} \ No newline at end of file diff --git a/app/services/openid/TrustedSitesService.php b/app/Services/OpenId/TrustedSitesService.php similarity index 69% rename from app/services/openid/TrustedSitesService.php rename to app/Services/OpenId/TrustedSitesService.php index 5b806dc4..c5acbe72 100644 --- a/app/services/openid/TrustedSitesService.php +++ b/app/Services/OpenId/TrustedSitesService.php @@ -1,24 +1,41 @@ -realm = $realm; $site->policy = $policy; $site->user_id = $user->getId(); $site->data = json_encode($data); + return $this->repository->add($site)?$site:false; } catch (Exception $ex) { @@ -77,7 +96,7 @@ class TrustedSitesService implements ITrustedSitesService * @param $realm * @param array $data * @return array|mixed - * @throws \Exception + * @throws Exception */ public function getTrustedSites(IOpenIdUser $user, $realm, $data = array()) { @@ -119,16 +138,17 @@ class TrustedSitesService implements ITrustedSitesService */ private function getSubDomains($url) { - $res = array(); - $url = strtolower($url); + $res = array(); + $url = strtolower($url); $scheme = $this->getScheme($url); //add entire url as first domain array_push($res, $url); + $ends_with_slash = substr($url, -1) == '/'; - $url = parse_url($url); - $authority = $url['host']; - $components = explode('.', $authority); - $len = count($components); + $url = parse_url($url); + $authority = $url['host']; + $components = explode('.', $authority); + $len = count($components); for ($i = 0; $i < $len; $i++) { if ($components[$i] == '*') continue; @@ -143,14 +163,15 @@ class TrustedSitesService implements ITrustedSitesService } /** - * @param $url + * @param string $url * @return string */ private function getScheme($url) { - $url = strtolower($url); - $url = parse_url($url); + $url = strtolower($url); + $url = parse_url($url); $scheme = 'http://'; + if (isset($url['scheme']) && !empty($url['scheme'])) { $scheme = $url['scheme'] . '://'; } diff --git a/app/Services/OpenId/UserService.php b/app/Services/OpenId/UserService.php new file mode 100644 index 00000000..592fbf3f --- /dev/null +++ b/app/Services/OpenId/UserService.php @@ -0,0 +1,254 @@ +repository = $repository; + $this->user_name_generator = $user_name_generator; + $this->configuration_service = $configuration_service; + $this->log_service = $log_service; + $this->tx_service = $tx_service; + } + + + /** + * @param int $user_id + * @return void + * @throws EntityNotFoundException + */ + public function updateLastLoginDate($user_id) + { + $this->tx_service->transaction(function() use($user_id){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + $user->last_login_date = gmdate("Y-m-d H:i:s", time()); + $this->repository->add($user); + }); + } + + /** + * @param int $user_id + * @return void + * @throws EntityNotFoundException + */ + public function updateFailedLoginAttempts($user_id) + { + $this->tx_service->transaction(function() use($user_id){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + $user->login_failed_attempt += 1; + $this->repository->add($user); + }); + } + + /** + * @param int $user_id + * @return void + * @throws EntityNotFoundException + */ + public function lockUser($user_id) + { + $this->tx_service->transaction(function() use($user_id){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + + $user->lock = true; + $this->repository->add($user); + + $support_email = $this->configuration_service->getConfigValue('SupportEmail'); + Mail::send('emails.auth.user_locked', [ + 'user_name' => $user->getFullName(), + 'attempts' => $user->login_failed_attempt, + 'support_email' => $support_email, + ], function($message) use ($user, $support_email) + { + $message + ->from($support_email, 'OpenStack Support Team') + ->to($user->getEmail(), $user->getFullName()) + ->subject('OpenStackId - your user has been locked!'); + }); + }); + } + + /** + * @param int $user_id + * @return void + * @throws EntityNotFoundException + */ + public function unlockUser($user_id) + { + $this->tx_service->transaction(function() use($user_id){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + $user->lock = false; + $this->repository->update($user); + }); + } + + /** + * @param int $user_id + * @return void + * @throws EntityNotFoundException + */ + public function activateUser($user_id) + { + $this->tx_service->transaction(function() use($user_id){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + $user->active = true; + $this->repository->update($user); + }); + } + + /** + * @param int $user_id + * @return void + * @throws EntityNotFoundException + */ + public function deActivateUser($user_id) + { + $this->tx_service->transaction(function() use($user_id){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + $user->active = false; + $this->repository->update($user); + }); + } + + /** + * @param int $user_id + * @param bool $show_pic + * @param bool $show_full_name + * @param bool $show_email + * @return bool + * @throws EntityNotFoundException + */ + public function saveProfileInfo($user_id, $show_pic, $show_full_name, $show_email) + { + + return $this->tx_service->transaction(function() use($user_id, $show_pic, $show_full_name, $show_email){ + $user = $this->repository->get($user_id); + if(is_null($user)) throw new EntityNotFoundException(); + + $user->public_profile_show_photo = $show_pic; + $user->public_profile_show_fullname = $show_full_name; + $user->public_profile_show_email = $show_email; + + $this->repository->update($user); + return true; + }); + } + + /** + * @param Member $member + * @return IOpenIdUser + */ + public function buildUser(Member $member) + { + $repository = $this->repository; + $user_name_generator = $this->user_name_generator; + + return $this->tx_service->transaction(function () use($member, $user_name_generator, $repository){ + //create user + $old_user = $repository->getByExternalId($member->ID); + if(!is_null($old_user)) + throw new ValidationException(sprintf('already exists an user with external_identifier %s', $member->ID)); + + $user = new User(); + $user->external_identifier = $member->ID; + $user->identifier = $member->ID; + $user->last_login_date = gmdate("Y-m-d H:i:s", time()); + $user->active = true; + $user->lock = false; + $user->login_failed_attempt = 0; + + $done = false; + $fragment_nbr = 1; + $identifier = $original_identifier = $user_name_generator->generate($member); + do + { + $old_user = $repository->getByIdentifier($identifier); + if(!is_null($old_user)) + { + $identifier = $original_identifier . IUserNameGeneratorService::USER_NAME_CHAR_CONNECTOR . $fragment_nbr; + $fragment_nbr++; + continue; + } + $user->identifier = $identifier; + break; + } while (1); + $repository->add($user); + return $user; + }); + } + +} \ No newline at end of file diff --git a/app/services/security_policies/AbstractBlacklistSecurityPolicy.php b/app/Services/SecurityPolicies/AbstractBlacklistSecurityPolicy.php similarity index 65% rename from app/services/security_policies/AbstractBlacklistSecurityPolicy.php rename to app/Services/SecurityPolicies/AbstractBlacklistSecurityPolicy.php index 50d7c78a..0f8e2ce3 100644 --- a/app/services/security_policies/AbstractBlacklistSecurityPolicy.php +++ b/app/Services/SecurityPolicies/AbstractBlacklistSecurityPolicy.php @@ -1,33 +1,55 @@ -tx_service = $tx_service; } + /** + * @param ISecurityPolicyCounterMeasure $counter_measure + * @return $this + */ public function setCounterMeasure(ISecurityPolicyCounterMeasure $counter_measure) { $this->counter_measure = $counter_measure; + return $this; } /** diff --git a/app/services/security_policies/AuthorizationCodeRedeemPolicy.php b/app/Services/SecurityPolicies/AuthorizationCodeRedeemPolicy.php similarity index 61% rename from app/services/security_policies/AuthorizationCodeRedeemPolicy.php rename to app/Services/SecurityPolicies/AuthorizationCodeRedeemPolicy.php index f4aea210..a5a082c3 100644 --- a/app/services/security_policies/AuthorizationCodeRedeemPolicy.php +++ b/app/Services/SecurityPolicies/AuthorizationCodeRedeemPolicy.php @@ -1,18 +1,28 @@ -resource_server_service = $resource_server_service; + $this->resource_server_repository = $resource_server_repository; // here we configure on which exceptions are we interested and the max occurrence attempts and initial delay on tar pit for // offending IP address $this->exception_dictionary = array( @@ -100,6 +118,7 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy 'BlacklistSecurityPolicy.OAuth2.BearerTokenDisclosureAttemptInitialDelay' ), ); + $this->white_listed_ip_repository = $white_listed_ip_repository; } /** @@ -164,7 +183,7 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy /** * @param Exception $ex * @throws Exception - * @return void + * @return $this */ public function apply(Exception $ex) { @@ -198,7 +217,7 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy ); $initial_delay_on_tar_pit = intval($this->server_configuration_service->getConfigValue($params[1])); - if (!$this->isIPAddressWhitelisted($remote_ip) && $exception_count >= $max_attempts) + if (!$this->isIPAddressWhiteListed($remote_ip) && $exception_count >= $max_attempts) { Log::warning ( @@ -221,16 +240,18 @@ class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy Log::error($ex); throw $ex; } + return $this; } /** * @param string $ip * @return bool */ - private function isIPAddressWhitelisted($ip) + private function isIPAddressWhiteListed($ip) { - $resource_server = $this->resource_server_service->getByIPAddress($ip); - $white_listed_ip = \WhiteListedIP::where('ip','=', $ip)->first(); + $resource_server = $this->resource_server_repository->getByIp($ip); + $white_listed_ip = $this->white_listed_ip_repository->getByIp($ip); + return !is_null($resource_server) || !is_null($white_listed_ip); } diff --git a/app/Services/SecurityPolicies/DelayCounterMeasure.php b/app/Services/SecurityPolicies/DelayCounterMeasure.php new file mode 100644 index 00000000..13249981 --- /dev/null +++ b/app/Services/SecurityPolicies/DelayCounterMeasure.php @@ -0,0 +1,58 @@ +cache_service = $cache_service; + } + + /** + * @param array $params + * @return $this + */ + public function trigger(array $params = array()) + { + try { + $remote_address = IPHelper::getUserIp(); + if ($this->cache_service->exists($remote_address)) { + Log::warning(sprintf("DelayCounterMeasure: attempt from banned ip %s",$remote_address)); + $hits = intval($this->cache_service->getSingleValue($remote_address)); + sleep(2 ^ $hits); + } + } catch (Exception $ex) { + Log::error($ex); + } + return $this; + } +} \ No newline at end of file diff --git a/app/Services/SecurityPolicies/LockUserCounterMeasure.php b/app/Services/SecurityPolicies/LockUserCounterMeasure.php new file mode 100644 index 00000000..5b889fd6 --- /dev/null +++ b/app/Services/SecurityPolicies/LockUserCounterMeasure.php @@ -0,0 +1,80 @@ +user_service = $user_service; + $this->server_configuration = $server_configuration; + $this->repository = $repository; + } + + /** + * @param array $params + * @return $this + */ + public function trigger(array $params = array()) + { + try { + if (isset($params["user_identifier"])) { + $user_identifier = $params["user_identifier"]; + $user = $this->repository->getByExternalId($user_identifier); + if (!is_null($user)) { + //apply lock policy + if (intval($user->login_failed_attempt) < intval($this->server_configuration->getConfigValue("MaxFailed.Login.Attempts"))) { + $this->user_service->updateFailedLoginAttempts($user->id); + } else { + $this->user_service->lockUser($user->id); + } + } + } + } catch (Exception $ex) { + Log::error($ex); + } + return $this; + } +} \ No newline at end of file diff --git a/app/Services/SecurityPolicies/LockUserSecurityPolicy.php b/app/Services/SecurityPolicies/LockUserSecurityPolicy.php new file mode 100644 index 00000000..de6a887d --- /dev/null +++ b/app/Services/SecurityPolicies/LockUserSecurityPolicy.php @@ -0,0 +1,68 @@ +counter_measure = $counter_measure; + return $this; + } + + /** + * Apply security policy on a exception + * @param Exception $ex + * @return $this + */ + public function apply(Exception $ex) + { + try { + if($ex instanceof AuthenticationInvalidPasswordAttemptException) { + $user_identifier = $ex->getIdentifier(); + if (!is_null($user_identifier) && !empty($user_identifier)) + $this->counter_measure->trigger(array('user_identifier' => $user_identifier)); + } + } catch (Exception $ex) { + Log::error($ex); + } + return $this; + } +} \ No newline at end of file diff --git a/app/Services/SecurityPolicies/OAuth2LockClientCounterMeasure.php b/app/Services/SecurityPolicies/OAuth2LockClientCounterMeasure.php new file mode 100644 index 00000000..42340b79 --- /dev/null +++ b/app/Services/SecurityPolicies/OAuth2LockClientCounterMeasure.php @@ -0,0 +1,56 @@ +client_service = $client_service; + } + + /** + * @param array $params + * @return $this + */ + public function trigger(array $params = array()) + { + try{ + + if (isset($params["client_id"])) { + $this->client_service->lockClient(intval($params['client_id'])); + } + } + catch(Exception $ex){ + Log::error($ex); + } + return $this; + } +} \ No newline at end of file diff --git a/app/Services/SecurityPolicies/OAuth2SecurityPolicy.php b/app/Services/SecurityPolicies/OAuth2SecurityPolicy.php new file mode 100644 index 00000000..cbbf6da7 --- /dev/null +++ b/app/Services/SecurityPolicies/OAuth2SecurityPolicy.php @@ -0,0 +1,128 @@ +server_configuration_service = $server_configuration_service; + $this->client_repository = $client_repository; + + $this->exception_dictionary = array( + 'auth2\exceptions\BearerTokenDisclosureAttemptException' => array('OAuth2SecurityPolicy.MaxBearerTokenDisclosureAttempts'), + 'auth2\exceptions\InvalidClientException' => array('OAuth2SecurityPolicy.MaxInvalidClientExceptionAttempts'), + 'auth2\exceptions\InvalidRedeemAuthCodeException' => array('OAuth2SecurityPolicy.MaxInvalidRedeemAuthCodeAttempts'), + 'auth2\exceptions\InvalidClientCredentials' => array('OAuth2SecurityPolicy.MaxInvalidClientCredentialsAttempts'), + ); + } + /** + * Check if current security policy is meet or not + * @return boolean + */ + public function check() + { + return true; + } + + /** + * Apply security policy on a exception + * @param Exception $ex + * @return $this + */ + public function apply(Exception $ex) + { + try { + if($ex instanceof OAuth2ClientBaseException){ + $client_id = $ex->getClientId(); + //save oauth2 exception by client id + if (!is_null($client_id) && !empty($client_id)){ + $client = $this->client_repository->getClientById($client_id); + if(!is_null($client)) { + $exception_class = get_class($ex); + $trail = new OAuth2TrailException(); + $trail->from_ip = IPHelper::getUserIp(); + $trail->exception_type = $exception_class; + $trail->client_id = $client->getId(); + $trail->Save(); + + //check exception count by type on last "MinutesWithoutExceptions" minutes... + $exception_count = intval(OAuth2TrailException::where('client_id', '=', intval($client->getId())) + ->where('exception_type', '=', $exception_class) + ->where('created_at', '>', DB::raw('( UTC_TIMESTAMP() - INTERVAL ' . $this->server_configuration_service->getConfigValue("OAuth2SecurityPolicy.MinutesWithoutExceptions") . ' MINUTE )')) + ->count()); + + if(array_key_exists($exception_class,$this->exception_dictionary)){ + $params = $this->exception_dictionary[$exception_class]; + $max_attempts = !is_null($params[0]) && !empty($params[0])? intval($this->server_configuration_service->getConfigValue($params[0])):0; + if ($exception_count >= $max_attempts) + $this->counter_measure->trigger(array('client_id' => $client->getId())); + } + } + } + } + + } catch (Exception $ex) { + Log::error($ex); + } + return $this; + } + + /** + * @param ISecurityPolicyCounterMeasure $counter_measure + * @return $this + */ + public function setCounterMeasure(ISecurityPolicyCounterMeasure $counter_measure) + { + $this->counter_measure = $counter_measure; + return $this; + } +} \ No newline at end of file diff --git a/app/Services/SecurityPolicies/RevokeAuthorizationCodeRelatedTokens.php b/app/Services/SecurityPolicies/RevokeAuthorizationCodeRelatedTokens.php new file mode 100644 index 00000000..07acd05c --- /dev/null +++ b/app/Services/SecurityPolicies/RevokeAuthorizationCodeRelatedTokens.php @@ -0,0 +1,59 @@ +token_service = $token_service; + } + + /** + * @param array $params + * @return $this|void + */ + public function trigger(array $params = array()) + { + try { + if (isset($params["auth_code"])) { + $auth_code = $params["auth_code"]; + $this->token_service->revokeAuthCodeRelatedTokens($auth_code); + } + } catch (Exception $ex) { + Log::error($ex); + } + return $this; + } +} \ No newline at end of file diff --git a/app/Services/ServicesProvider.php b/app/Services/ServicesProvider.php new file mode 100644 index 00000000..4eb1c7d1 --- /dev/null +++ b/app/Services/ServicesProvider.php @@ -0,0 +1,88 @@ +setCounterMeasure($delay_counter_measure); + + $revoke_tokens_counter_measure = App::make(\Services\SecurityPolicies\RevokeAuthorizationCodeRelatedTokens::class); + + $authorization_code_redeem_Policy = App::make(\Services\SecurityPolicies\AuthorizationCodeRedeemPolicy::class); + $authorization_code_redeem_Policy->setCounterMeasure($revoke_tokens_counter_measure); + + $lock_user_counter_measure = App::make(\Services\SecurityPolicies\LockUserCounterMeasure::class); + + $lock_user_security_policy = App::make(\Services\SecurityPolicies\LockUserSecurityPolicy::class); + $lock_user_security_policy->setCounterMeasure($lock_user_counter_measure); + + $oauth2_lock_client_counter_measure = App::make(\Services\SecurityPolicies\OAuth2LockClientCounterMeasure::class); + $oauth2_security_policy = App::make(\Services\SecurityPolicies\OAuth2SecurityPolicy::class); + $oauth2_security_policy->setCounterMeasure($oauth2_lock_client_counter_measure); + + $checkpoint_service = new CheckPointService($blacklist_security_policy); + $checkpoint_service->addPolicy($lock_user_security_policy); + $checkpoint_service->addPolicy($authorization_code_redeem_Policy); + $checkpoint_service->addPolicy($oauth2_security_policy); + return $checkpoint_service; + }); + + } + + public function provides() + { + return [ + \Services\IUserActionService::class, + \Services\SecurityPolicies\DelayCounterMeasure::class, + \Services\SecurityPolicies\LockUserCounterMeasure::class, + \Services\SecurityPolicies\RevokeAuthorizationCodeRelatedTokens::class, + \Services\SecurityPolicies\BlacklistSecurityPolicy::class, + \Services\SecurityPolicies\LockUserSecurityPolicy::class, + \Services\SecurityPolicies\OAuth2LockClientCounterMeasure::class, + \Services\SecurityPolicies\OAuth2SecurityPolicy::class, + \Services\SecurityPolicies\AuthorizationCodeRedeemPolicy::class, + UtilsServiceCatalog::CheckPointService, + ]; + } +} \ No newline at end of file diff --git a/app/Services/UserActionService.php b/app/Services/UserActionService.php new file mode 100644 index 00000000..fe7dcec5 --- /dev/null +++ b/app/Services/UserActionService.php @@ -0,0 +1,72 @@ +user_repository = $user_repository; + $this->tx_service = $tx_service; + } + + /** + * @param int $user_id + * @param string $ip + * @param string $user_action + * @param null|string $realm + * @return bool + */ + public function addUserAction($user_id, $ip, $user_action, $realm = null) + { + return $this->tx_service->transaction(function() use($user_id, $ip, $user_action, $realm){ + try { + + $action = new UserAction(); + $action->from_ip = $ip; + $action->user_action = $user_action; + $action->realm = $realm; + $user = $this->user_repository->get($user_id); + + if ($user) { + $user->actions()->save($action); + return true; + } + return false; + } catch (Exception $ex) { + Log::error($ex); + return false; + } + }); + + } +} \ No newline at end of file diff --git a/app/services/utils/BannedIPService.php b/app/Services/Utils/BannedIPService.php similarity index 61% rename from app/services/utils/BannedIPService.php rename to app/Services/Utils/BannedIPService.php index b5f656e0..c4d50f27 100644 --- a/app/services/utils/BannedIPService.php +++ b/app/Services/Utils/BannedIPService.php @@ -1,28 +1,53 @@ -log_service->error($ex); $res = false; } - return $res; } + /** + * @param $ip + * @return bool + */ public function delete($ip) { - $res = false; $cache_service = $this->cache_service; - $this_var = $this; - $this->tx_service->transaction(function () use ($ip, &$res, &$cache_service, &$this_var) { - - if ($banned_ip = $this_var->getByIP($ip)) { + return $this->tx_service->transaction(function () use ($ip, $cache_service) { + $res = false; + if ($banned_ip = $this->getByIP($ip)) { $res = $banned_ip->delete(); $cache_service->delete($ip); } + return $res; }); - - return $res; } + /** + * @param int $id + * @return BannedIP + */ public function get($id) { return BannedIP::find($id); } + /** + * @param int $ip + * @return BannedIP + */ public function getByIP($ip) { return BannedIP::where('ip', '=', $ip)->first(); } + /** + * @param int $page_nbr + * @param int $page_size + * @param array $filters + * @param array $fields + * @return mixed + */ public function getByPage($page_nbr = 1, $page_size = 10, array $filters = array(), array $fields = array('*')) { - DB::getPaginator()->setCurrentPage($page_nbr); - - return BannedIP::Filter($filters)->paginate($page_size, $fields); + return BannedIP::Filter($filters)->paginate($page_size, $fields, $pageName ='Page', $page_nbr); } } \ No newline at end of file diff --git a/app/services/utils/CheckPointService.php b/app/Services/Utils/CheckPointService.php similarity index 62% rename from app/services/utils/CheckPointService.php rename to app/Services/Utils/CheckPointService.php index a3e989f4..264748ee 100644 --- a/app/services/utils/CheckPointService.php +++ b/app/Services/Utils/CheckPointService.php @@ -1,18 +1,34 @@ -policies, $policy); + return $this; } } diff --git a/app/Services/Utils/EloquentTransactionService.php b/app/Services/Utils/EloquentTransactionService.php new file mode 100644 index 00000000..3e0b54ce --- /dev/null +++ b/app/Services/Utils/EloquentTransactionService.php @@ -0,0 +1,40 @@ +isMobile() ? 'join/register/mobile/community' : 'join/register'; - return sprintf("%s%s",ConfigFacade::getConfigValue("Assets.Url"),$path); + return sprintf("%s%s", ConfigFacade::getConfigValue("Assets.Url"),$path); } + /** + * @return string + */ public function getVerifyAccountUrl(){ $path = 'members/verification/resend'; - return sprintf("%s%s",ConfigFacade::getConfigValue("Assets.Url"),$path); + return sprintf("%s%s", ConfigFacade::getConfigValue("Assets.Url"),$path); } + /** + * @return string + */ public function getForgotPasswordUrl(){ $path = 'Security/lostpassword'; - return sprintf("%s%s",ConfigFacade::getConfigValue("Assets.Url"),$path); + return sprintf("%s%s", ConfigFacade::getConfigValue("Assets.Url"),$path); } } \ No newline at end of file diff --git a/app/services/utils/LockManagerService.php b/app/Services/Utils/LockManagerService.php similarity index 62% rename from app/services/utils/LockManagerService.php rename to app/Services/Utils/LockManagerService.php index f5351f08..69b28e40 100644 --- a/app/services/utils/LockManagerService.php +++ b/app/Services/Utils/LockManagerService.php @@ -1,15 +1,26 @@ -cache_service->delete($name); + return $this; } /** @@ -56,7 +71,7 @@ final class LockManagerService implements ILockManagerService { * @param int $lifetime * @return null * @throws UnacquiredLockException - * @throws \Exception + * @throws Exception */ public function lock($name, Closure $callback, $lifetime = 3600) { @@ -72,7 +87,7 @@ final class LockManagerService implements ILockManagerService { { throw $ex1; } - catch(\Exception $ex) + catch(Exception $ex) { $this->releaseLock($name); throw $ex; diff --git a/app/Services/Utils/LogService.php b/app/Services/Utils/LogService.php new file mode 100644 index 00000000..57e6f899 --- /dev/null +++ b/app/Services/Utils/LogService.php @@ -0,0 +1,55 @@ +redis = Redis::connection(); } - public function boot(){ - if(is_null($this->redis)){ - $this->redis = \RedisLV4::connection(); + public function boot() + { + if (is_null($this->redis)) + { + $this->redis = Redis::connection(); } } + /** * @param $key * @return mixed diff --git a/app/services/utils/ServerConfigurationService.php b/app/Services/Utils/ServerConfigurationService.php similarity index 88% rename from app/services/utils/ServerConfigurationService.php rename to app/Services/Utils/ServerConfigurationService.php index 1d56b91a..380a6a2e 100644 --- a/app/services/utils/ServerConfigurationService.php +++ b/app/Services/Utils/ServerConfigurationService.php @@ -1,31 +1,46 @@ - $identifier)); - - return $url; + return action("UserController@getIdentity", array("identifier" => $identifier)); } public function getOPEndpointURL() { - $url = action("OpenIdProviderController@endpoint"); - - return $url; + return action("OpenId\OpenIdProviderController@endpoint"); } /** diff --git a/app/Services/Utils/UtilsProvider.php b/app/Services/Utils/UtilsProvider.php new file mode 100644 index 00000000..b435015e --- /dev/null +++ b/app/Services/Utils/UtilsProvider.php @@ -0,0 +1,83 @@ +app['serverconfigurationservice'] = App::share(function ($app) { + return new ServerConfigurationService + ( + App::make(UtilsServiceCatalog::CacheService), + App::make(UtilsServiceCatalog::TransactionService) + ); + }); + + // setting facade + $this->app['externalurlservice'] = App::share(function ($app) { + return new ExternalUrlService(); + }); + + } + + public function provides() + { + return + [ + UtilsServiceCatalog::CacheService, + UtilsServiceCatalog::TransactionService, + UtilsServiceCatalog::LogService, + UtilsServiceCatalog::LockManagerService, + UtilsServiceCatalog::ServerConfigurationService, + UtilsServiceCatalog::BannedIpService, + \Services\Facades\ServerConfigurationService::class, + \Services\Facades\ExternalUrlService::class, + 'serverconfigurationservice', + 'externalurlservice', + 'ServerConfigurationService', + 'ExternalUrlService', + ]; + } + + public function when(){ + return array('redis'); + } +} \ No newline at end of file diff --git a/app/strategies/DefaultLoginStrategy.php b/app/Strategies/DefaultLoginStrategy.php similarity index 65% rename from app/strategies/DefaultLoginStrategy.php rename to app/Strategies/DefaultLoginStrategy.php index af5f9c6e..d059f994 100644 --- a/app/strategies/DefaultLoginStrategy.php +++ b/app/Strategies/DefaultLoginStrategy.php @@ -1,18 +1,26 @@ -auth_service->getCurrentUser(); $identifier = $user->getIdentifier(); - $this->user_action_service->addUserAction($this->auth_service->getCurrentUser(), IPHelper::getUserIp(), IUserActionService::LoginAction); + $this->user_action_service->addUserAction($this->auth_service->getCurrentUser()->getId(), IPHelper::getUserIp(), IUserActionService::LoginAction); $default_url = URL::action("UserController@getIdentity", array("identifier" => $identifier)); return Redirect::intended($default_url); - } public function cancelLogin() diff --git a/app/Strategies/DirectResponseStrategy.php b/app/Strategies/DirectResponseStrategy.php new file mode 100644 index 00000000..3aa772bf --- /dev/null +++ b/app/Strategies/DirectResponseStrategy.php @@ -0,0 +1,31 @@ +getContent(), $response->getHttpCode()); + $http_response->header('Content-Type', $response->getContentType()); + $http_response->header('Cache-Control','no-cache, no-store, max-age=0, must-revalidate'); + $http_response->header('Pragma','no-cache'); + return $http_response; + } +} \ No newline at end of file diff --git a/app/strategies/DisplayResponseJsonStrategy.php b/app/Strategies/DisplayResponseJsonStrategy.php similarity index 93% rename from app/strategies/DisplayResponseJsonStrategy.php rename to app/Strategies/DisplayResponseJsonStrategy.php index 3b57d382..47ce7406 100644 --- a/app/strategies/DisplayResponseJsonStrategy.php +++ b/app/Strategies/DisplayResponseJsonStrategy.php @@ -1,4 +1,4 @@ -getContent(); + $return_to = $response->getReturnTo(); + + if (is_null($return_to) || empty($return_to)) { + return Response::view('errors.404', array(), 404); + } + $return_to = (strpos($return_to, "?") == false) ? $return_to . "?" . $query_string : $return_to . "&" . $query_string; + + return Redirect::to($return_to) + ->header('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') + ->header('Pragma','no-cache'); + } +} \ No newline at end of file diff --git a/app/Strategies/IndirectResponseUrlFragmentStrategy.php b/app/Strategies/IndirectResponseUrlFragmentStrategy.php new file mode 100644 index 00000000..0c56be87 --- /dev/null +++ b/app/Strategies/IndirectResponseUrlFragmentStrategy.php @@ -0,0 +1,44 @@ +getContent(); + $return_to = $response->getReturnTo(); + + if (is_null($return_to) || empty($return_to)) { + return Response::view('errors.404', array(), 404);; + } + + $return_to = (strpos($return_to, "#") == false) ? $return_to . "#" . $fragment : $return_to . "&" . $fragment; + + return Redirect::to($return_to) + ->header('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') + ->header('Pragma','no-cache'); + } +} \ No newline at end of file diff --git a/app/Strategies/OAuth2AuthenticationStrategy.php b/app/Strategies/OAuth2AuthenticationStrategy.php new file mode 100644 index 00000000..5eccd17e --- /dev/null +++ b/app/Strategies/OAuth2AuthenticationStrategy.php @@ -0,0 +1,32 @@ +auth_service = $auth_service; - $this->memento_service = $memento_service; - $this->scope_service = $scope_service; - $this->client_service = $client_service; + $this->auth_service = $auth_service; + $this->memento_service = $memento_service; + $this->scope_repository = $scope_repository; + $this->client_repository = $client_repository; } public function getConsent() @@ -69,11 +74,11 @@ class OAuth2ConsentStrategy implements IConsentStrategy ); $client_id = $auth_request->getClientId(); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); $scopes = explode(' ',$auth_request->getScope()); - $requested_scopes = $this->scope_service->getScopesByName($scopes); + $requested_scopes = $this->scope_repository->getByName($scopes); - $data = array(); + $data = array(); $data['requested_scopes'] = $requested_scopes; $data['app_name'] = $client->getApplicationName(); $data['redirect_to'] = $auth_request->getRedirectUri(); @@ -96,6 +101,6 @@ class OAuth2ConsentStrategy implements IConsentStrategy public function postConsent($trust_action) { $this->auth_service->setUserAuthorizationResponse($trust_action); - return Redirect::action('OAuth2ProviderController@authorize'); + return Redirect::action('OAuth2\OAuth2ProviderController@auth'); } } \ No newline at end of file diff --git a/app/strategies/OAuth2LoginStrategy.php b/app/Strategies/OAuth2LoginStrategy.php similarity index 69% rename from app/strategies/OAuth2LoginStrategy.php rename to app/Strategies/OAuth2LoginStrategy.php index 7b89c0b5..2f005df7 100644 --- a/app/strategies/OAuth2LoginStrategy.php +++ b/app/Strategies/OAuth2LoginStrategy.php @@ -1,25 +1,29 @@ -user_action_service->addUserAction($this->auth_service->getCurrentUser(), IPHelper::getUserIp(), + $this->user_action_service->addUserAction($this->auth_service->getCurrentUser()->getId(), IPHelper::getUserIp(), IUserActionService::LoginAction, $auth_request->getRedirectUri()); - return Redirect::action("OAuth2ProviderController@authorize"); + return Redirect::action("OAuth2\OAuth2ProviderController@auth"); } public function cancelLogin() { $this->auth_service->setUserAuthenticationResponse(IAuthService::AuthenticationResponse_Cancel); - return Redirect::action("OAuth2ProviderController@authorize"); + return Redirect::action("OAuth2\OAuth2ProviderController@auth"); } /** diff --git a/app/strategies/OpenIdAuthenticationStrategy.php b/app/Strategies/OpenIdAuthenticationStrategy.php similarity index 51% rename from app/strategies/OpenIdAuthenticationStrategy.php rename to app/Strategies/OpenIdAuthenticationStrategy.php index c8092150..5e09cb48 100644 --- a/app/strategies/OpenIdAuthenticationStrategy.php +++ b/app/Strategies/OpenIdAuthenticationStrategy.php @@ -1,17 +1,25 @@ -memento_service->load()); if (is_null($msg) || !$msg->isValid()) throw new InvalidOpenIdMessageException(); - $this->user_action_service->addUserAction($this->auth_service->getCurrentUser(), IPHelper::getUserIp(), IUserActionService::ConsentAction, $msg->getParam(OpenIdProtocol::OpenIDProtocol_Realm)); + $this->user_action_service->addUserAction($this->auth_service->getCurrentUser()->getId(), IPHelper::getUserIp(), IUserActionService::ConsentAction, $msg->getParam(OpenIdProtocol::OpenIDProtocol_Realm)); $this->auth_service->setUserAuthorizationResponse($trust_action[0]); Session::remove('openid.auth.context'); Session::save(); - return Redirect::action('OpenIdProviderController@endpoint'); + return Redirect::action('OpenId\OpenIdProviderController@endpoint'); } return Redirect::action('UserController@getConsent'); } diff --git a/app/Strategies/OpenIdLoginStrategy.php b/app/Strategies/OpenIdLoginStrategy.php new file mode 100644 index 00000000..c577724e --- /dev/null +++ b/app/Strategies/OpenIdLoginStrategy.php @@ -0,0 +1,93 @@ +memento_service = $memento_service; + + parent::__construct($user_action_service, $auth_service); + } + + public function getLogin() + { + if (Auth::guest()) { + $msg = OpenIdMessage::buildFromMemento($this->memento_service->load()); + $auth_request = new OpenIdAuthenticationRequest($msg); + $params = array('realm' => $auth_request->getRealm()); + + if (!$auth_request->isIdentitySelectByOP()) { + $params['claimed_id'] = $auth_request->getClaimedId(); + $params['identity'] = $auth_request->getIdentity(); + $params['identity_select'] = false; + } else { + $params['identity_select'] = true; + } + + return View::make("login", $params); + } + return Redirect::action("UserController@getProfile"); + } + + public function postLogin() + { + //go to authentication flow again + $msg = OpenIdMessage::buildFromMemento($this->memento_service->load()); + + $this->user_action_service->addUserAction + ( + $this->auth_service->getCurrentUser()->getId(), + IPHelper::getUserIp(), + IUserActionService::LoginAction, + $msg->getParam(OpenIdProtocol::OpenIDProtocol_Realm) + ); + + return Redirect::action("OpenId\OpenIdProviderController@endpoint"); + } + + public function cancelLogin() + { + $this->auth_service->setUserAuthenticationResponse(IAuthService::AuthenticationResponse_Cancel); + + return Redirect::action("OpenId\OpenIdProviderController@endpoint"); + } +} \ No newline at end of file diff --git a/app/strategies/PostResponseStrategy.php b/app/Strategies/PostResponseStrategy.php similarity index 85% rename from app/strategies/PostResponseStrategy.php rename to app/Strategies/PostResponseStrategy.php index 80659899..453d383e 100644 --- a/app/strategies/PostResponseStrategy.php +++ b/app/Strategies/PostResponseStrategy.php @@ -1,4 +1,4 @@ -getContent(), $response->getHttpCode()); diff --git a/app/Strategies/StrategyProvider.php b/app/Strategies/StrategyProvider.php new file mode 100644 index 00000000..9fc7eda6 --- /dev/null +++ b/app/Strategies/StrategyProvider.php @@ -0,0 +1,66 @@ +isImplicit('fail'); } - public function validateBoolean($attribute, $value, $parameters) + public function validateBoolean($attribute, $value) { if (is_bool($value)) { return true; @@ -41,14 +55,14 @@ class CustomValidator extends Validator return strtoupper(trim($value)) == 'TRUE' || strtoupper(trim($value)) == 'FALSE' || strtoupper(trim($value)) == '1' || strtoupper(trim($value)) == '0'; } - public function validateText($attribute, $value, $parameters) + public function validateText($attribute, $value) { $value = trim($value); return preg_match("%^[a-zA-Z0-9\s\-\.\,\/\_]+$%i", $value) == 1; } - public function validateHttpmethod($attribute, $value, $parameters) + public function validateHttpmethod($attribute, $value) { $value = strtoupper(trim($value)); //'GET', 'HEAD','POST','PUT','DELETE','TRACE','CONNECT','OPTIONS' @@ -66,24 +80,24 @@ class CustomValidator extends Validator return array_key_exists($value, $allowed_http_verbs); } - public function validateRoute($attribute, $value, $parameters) + public function validateRoute($attribute, $value) { return true; } - public function validateScopename($attribute, $value, $parameters) + public function validateScopename($attribute, $value) { $value = trim($value); return preg_match("/^[a-zA-Z0-9\-\.\,\:\_\/]+$/", $value) == 1; } - public function validateHost($attribute, $value, $parameters) + public function validateHost($attribute, $value) { return filter_var(gethostbyname($value), FILTER_VALIDATE_IP) ? true : false; } - public function validateApplicationtype($attribute, $value, $parameters) + public function validateApplicationtype($attribute, $value) { if (!is_string($value)) { @@ -95,18 +109,17 @@ class CustomValidator extends Validator return in_array($value, Client::$valid_app_types); } - public function validateSslurl($attribute, $value, $parameters) + public function validateSslurl($attribute, $value) { return preg_match(";^https:\/\/([\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*$;i", $value) == 1; } - public function validateFreeText($attribute, $value, $parameters) + public function validateFreeText($attribute, $value) { - return preg_match('|^[a-z\-@_.,()\'"\s\:\/]+$|i', $value) == 1; + return preg_match('|^[a-z0-9A-Z\-@_.,()\'"\s\:\/]+$|i', $value) == 1; } - - public function validateSslorigin($attribute, $value, $parameters) + public function validateSslorigin($attribute, $value) { if (filter_var($value, FILTER_VALIDATE_URL)) { $parts = @parse_url($value); @@ -145,7 +158,7 @@ class CustomValidator extends Validator return false; } - public function validateEmailSet($attribute, $value, $parameters) + public function validateEmailSet($attribute, $value) { $emails = explode(',', $value); $res = true; @@ -159,7 +172,7 @@ class CustomValidator extends Validator return $res; } - public function validateUrlSet($attribute, $value, $parameters) + public function validateUrlSet($attribute, $value) { $urls = explode(',', $value); $res = true; @@ -173,32 +186,32 @@ class CustomValidator extends Validator return $res; } - public function validateTokenEndpointAuthMethod($attribute, $value, $parameters) + public function validateTokenEndpointAuthMethod($attribute, $value) { return in_array($value,OAuth2Protocol::$token_endpoint_auth_methods); } - public function validateSigningAlg($attribute, $value, $parameters) + public function validateSigningAlg($attribute, $value) { return in_array($value,OAuth2Protocol::$supported_signing_algorithms); } - public function validateSubjectType($attribute, $value, $parameters) + public function validateSubjectType($attribute, $value) { return in_array($value, Client::$valid_subject_types); } - public function validateEncryptedAlg($attribute, $value, $parameters) + public function validateEncryptedAlg($attribute, $value) { return in_array($value,OAuth2Protocol::$supported_key_management_algorithms); } - public function validateEncryptedEnc($attribute, $value, $parameters) + public function validateEncryptedEnc($attribute, $value) { return in_array($value,OAuth2Protocol::$supported_content_encryption_algorithms); } - public function validatePublicKeyPem($attribute, $value, $parameters) + public function validatePublicKeyPem($attribute, $value) { $res1 = strpos($value,'-----BEGIN PUBLIC KEY-----'); $res2 = strpos($value,'-----BEGIN RSA PUBLIC KEY-----'); @@ -214,9 +227,9 @@ class CustomValidator extends Validator return ($PKCS8 || $PKCS1) && $parsed; } - public function validatePublicKeyPemLength($attribute, $value, $parameters) + public function validatePublicKeyPemLength($attribute, $value) { - $rsa = new Crypt_RSA; + $rsa = new Crypt_RSA(); $parsed = $rsa->loadKey($value); return $parsed && $rsa->getSize() > 1024; @@ -288,7 +301,7 @@ class CustomValidator extends Validator $urls = explode(',', $value); $res = true; foreach ($urls as $url) { - $res = $app_type === IClient::ApplicationType_Native ? $this->validateUrl($attribute, $url, $parameters) : $this->validateSslurl($attribute, $url, $parameters); + $res = $app_type === IClient::ApplicationType_Native ? $this->validateCustomUrl($attribute, $url, $parameters): $this->validateSslurl($attribute, $url, $parameters); if (!$res) { break; } @@ -297,6 +310,14 @@ class CustomValidator extends Validator return $res; } + public function validateCustomUrl($attribute, $value, $paramenters){ + $uri = @parse_url($value); + if (!isset($uri['scheme'])) { + return false; + } + return true; + } + public function validateSslUrlSet($attribute, $value, $parameters) { diff --git a/app/config/app.php b/app/config/app.php deleted file mode 100644 index 22c67cbc..00000000 --- a/app/config/app.php +++ /dev/null @@ -1,187 +0,0 @@ - false, - - /* - |-------------------------------------------------------------------------- - | Application URL - |-------------------------------------------------------------------------- - | - | This URL is used by the console to properly generate URLs when using - | the Artisan command line tool. You should set this to the root of - | your application so that it is used when running Artisan tasks. - | - */ - - 'url' => '', - - /* - |-------------------------------------------------------------------------- - | Application Timezone - |-------------------------------------------------------------------------- - | - | Here you may specify the default timezone for your application, which - | will be used by the PHP date and date-time functions. We have gone - | ahead and set this to a sensible default for you out of the box. - | - */ - - 'timezone' => 'UTC', - - /* - |-------------------------------------------------------------------------- - | Application Locale Configuration - |-------------------------------------------------------------------------- - | - | The application locale determines the default locale that will be used - | by the translation service provider. You are free to set this value - | to any of the locales which will be supported by the application. - | - */ - - 'locale' => 'en', - - /* - |-------------------------------------------------------------------------- - | Encryption Key - |-------------------------------------------------------------------------- - | - | This key is used by the Illuminate encrypter service and should be set - | to a random, 32 character string, otherwise these encrypted strings - | will not be safe. Please do this before deploying an application! - | - */ - - 'key' => '', - - /* - |-------------------------------------------------------------------------- - | Autoloaded Service Providers - |-------------------------------------------------------------------------- - | - | The service providers listed here will be automatically loaded on the - | request to your application. Feel free to add your own services to - | this array to grant expanded functionality to your applications. - | - */ - - 'providers' => array( - 'Illuminate\Foundation\Providers\ArtisanServiceProvider', - 'Illuminate\Auth\AuthServiceProvider', - 'Illuminate\Cache\CacheServiceProvider', - 'Illuminate\Session\CommandsServiceProvider', - 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', - 'Illuminate\Routing\ControllerServiceProvider', - 'Illuminate\Cookie\CookieServiceProvider', - 'Illuminate\Database\DatabaseServiceProvider', - 'Illuminate\Encryption\EncryptionServiceProvider', - 'Illuminate\Filesystem\FilesystemServiceProvider', - 'Illuminate\Hashing\HashServiceProvider', - 'Illuminate\Html\HtmlServiceProvider', - 'Illuminate\Log\LogServiceProvider', - 'Illuminate\Mail\MailServiceProvider', - 'Illuminate\Database\MigrationServiceProvider', - 'Illuminate\Pagination\PaginationServiceProvider', - 'Illuminate\Queue\QueueServiceProvider', - 'Illuminate\Remote\RemoteServiceProvider', - 'Illuminate\Auth\Reminders\ReminderServiceProvider', - 'Illuminate\Database\SeedServiceProvider', - 'Illuminate\Session\SessionServiceProvider', - 'Illuminate\Translation\TranslationServiceProvider', - 'Illuminate\Validation\ValidationServiceProvider', - 'Illuminate\View\ViewServiceProvider', - 'Illuminate\Workbench\WorkbenchServiceProvider', - 'Illuminate\Redis\RedisServiceProvider', - 'services\utils\UtilsProvider', - 'repositories\RepositoriesProvider', - 'factories\FactoriesProvider', - 'services\oauth2\OAuth2ServiceProvider', - 'services\openid\OpenIdProvider', - 'auth\AuthenticationServiceProvider', - 'services\ServicesProvider', - 'strategies\StrategyProvider', - 'oauth2\OAuth2ServiceProvider', - 'openid\OpenIdServiceProvider', - 'Greggilbert\Recaptcha\RecaptchaServiceProvider', - 'services\oauth2\CORS\CORSProvider', - ), - - /* - |-------------------------------------------------------------------------- - | Service Provider Manifest - |-------------------------------------------------------------------------- - | - | The service provider manifest is used by Laravel to lazy load service - | providers which are not needed for each request, as well to keep a - | list of all of the services. Here, you may set its storage spot. - | - */ - - 'manifest' => storage_path().'/meta', - - /* - |-------------------------------------------------------------------------- - | Class Aliases - |-------------------------------------------------------------------------- - | - | This array of class aliases will be registered when this application - | is started. However, feel free to register as many as you wish as - | the aliases are "lazy" loaded so they don't hinder performance. - | - */ - - 'aliases' => array( - - 'App' => 'Illuminate\Support\Facades\App', - 'Artisan' => 'Illuminate\Support\Facades\Artisan', - 'Auth' => 'Illuminate\Support\Facades\Auth', - 'Blade' => 'Illuminate\Support\Facades\Blade', - 'Cache' => 'Illuminate\Support\Facades\Cache', - 'ClassLoader' => 'Illuminate\Support\ClassLoader', - 'Config' => 'Illuminate\Support\Facades\Config', - 'Controller' => 'Illuminate\Routing\Controller', - 'Cookie' => 'Illuminate\Support\Facades\Cookie', - 'Crypt' => 'Illuminate\Support\Facades\Crypt', - 'DB' => 'Illuminate\Support\Facades\DB', - 'Eloquent' => 'Illuminate\Database\Eloquent\Model', - 'Event' => 'Illuminate\Support\Facades\Event', - 'File' => 'Illuminate\Support\Facades\File', - 'Form' => 'Illuminate\Support\Facades\Form', - 'Hash' => 'Illuminate\Support\Facades\Hash', - 'HTML' => 'Illuminate\Support\Facades\HTML', - 'Input' => 'Illuminate\Support\Facades\Input', - 'Lang' => 'Illuminate\Support\Facades\Lang', - 'Log' => 'Illuminate\Support\Facades\Log', - 'Mail' => 'Illuminate\Support\Facades\Mail', - 'Paginator' => 'Illuminate\Support\Facades\Paginator', - 'Password' => 'Illuminate\Support\Facades\Password', - 'Queue' => 'Illuminate\Support\Facades\Queue', - 'Redirect' => 'Illuminate\Support\Facades\Redirect', - 'Request' => 'Illuminate\Support\Facades\Request', - 'Response' => 'Illuminate\Support\Facades\Response', - 'Route' => 'Illuminate\Support\Facades\Route', - 'Schema' => 'Illuminate\Support\Facades\Schema', - 'Seeder' => 'Illuminate\Database\Seeder', - 'Session' => 'Illuminate\Support\Facades\Session', - 'SSH' => 'Illuminate\Support\Facades\SSH', - 'Str' => 'Illuminate\Support\Str', - 'URL' => 'Illuminate\Support\Facades\URL', - 'Validator' => 'Illuminate\Support\Facades\Validator', - 'View' => 'Illuminate\Support\Facades\View', - 'RedisLV4' => 'Illuminate\Support\Facades\Redis', - ), - 'version' => 'XX.XX.XX', -); diff --git a/app/config/auth.php b/app/config/auth.php deleted file mode 100644 index 9cf486c2..00000000 --- a/app/config/auth.php +++ /dev/null @@ -1,71 +0,0 @@ - 'custom', - - /* - |-------------------------------------------------------------------------- - | Authentication Model - |-------------------------------------------------------------------------- - | - | When using the "Eloquent" authentication driver, we need to know which - | Eloquent model should be used to retrieve your users. Of course, it - | is often just the "User" model but you may use whatever you like. - | - */ - - 'model' => 'User', - - /* - |-------------------------------------------------------------------------- - | Authentication Table - |-------------------------------------------------------------------------- - | - | When using the "Database" authentication driver, we need to know which - | table should be used to retrieve your users. We have chosen a basic - | default value but you may easily change it to any table you like. - | - */ - - 'table' => 'users', - - /* - |-------------------------------------------------------------------------- - | Password Reminder Settings - |-------------------------------------------------------------------------- - | - | Here you may set the settings for password reminders, including a view - | that should be used as your password reminder e-mail. You will also - | be able to set the name of the table that holds the reset tokens. - | - | The "expire" time is the number of minutes that the reminder should be - | considered valid. This security feature keeps tokens short-lived so - | they have less time to be guessed. You may change this as needed. - | - */ - - 'reminder' => array( - - 'email' => 'emails.auth.reminder', - - 'table' => 'password_reminders', - - 'expire' => 60, - - ), - -); \ No newline at end of file diff --git a/app/config/cache.php b/app/config/cache.php deleted file mode 100644 index ce898423..00000000 --- a/app/config/cache.php +++ /dev/null @@ -1,89 +0,0 @@ - 'file', - - /* - |-------------------------------------------------------------------------- - | File Cache Location - |-------------------------------------------------------------------------- - | - | When using the "file" cache driver, we need a location where the cache - | files may be stored. A sensible default has been specified, but you - | are free to change it to any other place on disk that you desire. - | - */ - - 'path' => storage_path().'/cache', - - /* - |-------------------------------------------------------------------------- - | Database Cache Connection - |-------------------------------------------------------------------------- - | - | When using the "database" cache driver you may specify the connection - | that should be used to store the cached items. When this option is - | null the default database connection will be utilized for cache. - | - */ - - 'connection' => null, - - /* - |-------------------------------------------------------------------------- - | Database Cache Table - |-------------------------------------------------------------------------- - | - | When using the "database" cache driver we need to know the table that - | should be used to store the cached items. A default table name has - | been provided but you're free to change it however you deem fit. - | - */ - - 'table' => 'cache', - - /* - |-------------------------------------------------------------------------- - | Memcached Servers - |-------------------------------------------------------------------------- - | - | Now you may specify an array of your Memcached servers that should be - | used when utilizing the Memcached cache driver. All of the servers - | should contain a value for "host", "port", and "weight" options. - | - */ - - 'memcached' => array( - - array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100), - - ), - - /* - |-------------------------------------------------------------------------- - | Cache Key Prefix - |-------------------------------------------------------------------------- - | - | When utilizing a RAM based store such as APC or Memcached, there might - | be other applications utilizing the same cache. So, we'll specify a - | value to get prefixed to all our keys so we can avoid collisions. - | - */ - - 'prefix' => 'laravel', - -); diff --git a/app/config/compile.php b/app/config/compile.php deleted file mode 100644 index 54d7185b..00000000 --- a/app/config/compile.php +++ /dev/null @@ -1,18 +0,0 @@ - 'true', - /** - * http://www.w3.org/TR/cors/#access-control-max-age-response-header - */ - 'UsePreflightCaching' => true, - 'MaxAge' => 32000, - /** - * http://www.w3.org/TR/cors/#access-control-allow-headers-response-header - */ - 'AllowedHeaders' => 'origin, content-type, accept, authorization, x-requested-with', - /** - * http://www.w3.org/TR/cors/#access-control-allow-methods-response-header - */ - 'AllowedMethods' => 'GET, POST, OPTIONS, PUT, DELETE', -); \ No newline at end of file diff --git a/app/config/database.php b/app/config/database.php deleted file mode 100644 index 4ec6849d..00000000 --- a/app/config/database.php +++ /dev/null @@ -1,107 +0,0 @@ - PDO::FETCH_CLASS, - - /* - |-------------------------------------------------------------------------- - | Default Database Connection Name - |-------------------------------------------------------------------------- - | - | Here you may specify which of the database connections below you wish - | to use as your default connection for all database work. Of course - | you may use many connections at once using the Database library. - | - */ - - 'default' => 'openstackid', - - /* - |-------------------------------------------------------------------------- - | Database Connections - |-------------------------------------------------------------------------- - | - | Here are each of the database connections setup for your application. - | Of course, examples of configuring each database platform that is - | supported by Laravel is shown below to make development simple. - | - | - | All database work in Laravel is done through the PHP PDO facilities - | so make sure you have the driver for your particular database of - | choice installed on your machine before you begin development. - | - */ - - 'connections' => array( - //primary DB - 'openstackid' => array( - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'database', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ), - //secondary DB (OS Membership) - 'os_members' => array( - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'database', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ), - ), - - /* - |-------------------------------------------------------------------------- - | Migration Repository Table - |-------------------------------------------------------------------------- - | - | This table keeps track of all the migrations that have already run for - | your application. Using this information, we can determine which of - | the migrations on disk have not actually be run in the databases. - | - */ - - 'migrations' => 'migrations', - - /* - |-------------------------------------------------------------------------- - | Redis Databases - |-------------------------------------------------------------------------- - | - | Redis is an open source, fast, and advanced key-value store that also - | provides a richer set of commands than a typical key-value systems - | such as APC or Memcached. Laravel makes it easy to dig right in. - | - */ - - 'redis' => array( - - 'cluster' => false, - - 'default' => array( - 'host' => '127.0.0.1', - 'port' => 6379, - 'database' => 0, - ), - - ), -); diff --git a/app/config/log.php b/app/config/log.php deleted file mode 100644 index 4ce8a2a3..00000000 --- a/app/config/log.php +++ /dev/null @@ -1,11 +0,0 @@ - '', - //The sender of the mail - 'from_email' => '', -); \ No newline at end of file diff --git a/app/config/mail.php b/app/config/mail.php deleted file mode 100644 index aafb04ab..00000000 --- a/app/config/mail.php +++ /dev/null @@ -1,124 +0,0 @@ - 'mail', - - /* - |-------------------------------------------------------------------------- - | SMTP Host Address - |-------------------------------------------------------------------------- - | - | Here you may provide the host address of the SMTP server used by your - | applications. A default option is provided that is compatible with - | the Postmark mail service, which will provide reliable delivery. - | - */ - - 'host' => 'smtp.mailgun.org', - - /* - |-------------------------------------------------------------------------- - | SMTP Host Port - |-------------------------------------------------------------------------- - | - | This is the SMTP port used by your application to delivery e-mails to - | users of your application. Like the host we have set this value to - | stay compatible with the Postmark e-mail application by default. - | - */ - - 'port' => 587, - - /* - |-------------------------------------------------------------------------- - | Global "From" Address - |-------------------------------------------------------------------------- - | - | You may wish for all e-mails sent by your application to be sent from - | the same address. Here, you may specify a name and address that is - | used globally for all e-mails that are sent by your application. - | - */ - - 'from' => array('address' => null, 'name' => null), - - /* - |-------------------------------------------------------------------------- - | E-Mail Encryption Protocol - |-------------------------------------------------------------------------- - | - | Here you may specify the encryption protocol that should be used when - | the application send e-mail messages. A sensible default using the - | transport layer security protocol should provide great security. - | - */ - - 'encryption' => 'tls', - - /* - |-------------------------------------------------------------------------- - | SMTP Server Username - |-------------------------------------------------------------------------- - | - | If your SMTP server requires a username for authentication, you should - | set it here. This will get used to authenticate with your server on - | connection. You may also set the "password" value below this one. - | - */ - - 'username' => null, - - /* - |-------------------------------------------------------------------------- - | SMTP Server Password - |-------------------------------------------------------------------------- - | - | Here you may set the password required by your SMTP server to send out - | messages from your application. This will be given to the server on - | connection so that the application will be able to send messages. - | - */ - - 'password' => null, - - /* - |-------------------------------------------------------------------------- - | Sendmail System Path - |-------------------------------------------------------------------------- - | - | When using the "sendmail" driver to send e-mails, we will need to know - | the path to where Sendmail lives on this server. A default path has - | been provided here, which will work well on most of your systems. - | - */ - - 'sendmail' => '/usr/sbin/sendmail -bs', - - /* - |-------------------------------------------------------------------------- - | Mail "Pretend" - |-------------------------------------------------------------------------- - | - | When this option is enabled, e-mail will not actually be sent over the - | web and will instead be written to your application's logs files so - | you may inspect the message. This is great for local development. - | - */ - - 'pretend' => false, - -); \ No newline at end of file diff --git a/app/config/packages/greggilbert/recaptcha/config.php b/app/config/packages/greggilbert/recaptcha/config.php deleted file mode 100644 index 783f2373..00000000 --- a/app/config/packages/greggilbert/recaptcha/config.php +++ /dev/null @@ -1,26 +0,0 @@ - '', - 'private_key' => '', - - /* - |-------------------------------------------------------------------------- - | Template - |-------------------------------------------------------------------------- - | - | Set a template to use if you don't want to use the standard one. - | - */ - 'template' => '', - -); \ No newline at end of file diff --git a/app/config/production/.gitkeep b/app/config/production/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/config/queue.php b/app/config/queue.php deleted file mode 100644 index 6d01e569..00000000 --- a/app/config/queue.php +++ /dev/null @@ -1,63 +0,0 @@ - 'sync', - - /* - |-------------------------------------------------------------------------- - | Queue Connections - |-------------------------------------------------------------------------- - | - | Here you may configure the connection information for each server that - | is used by your application. A default configuration has been added - | for each back-end shipped with Laravel. You are free to add more. - | - */ - - 'connections' => array( - - 'sync' => array( - 'driver' => 'sync', - ), - - 'beanstalkd' => array( - 'driver' => 'beanstalkd', - 'host' => 'localhost', - 'queue' => 'default', - ), - - 'sqs' => array( - 'driver' => 'sqs', - 'key' => 'your-public-key', - 'secret' => 'your-secret-key', - 'queue' => 'your-queue-url', - 'region' => 'us-east-1', - ), - - 'iron' => array( - 'driver' => 'iron', - 'project' => 'your-project-id', - 'token' => 'your-token', - 'queue' => 'your-queue-name', - ), - - ), - 'failed' => array( - 'database' => 'mysql', 'table' => 'failed_jobs', - ), - -); diff --git a/app/config/remote.php b/app/config/remote.php deleted file mode 100644 index c8bc303b..00000000 --- a/app/config/remote.php +++ /dev/null @@ -1,59 +0,0 @@ - 'production', - - /* - |-------------------------------------------------------------------------- - | Remote Server Connections - |-------------------------------------------------------------------------- - | - | These are the servers that will be accessible via the SSH task runner - | facilities of Laravel. This feature radically simplifies executing - | tasks on your servers, such as deploying out these applications. - | - */ - - 'connections' => array( - - 'production' => array( - 'host' => '', - 'username' => '', - 'password' => '', - 'key' => '', - 'keyphrase' => '', - 'root' => '/var/www', - ), - - ), - - /* - |-------------------------------------------------------------------------- - | Remote Server Groups - |-------------------------------------------------------------------------- - | - | Here you may list connections under a single group name, which allows - | you to easily access all of the servers at once using a short name - | that is extremely easy to remember, such as "web" or "database". - | - */ - - 'groups' => array( - - 'web' => array('production') - - ), - -); \ No newline at end of file diff --git a/app/config/server.php b/app/config/server.php deleted file mode 100644 index aa20bbf7..00000000 --- a/app/config/server.php +++ /dev/null @@ -1,59 +0,0 @@ - 'https://www.openstack.org/', - 'Support_Email' => 'noreply@openstack.org', - 'MaxFailed_Login_Attempts' => 10, - 'MaxFailed_LoginAttempts_2ShowCaptcha' => 3, - //openid default values - 'OpenId_Private_Association_Lifetime' => 240, - 'OpenId_Session_Association_Lifetime' => 21600, - 'OpenId_Nonce_Lifetime' => 360, - /** - * Security Policies Configuration - */ - 'BlacklistSecurityPolicy_BannedIpLifeTimeSeconds' => 21600, - 'BlacklistSecurityPolicy_MinutesWithoutExceptions' => 5, - 'BlacklistSecurityPolicy_MaxReplayAttackExceptionAttempts' => 3, - 'BlacklistSecurityPolicy_ReplayAttackExceptionInitialDelay' => 10, - 'BlacklistSecurityPolicy_MaxInvalidNonceAttempts' => 10, - 'BlacklistSecurityPolicy_InvalidNonceInitialDelay' => 10, - 'BlacklistSecurityPolicy_MaxInvalidOpenIdMessageExceptionAttempts' => 10, - 'BlacklistSecurityPolicy_InvalidOpenIdMessageExceptionInitialDelay' => 10, - 'BlacklistSecurityPolicy_MaxOpenIdInvalidRealmExceptionAttempts' => 10, - 'BlacklistSecurityPolicy_OpenIdInvalidRealmExceptionInitialDelay' => 10, - 'BlacklistSecurityPolicy_MaxInvalidOpenIdMessageModeAttempts' => 10, - 'BlacklistSecurityPolicy_InvalidOpenIdMessageModeInitialDelay' => 10, - 'BlacklistSecurityPolicy_MaxInvalidOpenIdAuthenticationRequestModeAttempts' => 10, - 'BlacklistSecurityPolicy_InvalidOpenIdAuthenticationRequestModeInitialDelay' => 10, - 'BlacklistSecurityPolicy_MaxAuthenticationExceptionAttempts' => 10, - 'BlacklistSecurityPolicy_AuthenticationExceptionInitialDelay' => 20, - 'BlacklistSecurityPolicy_MaxInvalidAssociationAttempts' => 10, - 'BlacklistSecurityPolicy_InvalidAssociationInitialDelay' => 20, - 'BlacklistSecurityPolicy_OAuth2_MaxAuthCodeReplayAttackAttempts' => 3, - 'BlacklistSecurityPolicy_OAuth2_AuthCodeReplayAttackInitialDelay' => 10, - 'BlacklistSecurityPolicy_OAuth2_MaxInvalidAuthorizationCodeAttempts' => 3, - 'BlacklistSecurityPolicy_OAuth2_InvalidAuthorizationCodeInitialDelay' => 10, - 'BlacklistSecurityPolicy_OAuth2_MaxInvalidBearerTokenDisclosureAttempt' => 3, - 'BlacklistSecurityPolicy_OAuth2_BearerTokenDisclosureAttemptInitialDelay' => 10, - //oauth2 default config values - 'OAuth2_AuthorizationCode_Lifetime' => 240, - 'OAuth2_AccessToken_Lifetime' => 3600, - // in seconds , should be equal to session.lifetime (120 minutes) - 'OAuth2_IdToken_Lifetime' => 7200, - 'OAuth2_RefreshToken_Lifetime' => 0, - 'OAuth2_Enable' => true, - //oauth2 security policy configuration - 'OAuth2SecurityPolicy_MinutesWithoutExceptions' => 2, - 'OAuth2SecurityPolicy_MaxBearerTokenDisclosureAttempts' => 5, - 'OAuth2SecurityPolicy_MaxInvalidClientExceptionAttempts' => 10, - 'OAuth2SecurityPolicy_MaxInvalidRedeemAuthCodeAttempts' => 10, - 'OAuth2SecurityPolicy_MaxInvalidClientCredentialsAttempts' => 5, - 'Banning_Enable' => true, - 'FileLog_Level' => 'warning', - 'EmailLog_Level' => 'error', -); \ No newline at end of file diff --git a/app/config/session.php b/app/config/session.php deleted file mode 100644 index a362693b..00000000 --- a/app/config/session.php +++ /dev/null @@ -1,129 +0,0 @@ - 'redis', - - /* - |-------------------------------------------------------------------------- - | Session Lifetime - |-------------------------------------------------------------------------- - | - | Here you may specify the number of minutes that you wish the session - | to be allowed to remain idle before it expires. If you want them - | to immediately expire when the browser closes, set it to zero. - | - */ - - 'lifetime' => 120, - - 'expire_on_close' => false, - - /* - |-------------------------------------------------------------------------- - | Session File Location - |-------------------------------------------------------------------------- - | - | When using the native session driver, we need a location where session - | files may be stored. A default has been set for you but a different - | location may be specified. This is only needed for file sessions. - | - */ - - 'files' => storage_path().'/sessions', - - /* - |-------------------------------------------------------------------------- - | Session Database Connection - |-------------------------------------------------------------------------- - | - | When using the "database" session driver, you may specify the database - | connection that should be used to manage your sessions. This should - | correspond to a connection in your "database" configuration file. - | - */ - - 'connection' => null, - - /* - |-------------------------------------------------------------------------- - | Session Database Table - |-------------------------------------------------------------------------- - | - | When using the "database" session driver, you may specify the table we - | should use to manage the sessions. Of course, a sensible default is - | provided for you; however, you are free to change this as needed. - | - */ - - 'table' => 'sessions', - - /* - |-------------------------------------------------------------------------- - | Session Sweeping Lottery - |-------------------------------------------------------------------------- - | - | Some session drivers must manually sweep their storage location to get - | rid of old sessions from storage. Here are the chances that it will - | happen on a given request. By default, the odds are 2 out of 100. - | - */ - - 'lottery' => array(2, 100), - - /* - |-------------------------------------------------------------------------- - | Session Cookie Name - |-------------------------------------------------------------------------- - | - | Here you may change the name of the cookie used to identify a session - | instance by ID. The name specified here will get used every time a - | new session cookie is created by the framework for every driver. - | - */ - - 'cookie' => 'openstackid_session', - - /* - |-------------------------------------------------------------------------- - | Session Cookie Path - |-------------------------------------------------------------------------- - | - | The session cookie path determines the path for which the cookie will - | be regarded as available. Typically, this will be the root path of - | your application but you are free to change this when necessary. - | - */ - - 'path' => '/', - - /* - |-------------------------------------------------------------------------- - | Session Cookie Domain - |-------------------------------------------------------------------------- - | - | Here you may change the domain of the cookie used to identify a session - | in your application. This will determine which domains the cookie is - | available to in your application. A sensible default has been set. - | - */ - - 'domain' => null, - - - -); diff --git a/app/config/staging/.gitkeep b/app/config/staging/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/config/testing/.gitkeep b/app/config/testing/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/config/testing/cache.php b/app/config/testing/cache.php deleted file mode 100644 index f55b773a..00000000 --- a/app/config/testing/cache.php +++ /dev/null @@ -1,20 +0,0 @@ - 'redis', - -); \ No newline at end of file diff --git a/app/config/testing/session.php b/app/config/testing/session.php deleted file mode 100644 index d92f8515..00000000 --- a/app/config/testing/session.php +++ /dev/null @@ -1,21 +0,0 @@ - 'redis', - -); \ No newline at end of file diff --git a/app/config/view.php b/app/config/view.php deleted file mode 100644 index 34b8f387..00000000 --- a/app/config/view.php +++ /dev/null @@ -1,31 +0,0 @@ - array(__DIR__.'/../views'), - - /* - |-------------------------------------------------------------------------- - | Pagination View - |-------------------------------------------------------------------------- - | - | This view will be used to render the pagination link output, and can - | be easily customized here to show any view you like. A clean view - | compatible with Twitter's Bootstrap is given to you by default. - | - */ - - 'pagination' => 'pagination::slider-3', - -); diff --git a/app/config/workbench.php b/app/config/workbench.php deleted file mode 100644 index 56bee526..00000000 --- a/app/config/workbench.php +++ /dev/null @@ -1,31 +0,0 @@ - '', - - /* - |-------------------------------------------------------------------------- - | Workbench Author E-Mail Address - |-------------------------------------------------------------------------- - | - | Like the option above, your e-mail address is used when generating new - | workbench packages. The e-mail is placed in your composer.json file - | automatically after the package is created by the workbench tool. - | - */ - - 'email' => '', - -); \ No newline at end of file diff --git a/app/controllers/.gitkeep b/app/controllers/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/controllers/BaseController.php b/app/controllers/BaseController.php deleted file mode 100644 index b640e64e..00000000 --- a/app/controllers/BaseController.php +++ /dev/null @@ -1,18 +0,0 @@ -layout)) { - $this->layout = View::make($this->layout); - } - } - -} \ No newline at end of file diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php deleted file mode 100644 index 7325a6cd..00000000 --- a/app/controllers/HomeController.php +++ /dev/null @@ -1,29 +0,0 @@ -discovery = $discovery; - } - - public function index() - { - - if ($this->isDiscoveryRequest()) - return $this->discovery->idp(); - if (Auth::guest()) { - Session::flush(); - Session::regenerate(); - return View::make("home"); - } - else - return Redirect::action("UserController@getProfile"); - } -} \ No newline at end of file diff --git a/app/controllers/apis/ClientApiController.php b/app/controllers/apis/ClientApiController.php deleted file mode 100644 index 37337629..00000000 --- a/app/controllers/apis/ClientApiController.php +++ /dev/null @@ -1,537 +0,0 @@ -client_service = $client_service; - $this->scope_service = $scope_service; - $this->token_service = $token_service; - $this->auth_service = $auth_service; - - //set filters allowed values - $this->allowed_filter_fields = array('user_id'); - $this->allowed_projection_fields = array('*'); - } - - public function get($id) - { - try { - $client = $this->client_service->get($id); - if (is_null($client)) - { - return $this->error404(array('error' => 'client not found')); - } - $data = $client->toArray(); - - return $this->ok($data); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - /** - * Deletes an existing client - * @param $id - * @return mixed - */ - public function delete($id) - { - try { - $res = $this->client_service->deleteClientByIdentifier($id); - return $res ? $this->deleted() : $this->error404(array('error' => 'operation failed')); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - /** - * Creates an existing client - * @return mixed - */ - public function create() - { - try { - $values = Input::All(); - - // Build the validation constraint set. - $rules = array( - 'app_name' => 'required|freetext|max:255', - 'app_description' => 'required|freetext|max:512', - 'website' => 'url', - 'admin_users' => 'user_ids', - 'application_type' => 'required|applicationtype', - ); - - // Create a new validator instance. - $validation = Validator::make($values, $rules); - - if ($validation->fails()) { - $messages = $validation->messages()->toArray(); - - return $this->error400(array('error' => 'validation', 'messages' => $messages)); - } - - if ($this->client_service->existClientAppName($values['app_name'])) { - return $this->error400(array('error' => 'application Name already exists!.')); - } - $admin_users = trim($values['admin_users']); - $admin_users = empty($admin_users) ? array():explode(',',$admin_users); - - $new_client = $this->client_service->addClient - ( - $values['application_type'], - trim($values['app_name']), - trim($values['app_description']), - trim($values['website']), - $admin_users - ); - - return $this->created - ( - array - ( - 'id' => $new_client->id, - 'client_id' => $new_client->client_id, - 'client_secret' => $new_client->client_secret, - ) - ); - - } catch (Exception $ex) { - $this->log_service->error($ex); - return $this->error500($ex); - } - } - - /** - * @return mixed - */ - public function update() - { - try { - - $values = Input::all(); - - $rules = array( - 'id' => 'required|integer', - 'application_type' =>'required|application_type', - 'app_name' => 'sometimes|required|freetext|max:255', - 'app_description' => 'sometimes|required|freetext|max:512', - 'website' => 'url', - 'active' => 'sometimes|required|boolean', - 'locked' => 'sometimes|required|boolean', - 'use_refresh_token' => 'sometimes|required|boolean', - 'rotate_refresh_token' => 'sometimes|required|boolean', - 'contacts' => 'email_set', - 'logo_uri' => 'url', - 'tos_uri' => 'url', - 'redirect_uris' => 'custom_url_set:application_type', - 'post_logout_redirect_uris' => 'ssl_url_set', - 'allowed_origins' => 'ssl_url_set', - 'logout_uri' => 'url', - 'logout_session_required' => 'sometimes|required|boolean', - 'logout_use_iframe' => 'sometimes|required|boolean', - 'policy_uri' => 'url', - 'jwks_uri' => 'url', - 'default_max_age' => 'sometimes|required|integer', - 'logout_use_iframe' => 'sometimes|required|boolean', - 'require_auth_time' => 'sometimes|required|boolean', - 'token_endpoint_auth_method' => 'sometimes|required|token_endpoint_auth_method', - 'token_endpoint_auth_signing_alg' => 'sometimes|required|signing_alg', - 'subject_type' => 'sometimes|required|subject_type', - 'userinfo_signed_response_alg' => 'sometimes|required|signing_alg', - 'userinfo_encrypted_response_alg' => 'sometimes|required|encrypted_alg', - 'userinfo_encrypted_response_enc' => 'sometimes|required|encrypted_enc', - 'id_token_signed_response_alg' => 'sometimes|required|signing_alg', - 'id_token_encrypted_response_alg' => 'sometimes|required|encrypted_alg', - 'id_token_encrypted_response_enc' => 'sometimes|required|encrypted_enc', - 'admin_users' => 'user_ids', - ); - - // Creates a Validator instance and validates the data. - $validation = Validator::make($values, $rules); - - if ($validation->fails()) { - $messages = $validation->messages()->toArray(); - - return $this->error400(array('error' => 'validation', 'messages' => $messages)); - } - - $res = $this->client_service->update(intval($values['id']), $values); - - return $res ? $this->ok() : $this->error400(array('error' => 'operation failed')); - - } - catch (AbsentClientException $ex1) - { - $this->log_service->error($ex1); - return $this->error404(array('error' => $ex1->getMessage())); - } - catch(ValidationException $ex2) - { - $this->log_service->error($ex2); - return $this->error412(array($ex2->getMessage())); - } - catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - /** - * @return mixed - */ - public function getByPage() - { - try { - - $items = array(); - $user = $this->auth_service->getCurrentUser(); - $clients = $user->getClients(); - - foreach ($clients as $client) - { - $data = $client->toArray(); - $data['application_type'] = $client->getFriendlyApplicationType(); - $data['is_own'] = $client->isOwner($this->auth_service->getCurrentUser()); - $data['modified_by'] = $client->getEditedByNice(); - array_push($items, $data); - } - - return $this->ok - ( - array - ( - 'page' => $items, - 'total_items' => count($items) - ) - ); - - } - catch (Exception $ex) - { - $this->log_service->error($ex); - return $this->error500($ex); - } - } - - public function addAllowedScope($id, $scope_id) - { - try - { - $this->client_service->addClientScope($id, $scope_id); - return $this->ok(); - } - catch (EntityNotFoundException $ex1) - { - $this->log_service->error($ex1); - return $this->error404(array('error' => $ex1->getMessage())); - } - catch (InvalidApiScope $ex2) - { - $this->log_service->error($ex2); - return $this->error412(array('messages' => $ex2->getMessage())); - } - catch (Exception $ex) - { - $this->log_service->error($ex); - return $this->error500($ex); - } - } - - public function removeAllowedScope($id, $scope_id) - { - try - { - $res = $this->client_service->deleteClientScope($id, $scope_id); - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - } catch (AbsentClientException $ex1) { - $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function activate($id) - { - try { - $res = $this->client_service->activateClient($id, true); - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - } catch (AbsentClientException $ex1) { - $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function deactivate($id) - { - try { - $res = $this->client_service->activateClient($id, false); - - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - } catch (AbsentClientException $ex1) { - $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function regenerateClientSecret($id) - { - try - { - $client = $this->client_service->regenerateClientSecret($id); - - return !is_null($client) ? - $this->ok - ( - array - ( - 'new_secret' => $client->getClientSecret(), - 'new_expiration_date' => $client->getClientSecretExpiration(), - ) - ) : $this->error404(array('error' => 'operation failed')); - } - catch (Exception $ex) - { - $this->log_service->error($ex); - return $this->error500($ex); - } - } - - public function setRefreshTokenClient($id) - { - try { - $values = Input::All(); - - // Build the validation constraint set. - $rules = array( - 'use_refresh_token' => 'required|boolean' - ); - - // Creates a Validator instance and validates the data. - $validation = Validator::make($values, $rules); - if ($validation->fails()) { - $messages = $validation->messages()->toArray(); - - return $this->error400(array('error' => 'validation', 'messages' => $messages)); - } - - $res = $this->client_service->setRefreshTokenUsage($id, $values['use_refresh_token']); - - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - - } catch (AbsentClientException $ex1) { - $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function setRotateRefreshTokenPolicy($id) - { - try { - $values = Input::All(); - - // Build the validation constraint set. - $rules = array( - 'rotate_refresh_token' => 'required|boolean' - ); - // Creates a Validator instance and validates the data. - $validation = Validator::make($values, $rules); - if ($validation->fails()) { - $messages = $validation->messages()->toArray(); - - return $this->error400(array('error' => 'validation', 'messages' => $messages)); - } - - $res = $this->client_service->setRotateRefreshTokenPolicy($id, $values['rotate_refresh_token']); - - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - } catch (AbsentClientException $ex1) { - $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function revokeToken($id, $value, $hint) - { - try { - $res = false; - $client = $this->client_service->getClientByIdentifier($id); - switch ($hint) { - case 'access-token': { - $token = $this->token_service->getAccessToken($value, true); - if (is_null($token)) { - return $this->error404(array('error' => sprintf('access token %s does not exists!', $value))); - } - Log::debug(sprintf('access token client id %s - client id %s ',$token->getClientId() , $client->client_id)); - if ($token->getClientId() !== $client->client_id) { - return $this->error412(array( - 'error' => sprintf('access token %s does not belongs to client id !', $value, $id) - )); - } - $res = $this->token_service->revokeAccessToken($value, true); - } - break; - case 'refresh-token': { - $token = $this->token_service->getRefreshToken($value, true); - if (is_null($token)) { - return $this->error404(array('error' => sprintf('refresh token %s does not exists!', $value))); - } - Log::debug(sprintf('refresh token client id %s - client id %s ',$token->getClientId() , $client->client_id)); - if ($token->getClientId() !== $client->client_id) { - return $this->error412(array( - 'error' => sprintf('refresh token %s does not belongs to client id !', $value, $id) - )); - } - $res = $this->token_service->revokeRefreshToken($value, true); - } - break; - default: - break; - } - - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function getAccessTokens($id) - { - try { - $client = $this->client_service->getClientByIdentifier($id); - $access_tokens = $this->token_service->getAccessTokenByClient($client->client_id); - $res = array(); - foreach ($access_tokens as $token) { - array_push($res, array( - 'value' => $token->value, - 'scope' => $token->scope, - 'lifetime' => $token->getRemainingLifetime(), - 'issued' => $token->created_at->format('Y-m-d H:i:s') - )); - } - - return $this->ok(array('access_tokens' => $res)); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - public function getRefreshTokens($id) - { - try { - $client = $this->client_service->getClientByIdentifier($id); - $refresh_tokens = $this->token_service->getRefreshTokenByClient($client->client_id); - $res = array(); - foreach ($refresh_tokens as $token) { - array_push($res, array( - 'value' => $token->value, - 'scope' => $token->scope, - 'lifetime' => $token->getRemainingLifetime(), - 'issued' => $token->created_at->format('Y-m-d H:i:s') - )); - } - - return $this->ok(array('refresh_tokens' => $res)); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - - /** - * @param $id - * @return mixed - */ - public function unlock($id) - { - try { - $res = $this->client_service->unlockClient($id); - - return $res ? $this->ok() : $this->error404(array('error' => 'operation failed')); - } catch (AbsentClientException $ex1) { - $this->log_service->error($ex1); - - return $this->error404(array('error' => $ex1->getMessage())); - } catch (Exception $ex) { - $this->log_service->error($ex); - - return $this->error500($ex); - } - } - -} \ No newline at end of file diff --git a/app/controllers/apis/protected/OAuth2ProtectedController.php b/app/controllers/apis/protected/OAuth2ProtectedController.php deleted file mode 100644 index 8ad212ce..00000000 --- a/app/controllers/apis/protected/OAuth2ProtectedController.php +++ /dev/null @@ -1,32 +0,0 @@ -resource_server_context = $resource_server_context; - } -} \ No newline at end of file diff --git a/app/controllers/openid/DiscoveryController.php b/app/controllers/openid/DiscoveryController.php deleted file mode 100644 index a09837de..00000000 --- a/app/controllers/openid/DiscoveryController.php +++ /dev/null @@ -1,54 +0,0 @@ -openid_protocol = $openid_protocol; - $this->auth_service = $auth_service; - $this->server_config_service = $server_config_service; - } - - /** - * XRDS discovery(eXtensible Resource Descriptor Sequence) - * @return xrds document on response - */ - public function idp() - { - $response = Response::make($this->openid_protocol->getXRDSDiscovery(IOpenIdProtocol::OpenIdXRDSModeIdp), 200); - $this->setDiscoveryResponseType($response); - return $response; - } - - /** - * If the Claimed Identifier was not previously discovered by the Relying Party - * (the "openid.identity" in the request was "http://specs.openid.net/auth/2.0/identifier_select" - * or a different Identifier, or if the OP is sending an unsolicited positive assertion), - * the Relying Party MUST perform discovery on the Claimed Identifier in - * the response to make sure that the OP is authorized to make assertions about the Claimed Identifier. - * @param $identifier - * @return mixed - */ - public function user($identifier) - { - $user = $this->auth_service->getUserByOpenId($identifier); - if (is_null($user)) - return View::make("404"); - - $local_identifier = $this->server_config_service->getUserIdentityEndpointURL($identifier); - $response = Response::make($this->openid_protocol->getXRDSDiscovery(IOpenIdProtocol::OpenIdXRDSModeUser, $local_identifier), 200); - $this->setDiscoveryResponseType($response); - return $response; - } - -} \ No newline at end of file diff --git a/app/controllers/openid/OpenIdProviderController.php b/app/controllers/openid/OpenIdProviderController.php deleted file mode 100644 index 121fe757..00000000 --- a/app/controllers/openid/OpenIdProviderController.php +++ /dev/null @@ -1,60 +0,0 @@ -openid_protocol = $openid_protocol; - $this->memento_service = $memento_service; - } - - /** - * @return OpenIdResponse - * @throws Exception - * @throws InvalidOpenIdMessageException - */ - public function endpoint() - { - $msg = new OpenIdMessage( Input::all() ); - - if($this->memento_service->exists()){ - $msg = OpenIdMessage::buildFromMemento( $this->memento_service->load()); - } - - if (!$msg->isValid()) - throw new InvalidOpenIdMessageException(OpenIdErrorMessages::InvalidOpenIdMessage); - - //get response and manage it taking in consideration its type (direct or indirect) - $response = $this->openid_protocol->handleOpenIdMessage($msg); - - if ($response instanceof OpenIdResponse) { - $strategy = OpenIdResponseStrategyFactoryMethod::buildStrategy($response); - return $strategy->handle($response); - } - return $response; - } -} \ No newline at end of file diff --git a/app/database/migrations/.gitkeep b/app/database/migrations/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/database/migrations/2015_03_19_190534_insert_marketplace_api_endpoints_scopes.php b/app/database/migrations/2015_03_19_190534_insert_marketplace_api_endpoints_scopes.php deleted file mode 100644 index 0318d9a4..00000000 --- a/app/database/migrations/2015_03_19_190534_insert_marketplace_api_endpoints_scopes.php +++ /dev/null @@ -1,263 +0,0 @@ - 'public-clouds', - 'logo' => null, - 'active' => true, - 'Description' => 'Marketplace Public Clouds', - 'resource_server_id' => $resource_server->id, - 'logo' => asset('/assets/img/apis/server.png') - ) - ); - // private clouds - Api::create( - array( - 'name' => 'private-clouds', - 'logo' => null, - 'active' => true, - 'Description' => 'Marketplace Private Clouds', - 'resource_server_id' => $resource_server->id, - 'logo' => asset('/assets/img/apis/server.png') - ) - ); - // consultants - Api::create( - array( - 'name' => 'consultants', - 'logo' => null, - 'active' => true, - 'Description' => 'Marketplace Consultants', - 'resource_server_id' => $resource_server->id, - 'logo' => asset('/assets/img/apis/server.png') - ) - ); - - $this->seedPublicCloudScopes(); - $this->seedPrivateCloudScopes(); - $this->seedConsultantScopes(); - $this->seedPublicCloudsEndpoints(); - $this->seedPrivateCloudsEndpoints(); - $this->seedConsultantsEndpoints(); - } - - - private function seedPublicCloudScopes(){ - - $current_realm = Config::get('app.url'); - $public_clouds = Api::where('name','=','public-clouds')->first(); - - ApiScope::create( - array( - 'name' => sprintf('%s/public-clouds/read',$current_realm), - 'short_description' => 'Get Public Clouds', - 'description' => 'Grants read only access for Public Clouds', - 'api_id' => $public_clouds->id, - 'system' => false, - ) - ); - } - - private function seedPrivateCloudScopes(){ - - $current_realm = Config::get('app.url'); - $private_clouds = Api::where('name','=','private-clouds')->first(); - - ApiScope::create( - array( - 'name' => sprintf('%s/private-clouds/read',$current_realm), - 'short_description' => 'Get Private Clouds', - 'description' => 'Grants read only access for Private Clouds', - 'api_id' => $private_clouds->id, - 'system' => false, - ) - ); - } - - private function seedConsultantScopes(){ - - $current_realm = Config::get('app.url'); - $consultants = Api::where('name','=','consultants')->first(); - - ApiScope::create( - array( - 'name' => sprintf('%s/consultants/read',$current_realm), - 'short_description' => 'Get Consultants', - 'description' => 'Grants read only access for Consultants', - 'api_id' => $consultants->id, - 'system' => false, - ) - ); - } - - private function seedPublicCloudsEndpoints(){ - $public_clouds = Api::where('name','=','public-clouds')->first(); - $current_realm = Config::get('app.url'); - // endpoints scopes - - ApiEndpoint::create( - array( - 'name' => 'get-public-clouds', - 'active' => true, - 'api_id' => $public_clouds->id, - 'route' => '/api/v1/marketplace/public-clouds', - 'http_method' => 'GET' - ) - ); - - ApiEndpoint::create( - array( - 'name' => 'get-public-cloud', - 'active' => true, - 'api_id' => $public_clouds->id, - 'route' => '/api/v1/marketplace/public-clouds/{id}', - 'http_method' => 'GET' - ) - ); - - ApiEndpoint::create( - array( - 'name' => 'get-public-cloud-datacenters', - 'active' => true, - 'api_id' => $public_clouds->id, - 'route' => '/api/v1/marketplace/public-clouds/{id}/data-centers', - 'http_method' => 'GET' - ) - ); - - $public_cloud_read_scope = ApiScope::where('name','=',sprintf('%s/public-clouds/read',$current_realm))->first(); - - $endpoint_get_public_clouds = ApiEndpoint::where('name','=','get-public-clouds')->first(); - $endpoint_get_public_clouds->scopes()->attach($public_cloud_read_scope->id); - - $endpoint_get_public_cloud = ApiEndpoint::where('name','=','get-public-cloud')->first(); - $endpoint_get_public_cloud->scopes()->attach($public_cloud_read_scope->id); - - $endpoint_get_public_cloud_datacenters = ApiEndpoint::where('name','=','get-public-cloud-datacenters')->first(); - $endpoint_get_public_cloud_datacenters->scopes()->attach($public_cloud_read_scope->id); - } - - private function seedPrivateCloudsEndpoints(){ - $private_clouds = Api::where('name','=','private-clouds')->first(); - $current_realm = Config::get('app.url'); - // endpoints scopes - - ApiEndpoint::create( - array( - 'name' => 'get-private-clouds', - 'active' => true, - 'api_id' => $private_clouds->id, - 'route' => '/api/v1/marketplace/private-clouds', - 'http_method' => 'GET' - ) - ); - - ApiEndpoint::create( - array( - 'name' => 'get-private-cloud', - 'active' => true, - 'api_id' => $private_clouds->id, - 'route' => '/api/v1/marketplace/private-clouds/{id}', - 'http_method' => 'GET' - ) - ); - - ApiEndpoint::create( - array( - 'name' => 'get-private-cloud-datacenters', - 'active' => true, - 'api_id' => $private_clouds->id, - 'route' => '/api/v1/marketplace/private-clouds/{id}/data-centers', - 'http_method' => 'GET' - ) - ); - - $private_cloud_read_scope = ApiScope::where('name','=',sprintf('%s/private-clouds/read',$current_realm))->first(); - - $endpoint_get_private_clouds = ApiEndpoint::where('name','=','get-private-clouds')->first(); - $endpoint_get_private_clouds->scopes()->attach($private_cloud_read_scope->id); - - $endpoint_get_private_cloud = ApiEndpoint::where('name','=','get-private-cloud')->first(); - $endpoint_get_private_cloud->scopes()->attach($private_cloud_read_scope->id); - - $endpoint_get_private_cloud_datacenters = ApiEndpoint::where('name','=','get-private-cloud-datacenters')->first(); - $endpoint_get_private_cloud_datacenters->scopes()->attach($private_cloud_read_scope->id); - - } - - private function seedConsultantsEndpoints(){ - - $consultants = Api::where('name','=','consultants')->first(); - $current_realm = Config::get('app.url'); - // endpoints scopes - - ApiEndpoint::create( - array( - 'name' => 'get-consultants', - 'active' => true, - 'api_id' => $consultants->id, - 'route' => '/api/v1/marketplace/consultants', - 'http_method' => 'GET' - ) - ); - - ApiEndpoint::create( - array( - 'name' => 'get-consultant', - 'active' => true, - 'api_id' => $consultants->id, - 'route' => '/api/v1/marketplace/consultants/{id}', - 'http_method' => 'GET' - ) - ); - - ApiEndpoint::create( - array( - 'name' => 'get-consultant-offices', - 'active' => true, - 'api_id' => $consultants->id, - 'route' => '/api/v1/marketplace/consultants/{id}/offices', - 'http_method' => 'GET' - ) - ); - - $consultant_read_scope = ApiScope::where('name','=',sprintf('%s/consultants/read',$current_realm))->first(); - - $endpoint = ApiEndpoint::where('name','=','get-consultants')->first(); - $endpoint->scopes()->attach($consultant_read_scope->id); - - $endpoint = ApiEndpoint::where('name','=','get-consultant')->first(); - $endpoint->scopes()->attach($consultant_read_scope->id); - - $endpoint = ApiEndpoint::where('name','=','get-consultant-offices')->first(); - $endpoint->scopes()->attach($consultant_read_scope->id); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - // - } - -} diff --git a/app/database/migrations/2015_05_06_142958_delete_marketplace_api_endpoints_scopes.php b/app/database/migrations/2015_05_06_142958_delete_marketplace_api_endpoints_scopes.php deleted file mode 100644 index 871e827c..00000000 --- a/app/database/migrations/2015_05_06_142958_delete_marketplace_api_endpoints_scopes.php +++ /dev/null @@ -1,33 +0,0 @@ -first(); - if($public_clouds) $public_clouds->delete(); - $private_clouds = Api::where('name','=','private-clouds')->first(); - if($private_clouds) $private_clouds->delete(); - $consultants = Api::where('name','=','consultants')->first(); - if($consultants) $consultants->delete(); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - // - } - -} diff --git a/app/database/production.sqlite b/app/database/production.sqlite deleted file mode 100644 index e69de29b..00000000 diff --git a/app/database/seeds/.gitkeep b/app/database/seeds/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/filters.php b/app/filters.php deleted file mode 100644 index 6cfa7e01..00000000 --- a/app/filters.php +++ /dev/null @@ -1,270 +0,0 @@ -getService(UtilsServiceCatalog::CheckPointService); - if (!$checkpoint_service->check()) { - return Response::view('404', array(), 404); - } - } catch (Exception $ex) { - Log::error($ex); - - return Response::view('404', array(), 404); - } - } - - $cors = ServiceLocator::getInstance()->getService('CORSMiddleware'); - if($response = $cors->verifyRequest($request)) - return $response; -}); - -App::after(function($request, $response){ - // https://www.owasp.org/index.php/List_of_useful_HTTP_headers - $response->headers->set('X-content-type-options','nosniff'); - $response->headers->set('X-xss-protection','1; mode=block'); - //cache - $response->headers->set('pragma','no-cache'); - $response->headers->set('Expires','-1'); - $response->headers->set('cache-control','no-store, must-revalidate, no-cache'); - $cors = ServiceLocator::getInstance()->getService('CORSMiddleware'); - $cors->modifyResponse($request, $response); -}); - -/* -|-------------------------------------------------------------------------- -| Authentication Filters -|-------------------------------------------------------------------------- -| -| The following filters are used to verify that the user of the current -| session is logged into this application. The "basic" filter easily -| integrates HTTP Basic authentication for quick, simple checking. -| -*/ - -Route::filter('auth', function () { - if (Auth::guest()) { - Session::put('url.intended', URL::full()); - Session::save(); - return Redirect::action('HomeController@index'); - } - $redirect = Session::get('url.intended'); - if (!empty($redirect)) { - Session::forget('url.intended'); - Session::save(); - return Redirect::to($redirect); - } -}); - -Route::filter('auth.basic', function () { - return Auth::basic(); -}); - -/* -|-------------------------------------------------------------------------- -| Guest Filter -|-------------------------------------------------------------------------- -| -| The "guest" filter is the counterpart of the authentication filters as -| it simply checks that the current user is not logged in. A redirect -| response will be issued if they are, which you may freely change. -| -*/ - -Route::filter('guest', function () { - if (Auth::check()) return Redirect::to('/'); -}); - -Route::filter('user.logged', function () { - if (!Auth::check()) - { - return Response::json(array('error' => 'operation not allowed.'), 400); - } -}); - -/* -|-------------------------------------------------------------------------- -| CSRF Protection Filter -|-------------------------------------------------------------------------- -| -| The CSRF filter is responsible for protecting your application against -| cross-site request forgery attacks. If this special token in a user -| session does not match the one given in this request, we'll bail. -| -*/ - -Route::filter('csrf', function () { - if (Session::token() != Input::get('_token')) { - throw new Illuminate\Session\TokenMismatchException; - } -}); - -Route::filter('ajax', function() -{ - if (!Request::ajax()) App::abort(404); -}); - -Route::filter("ssl", function () { - if ((!Request::secure()) && (ServerConfigurationService::getConfigValue("SSL.Enable"))) { - return Redirect::secure(Request::getRequestUri()); - } -}); - -Route::filter("oauth2.enabled",function(){ - if(!ServerConfigurationService::getConfigValue("OAuth2.Enable")){ - return Response::view('404', array(), 404); - } -}); - -Route::filter('user.owns.client.policy',function($route, $request){ - try{ - $authentication_service = ServiceLocator::getInstance()->getService(UtilsServiceCatalog::AuthenticationService); - $client_service = ServiceLocator::getInstance()->getService(OAuth2ServiceCatalog::ClientService); - $client_id = $route->getParameter('id'); - - if(is_null($client_id)) - $client_id = $route->getParameter('client_id'); - - if(is_null($client_id)) - $client_id =Input::get('client_id',null);; - - $client = $client_service->getClientByIdentifier($client_id); - $user = $authentication_service->getCurrentUser(); - if (is_null($client) || !$client->isOwner($user)) - throw new Exception('invalid client id for current user'); - - } catch (Exception $ex) { - Log::error($ex); - return Response::json(array('error' => 'operation not allowed.'), 400); - } -}); - -Route::filter('user.can.edit.client.policy',function($route, $request){ - try{ - $authentication_service = ServiceLocator::getInstance()->getService(UtilsServiceCatalog::AuthenticationService); - $client_service = ServiceLocator::getInstance()->getService(OAuth2ServiceCatalog::ClientService); - $client_id = $route->getParameter('id'); - - if(is_null($client_id)) - $client_id = $route->getParameter('client_id'); - - if(is_null($client_id)) - $client_id = Input::get('client_id',null);; - - $client = $client_service->getClientByIdentifier($client_id); - $user = $authentication_service->getCurrentUser(); - if (is_null($client) || !$client->candEdit($user)) - throw new Exception('invalid client id for current user'); - - } catch (Exception $ex) { - Log::error($ex); - return Response::json(array('error' => 'operation not allowed.'), 400); - } -}); - -Route::filter('is.current.user',function($route, $request){ - try{ - $authentication_service = ServiceLocator::getInstance()->getService(UtilsServiceCatalog::AuthenticationService); - $used_id = Input::get('user_id',null); - - if(is_null($used_id)) - $used_id = Input::get('id',null); - - if(is_null($used_id)) - $used_id = $route->getParameter('user_id'); - - if(is_null($used_id)) - $used_id = $route->getParameter('id'); - - $user = $authentication_service->getCurrentUser(); - if (is_null($used_id) || intval($used_id) !== intval($user->getId())) - throw new Exception(sprintf('user id %s does not match with current user id %s',$used_id,$user->getId())); - - } catch (Exception $ex) { - Log::error($ex); - return Response::json(array('error' => 'operation not allowed.'), 400); - } -}); - - -// filter to protect an api endpoint with oauth2 - -Route::filter('oauth2.protected.endpoint','OAuth2BearerAccessTokenRequestValidator'); - -//oauth2 server admin filter - -Route::filter('oauth2.server.admin.json',function(){ - if (Auth::guest()) { - return Response::json(array('error' => 'you are not allowed to perform this operation')); - } - if(!Auth::user()->isOAuth2ServerAdmin()){ - return Response::json(array('error' => 'you are not allowed to perform this operation')); - } -}); - - -Route::filter('oauth2.server.admin',function(){ - if (Auth::guest()) { - return Response::view('404', array(), 404); - } - if(!Auth::user()->isOAuth2ServerAdmin()){ - return Response::view('404', array(), 404); - } -}); - - -//openstackid server admin - -Route::filter('openstackid.server.admin.json',function(){ - if (Auth::guest()) { - return Response::json(array('error' => 'you are not allowed to perform this operation')); - } - if(!Auth::user()->isOpenstackIdAdmin()){ - return Response::json(array('error' => 'you are not allowed to perform this operation')); - } -}); - - -Route::filter('openstackid.server.admin',function(){ - if (Auth::guest()) { - return Response::view('404', array(), 404); - } - if(!Auth::user()->isOpenstackIdAdmin()){ - return Response::view('404', array(), 404); - } -}); \ No newline at end of file diff --git a/app/filters/.gitkeep b/app/filters/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/lang/en/pagination.php b/app/lang/en/pagination.php deleted file mode 100644 index eb9be3ba..00000000 --- a/app/lang/en/pagination.php +++ /dev/null @@ -1,20 +0,0 @@ - '« Previous', - - 'next' => 'Next »', - -); \ No newline at end of file diff --git a/app/lang/en/validation.php b/app/lang/en/validation.php deleted file mode 100644 index bc024339..00000000 --- a/app/lang/en/validation.php +++ /dev/null @@ -1,114 +0,0 @@ - "The :attribute must be accepted.", - "active_url" => "The :attribute is not a valid URL.", - "after" => "The :attribute must be a date after :date.", - "alpha" => "The :attribute may only contain letters.", - "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", - "alpha_num" => "The :attribute may only contain letters and numbers.", - "array" => "The :attribute must be an array.", - "before" => "The :attribute must be a date before :date.", - "between" => array( - "numeric" => "The :attribute must be between :min - :max.", - "file" => "The :attribute must be between :min - :max kilobytes.", - "string" => "The :attribute must be between :min - :max characters.", - "array" => "The :attribute must have between :min - :max items.", - ), - "confirmed" => "The :attribute confirmation does not match.", - "date" => "The :attribute is not a valid date.", - "date_format" => "The :attribute does not match the format :format.", - "different" => "The :attribute and :other must be different.", - "digits" => "The :attribute must be :digits digits.", - "digits_between" => "The :attribute must be between :min and :max digits.", - "email" => "The :attribute format is invalid.", - "exists" => "The selected :attribute is invalid.", - "image" => "The :attribute must be an image.", - "in" => "The selected :attribute is invalid.", - "integer" => "The :attribute must be an integer.", - "ip" => "The :attribute must be a valid IP address.", - "max" => array( - "numeric" => "The :attribute may not be greater than :max.", - "file" => "The :attribute may not be greater than :max kilobytes.", - "string" => "The :attribute may not be greater than :max characters.", - "array" => "The :attribute may not have more than :max items.", - ), - "mimes" => "The :attribute must be a file of type: :values.", - "min" => array( - "numeric" => "The :attribute must be at least :min.", - "file" => "The :attribute must be at least :min kilobytes.", - "string" => "The :attribute must be at least :min characters.", - "array" => "The :attribute must have at least :min items.", - ), - "not_in" => "The selected :attribute is invalid.", - "numeric" => "The :attribute must be a number.", - "regex" => "The :attribute format is invalid.", - "required" => "The :attribute field is required.", - "required_if" => "The :attribute field is required when :other is :value.", - "required_with" => "The :attribute field is required when :values is present.", - "required_without" => "The :attribute field is required when :values is not present.", - "same" => "The :attribute and :other must match.", - "size" => array( - "numeric" => "The :attribute must be :size.", - "file" => "The :attribute must be :size kilobytes.", - "string" => "The :attribute must be :size characters.", - "array" => "The :attribute must contain :size items.", - ), - "unique" => "The :attribute has already been taken.", - "url" => "The :attribute format is invalid.", - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - - 'custom' => array(), - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - - 'attributes' => array(), - //custom messages - 'boolean' => "The :attribute must be a boolean.", - 'text' => "The :attribute may only contain text.", - 'httpmethod' => "The :attribute must be one of the following values 'GET', 'HEAD','POST','PUT','DELETE','TRACE','CONNECT' OR 'OPTIONS'.", - 'route' => "The :attribute may be a valid http route.", - 'host' => "The :attribute may be a valid host name.", - 'scopename' => "The :attribute may be a valid scope name.", - 'applicationtype' => "The :attribute may be a valid application type.", - 'sslurl' => "The :attribute may be a valid URL under ssl schema.", - 'sslorigin' => "The :attribute may be a valid HTTP origin under ssl schema.", - 'freetext' => "The :attribute may only contain text.", - 'public_key_pem' => "The :attribute has not a valid PCK#1/PCK#8 public key format.", - 'private_key_pem' => "The :attribute has not a valid PCK#1/PCK#8 private key format.", - 'public_key_usage' => "The :attribute has not a valid key usage (enc, sig).", - 'public_key_type'=> "The :attribute has not a valid key type (RSA).", - 'private_key_password' => "The :attribute is not the right password of the PEM private key.", - 'private_key_pem_length'=> "The :attribute has not a valid private key length ( at least 2048 bits ).", - 'public_key_pem_length'=> "The :attribute has not a valid public key length ( at least 2048 bits ).", - 'key_alg' => "The :attribute has not a valid alg parameter for the key usage.", -); diff --git a/app/libs/auth/AuthHelper.php b/app/libs/Auth/AuthHelper.php similarity index 87% rename from app/libs/auth/AuthHelper.php rename to app/libs/Auth/AuthHelper.php index 632269c8..28f3a77d 100644 --- a/app/libs/auth/AuthHelper.php +++ b/app/libs/Auth/AuthHelper.php @@ -1,9 +1,23 @@ -randomToken('sha1'), 0, 22); + $generator = Hash::compute('sha1',Rand::getString(128, null, true)); + return sprintf('%02d', self::$cost) . '$' . substr($generator, 0, 22); } public function check($hash, $password, $salt = null) { @@ -229,6 +244,10 @@ final class PasswordEncryptor_Blowfish extends PasswordEncryptorStrategy { } } +/** + * Class AuthHelper + * @package Auth + */ class AuthHelper { @@ -246,12 +265,12 @@ class AuthHelper * @param $salt * @param string $algorithm * @return string - * @throws \Exception + * @throws Exception */ public static function encrypt_password($password, $salt, $algorithm = "sha1") { if (!isset(self::$algorithms[$algorithm])) - throw new \Exception(sprintf("non supported algorithm %s", $algorithm)); + throw new Exception(sprintf("non supported algorithm %s", $algorithm)); $class = self::$algorithms[$algorithm]; @@ -265,12 +284,12 @@ class AuthHelper * @param string $hash2 * @param string $algorithm * @return bool - * @throws \Exception + * @throws Exception */ public static function compare($hash1, $hash2, $algorithm = "sha1") { if (!isset(self::$algorithms[$algorithm])) - throw new \Exception(sprintf("non supported algorithm %s", $algorithm)); + throw new Exception(sprintf("non supported algorithm %s", $algorithm)); $class = self::$algorithms[$algorithm]; $strategy = new $class($algorithm); diff --git a/app/libs/auth/AuthService.php b/app/libs/Auth/AuthService.php similarity index 73% rename from app/libs/auth/AuthService.php rename to app/libs/Auth/AuthService.php index 813dbea2..f8278068 100644 --- a/app/libs/auth/AuthService.php +++ b/app/libs/Auth/AuthService.php @@ -1,26 +1,34 @@ -member_repository = $member_repository; + $this->user_repository = $user_repository; $this->principal_service = $principal_service; $this->user_service = $user_service; $this->cache_service = $cache_service; } /** - * @return mixed + * @return bool */ public function isUserLogged() { @@ -67,9 +96,9 @@ final class AuthService implements IAuthService } /** - * @param $username - * @param $password - * @param $remember_me + * @param string $username + * @param string $password + * @param bool $remember_me * @return mixed */ public function login($username, $password, $remember_me) @@ -133,9 +162,7 @@ final class AuthService implements IAuthService */ public function getUserByOpenId($openid) { - $user = User::where('identifier', '=', $openid)->first(); - - return $user; + return $this->user_repository->getByIdentifier($openid); } /** @@ -144,10 +171,11 @@ final class AuthService implements IAuthService */ public function getUserByUsername($username) { - $member = Member::where('Email', '=', $username)->first(); + $member = $this->member_repository->getByEmail($username); + if (!is_null($member)) { - $user = User::where('external_identifier', '=', $member->ID)->first(); + $user = $this->user_repository->getByExternalId($member->ID); if(!$user) { @@ -166,7 +194,7 @@ final class AuthService implements IAuthService */ public function getUserById($id) { - return User::find($id); + return $this->user_repository->get($id); } // Authentication @@ -202,6 +230,7 @@ final class AuthService implements IAuthService public function unwrapUserId($user_id) { $user = $this->getUserByExternalId($user_id); + if(!is_null($user)) return $user_id; @@ -219,11 +248,9 @@ final class AuthService implements IAuthService { if($client->getSubjectType() === IClient::SubjectType_Public) return $user_id; - else - { - $wrapped_name = sprintf('%s:%s', $client->getClientId(), $user_id); - return $this->encrypt($wrapped_name); - } + + $wrapped_name = sprintf('%s:%s', $client->getClientId(), $user_id); + return $this->encrypt($wrapped_name); } /** @@ -251,10 +278,11 @@ final class AuthService implements IAuthService */ public function getUserByExternalId($external_id) { - $member = Member::where('ID', '=', $external_id)->first(); + $member = $this->member_repository->get($external_id); + if (!is_null($member)) { - $user = User::where('external_identifier', '=', $member->ID)->first(); + $user = $this->user_repository->getByExternalId($member->ID); if(!$user) { @@ -319,19 +347,19 @@ final class AuthService implements IAuthService /** * @param string $jti - * @throws \Exception + * @throws Exception */ public function reloadSession($jti) { $session_id = $this->cache_service->getSingleValue($jti); - if(empty($session_id)) throw new \Exception('session not found!'); + if(empty($session_id)) throw new Exception('session not found!'); Session::setId(Crypt::decrypt($session_id)); Session::start(); if(!Auth::check()) { $user_id = $this->principal_service->get()->getUserId(); $user = $this->getUserById($user_id); - if(is_null($user)) throw new \Exception('user not found!'); + if(is_null($user)) throw new Exception('user not found!'); Auth::login($user); } } diff --git a/app/libs/Auth/AuthenticationExtensionService.php b/app/libs/Auth/AuthenticationExtensionService.php new file mode 100644 index 00000000..98976bc6 --- /dev/null +++ b/app/libs/Auth/AuthenticationExtensionService.php @@ -0,0 +1,45 @@ +extensions = array(); + } + /** + * @return array + */ + public function getExtensions() + { + return $this->extensions; + } + + /** + * @param IAuthenticationExtension $extension + * @return $this + */ + public function addExtension(IAuthenticationExtension $extension) + { + array_push($this->extensions, $extension); + return $this; + } +} \ No newline at end of file diff --git a/app/libs/Auth/AuthenticationServiceProvider.php b/app/libs/Auth/AuthenticationServiceProvider.php new file mode 100644 index 00000000..c505155e --- /dev/null +++ b/app/libs/Auth/AuthenticationServiceProvider.php @@ -0,0 +1,45 @@ +last_login_date = gmdate("Y-m-d H:i:s", time()); + $user->last_login_date = gmdate("Y-m-d H:i:s", time()); $user->login_failed_attempt = 0; - $user->active = true; - $user->lock = false; + $user->active = true; + $user->lock = false; + $user_repository->update($user); $user->setMember($member); @@ -190,8 +204,6 @@ class CustomAuthProvider implements UserProviderInterface { $auth_extension->process($user); } - - } catch(UnverifiedEmailMemberException $ex1){ $checkpoint_service->trackException($ex1); @@ -212,13 +224,12 @@ class CustomAuthProvider implements UserProviderInterface /** - * Validate a user against the given credentials. - * @param UserInterface $user + * @param Authenticatable $user * @param array $credentials * @return bool - * @throws exceptions\AuthenticationException + * @throws AuthenticationException */ - public function validateCredentials(UserInterface $user, array $credentials) + public function validateCredentials(Authenticatable $user, array $credentials) { if (!isset($credentials['username']) || !isset($credentials['password'])) { throw new AuthenticationException("invalid crendentials"); @@ -249,7 +260,7 @@ class CustomAuthProvider implements UserProviderInterface * Retrieve a user by by their unique identifier and "remember me" token. * @param mixed $identifier * @param string $token - * @return \Illuminate\Auth\UserInterface|null + * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function retrieveByToken($identifier, $token) { @@ -258,11 +269,11 @@ class CustomAuthProvider implements UserProviderInterface /** * Update the "remember me" token for the given user in storage. - * @param \Illuminate\Auth\UserInterface $user + * @param Authenticatable $user * @param string $token * @return void */ - public function updateRememberToken(UserInterface $user, $token) + public function updateRememberToken(Authenticatable $user, $token) { $user->setAttribute($user->getRememberTokenName(), $token); diff --git a/app/libs/Auth/Exceptions/AuthenticationException.php b/app/libs/Auth/Exceptions/AuthenticationException.php new file mode 100644 index 00000000..163b9fa2 --- /dev/null +++ b/app/libs/Auth/Exceptions/AuthenticationException.php @@ -0,0 +1,27 @@ +identifier = $identifier; + parent::__construct($message, 0, null); + } + + public function getIdentifier(){ + return $this->identifier; + } +} \ No newline at end of file diff --git a/app/libs/Auth/Exceptions/AuthenticationLockedUserLoginAttempt.php b/app/libs/Auth/Exceptions/AuthenticationLockedUserLoginAttempt.php new file mode 100644 index 00000000..68dc6296 --- /dev/null +++ b/app/libs/Auth/Exceptions/AuthenticationLockedUserLoginAttempt.php @@ -0,0 +1,35 @@ +identifier = $identifier; + parent::__construct($message, 0, null); + } + + public function getIdentifier(){ + return $this->identifier; + } + +} \ No newline at end of file diff --git a/app/libs/auth/exceptions/UnverifiedEmailMemberException.php b/app/libs/Auth/Exceptions/UnverifiedEmailMemberException.php similarity index 85% rename from app/libs/auth/exceptions/UnverifiedEmailMemberException.php rename to app/libs/Auth/Exceptions/UnverifiedEmailMemberException.php index a26dc90a..f14e315e 100644 --- a/app/libs/auth/exceptions/UnverifiedEmailMemberException.php +++ b/app/libs/Auth/Exceptions/UnverifiedEmailMemberException.php @@ -1,4 +1,4 @@ -hasMany("OpenIdTrustedSite", 'user_id'); + return $this->hasMany("Models\OpenId\OpenIdTrustedSite", 'user_id'); } public function access_tokens() { - return $this->hasMany('AccessToken', 'user_id'); + return $this->hasMany('Models\OAuth2\AccessToken', 'user_id'); } public function refresh_tokens() { - return $this->hasMany('RefreshToken', 'user_id'); + return $this->hasMany('Models\OAuth2\RefreshToken', 'user_id'); } public function consents() { - return $this->hasMany('UserConsent', 'user_id'); + return $this->hasMany('Models\OAuth2\UserConsent', 'user_id'); } public function clients() { - return $this->hasMany("Client", 'user_id'); + return $this->hasMany("Models\OAuth2\Client", 'user_id'); } public function getActions() @@ -58,7 +68,7 @@ class User extends BaseModelEloquent implements UserInterface, IOpenIdUser, IOAu public function actions() { - return $this->hasMany("UserAction", 'user_id'); + return $this->hasMany("Models\UserAction", 'user_id'); } public function setMember($member) @@ -224,7 +234,7 @@ class User extends BaseModelEloquent implements UserInterface, IOpenIdUser, IOAu public function managed_clients() { - return $this->belongsToMany('Client', 'oauth2_client_admin_users', 'user_id', 'oauth2_client_id'); + return $this->belongsToMany('Models\OAuth2\Client', 'oauth2_client_admin_users', 'user_id', 'oauth2_client_id'); } /** @@ -257,7 +267,7 @@ class User extends BaseModelEloquent implements UserInterface, IOpenIdUser, IOAu public function isOpenstackIdAdmin() { $this->getAssociatedMember(); - $group = $this->member->groups()->where('code', '=', IOpenIdUser::OpenstackIdServerAdminGroup)->first(); + $group = $this->member->groups()->where('code', '=', IOpenIdUser::OpenStackIdServerAdminGroup)->first(); return !is_null($group); } @@ -363,7 +373,7 @@ class User extends BaseModelEloquent implements UserInterface, IOpenIdUser, IOAu */ public function groups() { - return $this->belongsToMany('ApiScopeGroup','oauth2_api_scope_group_users','user_id', 'group_id'); + return $this->belongsToMany('Models\OAuth2\ApiScopeGroup','oauth2_api_scope_group_users','user_id', 'group_id'); } /** diff --git a/app/libs/auth/UserNameGeneratorService.php b/app/libs/Auth/UserNameGeneratorService.php similarity index 96% rename from app/libs/auth/UserNameGeneratorService.php rename to app/libs/Auth/UserNameGeneratorService.php index bf71cdae..cdc9e0b0 100644 --- a/app/libs/auth/UserNameGeneratorService.php +++ b/app/libs/Auth/UserNameGeneratorService.php @@ -1,4 +1,4 @@ -FirstName); $lname = self::normalizeChars($member->Surname); @@ -99,7 +97,7 @@ final class UserNameGeneratorService implements IUserNameGeneratorService preg_replace('/[^\d\w_-]+/i', IUserNameGeneratorService::USER_NAME_INVALID_CHAR_REPLACEMENT, $lname) ); //if all characters were replaced by a connector, then is not a latin character based user name - if(strlen($user_name) === substr_count($user_name,IUserNameGeneratorService::USER_NAME_CHAR_CONNECTOR)) + if(strlen($user_name) === substr_count($user_name, IUserNameGeneratorService::USER_NAME_CHAR_CONNECTOR)) { $email = $member->Email; $email = explode('@', $email); diff --git a/app/commands/.gitkeep b/app/libs/OAuth2/.gitkeep similarity index 100% rename from app/commands/.gitkeep rename to app/libs/OAuth2/.gitkeep diff --git a/app/libs/oauth2/AddressClaim.php b/app/libs/OAuth2/AddressClaim.php similarity index 95% rename from app/libs/oauth2/AddressClaim.php rename to app/libs/OAuth2/AddressClaim.php index 7ceb16d2..0dcafda2 100644 --- a/app/libs/oauth2/AddressClaim.php +++ b/app/libs/OAuth2/AddressClaim.php @@ -1,4 +1,4 @@ -protocol = $protocol; + } + + /** + * @param OAuth2Request $request + * @return mixed + * @throws InvalidOAuth2Request + * @throws InvalidClientException + * @throws UriNotAllowedException + * @throws ScopeNotAllowedException + * @throws UnsupportedResponseTypeException + * @throws UnAuthorizedClientException + * @throws AccessDeniedException + * @throws OAuth2GenericException + */ + public function handle(OAuth2Request $request) + { + foreach($this->protocol->getAvailableGrants() as $key => $grant){ + if($grant->canHandle($request)) + return $grant->handle($request); + } + throw new InvalidOAuth2Request; + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Endpoints/IOAuth2Endpoint.php b/app/libs/OAuth2/Endpoints/IOAuth2Endpoint.php new file mode 100644 index 00000000..e01d2b02 --- /dev/null +++ b/app/libs/OAuth2/Endpoints/IOAuth2Endpoint.php @@ -0,0 +1,30 @@ +protocol = $protocol; + $this->grant_type = new ValidateBearerTokenGrantType($client_service, $client_repository, $token_service, $auth_service, $log_service); + } + + + /** + * @param OAuth2Request $request + * @return OAuth2Response + * @throws InvalidOAuth2Request + * @throws BearerTokenDisclosureAttemptException + * @throws ExpiredAccessTokenException + * @throws InvalidApplicationType + * @throws InvalidOAuth2Request + * @throws LockedClientException + */ + public function handle(OAuth2Request $request) + { + if($this->grant_type->canHandle($request)) + { + return $this->grant_type->completeFlow($request); + } + throw new InvalidOAuth2Request; + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Endpoints/TokenRevocationEndpoint.php b/app/libs/OAuth2/Endpoints/TokenRevocationEndpoint.php new file mode 100644 index 00000000..aa4ef5fb --- /dev/null +++ b/app/libs/OAuth2/Endpoints/TokenRevocationEndpoint.php @@ -0,0 +1,84 @@ +protocol = $protocol; + $this->grant_type = new RevokeBearerTokenGrantType($client_service, $client_repository, $token_service, $log_service); + } + + /** + * @param OAuth2Request $request + * @return OAuth2Response + * @throws InvalidOAuth2Request + * @throws Exception + * @throws BearerTokenDisclosureAttemptException + * @throws ExpiredAccessTokenException + * @throws UnAuthorizedClientException + */ + public function handle(OAuth2Request $request) + { + if($this->grant_type->canHandle($request)) + { + return $this->grant_type->completeFlow($request); + } + throw new InvalidOAuth2Request; + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Exceptions/AbsentClientException.php b/app/libs/OAuth2/Exceptions/AbsentClientException.php new file mode 100644 index 00000000..e9f0988e --- /dev/null +++ b/app/libs/OAuth2/Exceptions/AbsentClientException.php @@ -0,0 +1,28 @@ +client_id = $client_id; + $message = "OAuth2 Client Base Exception : " . $message; + parent::__construct($message, 0, null); + } + + /** + * @return string + */ + public function getClientId(){ + return $this->client_id; + } + +} \ No newline at end of file diff --git a/app/libs/OAuth2/Exceptions/OAuth2GenericException.php b/app/libs/OAuth2/Exceptions/OAuth2GenericException.php new file mode 100644 index 00000000..915a2cf7 --- /dev/null +++ b/app/libs/OAuth2/Exceptions/OAuth2GenericException.php @@ -0,0 +1,28 @@ +http_code = $http_code; + $this->error = $error; + $this->error_description = $error_description; + $this->scope = $scope; + + $message = "Resource Server Exception : " . sprintf + ( + 'http code : %s - error : %s - error description: %s', + $http_code, + $error, + $error_description + ); + + parent::__construct($message, 0, null); + } + + /** + * @return int + */ + public function getError() + { + return $this->error; + } + + /** + * @return string + */ + public function getErrorDescription() + { + return $this->error_description; + } + + /** + * @return null|string + */ + public function getScope() + { + return $this->scope; + } + + /** + * @return string + */ + public function getHttpCode() + { + return $this->http_code; + } +} \ No newline at end of file diff --git a/app/libs/oauth2/exceptions/RecipientKeyNotFoundException.php b/app/libs/OAuth2/Exceptions/RecipientKeyNotFoundException.php similarity index 86% rename from app/libs/oauth2/exceptions/RecipientKeyNotFoundException.php rename to app/libs/OAuth2/Exceptions/RecipientKeyNotFoundException.php index c87fd2bd..f8654462 100644 --- a/app/libs/oauth2/exceptions/RecipientKeyNotFoundException.php +++ b/app/libs/OAuth2/Exceptions/RecipientKeyNotFoundException.php @@ -1,6 +1,6 @@ -token = $token; + parent::__construct($description); + } + /** + * @var string + */ + private $token; + + /** + * @return string + */ + public function getToken() + { + return $this->token; + } + /** + * @return string + */ + public function getError() + { + return OAuth2Protocol::OAuth2Protocol_Error_InvalidGrant; + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Exceptions/ReplayAttackRefreshTokenException.php b/app/libs/OAuth2/Exceptions/ReplayAttackRefreshTokenException.php new file mode 100644 index 00000000..bb29cec8 --- /dev/null +++ b/app/libs/OAuth2/Exceptions/ReplayAttackRefreshTokenException.php @@ -0,0 +1,29 @@ +getResponseType() + ); + + $is_hybrid_flow = OAuth2Protocol::responseTypeBelongsToFlow + ( + $response_type, + OAuth2Protocol::OAuth2Protocol_GrantType_Hybrid + ); + + if ($is_hybrid_flow) { + + if (in_array(OAuth2Protocol::OAuth2Protocol_ResponseType_Token, $response_type)) { + + $access_token = $token_service->createAccessToken($auth_code, $request->getRedirectUri()); + } + + // check if should emmit id token + + if (in_array(OAuth2Protocol::OAuth2Protocol_ResponseType_IdToken, $response_type)) { + + $id_token = $token_service->createIdToken + ( + $auth_code->getNonce(), + $auth_code->getClientId(), + $access_token + ); + } + + if (is_null($id_token) && is_null($access_token)) throw new InvalidOAuth2Request; + } + else + { + $access_token = $token_service->createAccessToken($auth_code, $request->getRedirectUri()); + + $id_token = $token_service->createIdToken + ( + $auth_code->getNonce(), + $auth_code->getClientId(), + $access_token + ); + } + + if (!is_null($access_token)) + $refresh_token = $access_token->getRefreshToken(); + + return new OAuth2IdTokenResponse + ( + is_null($access_token) ? null : $access_token->getValue(), + is_null($access_token) ? null : $access_token->getLifetime(), + is_null($id_token) ? null : $id_token->toCompactSerialization(), + is_null($refresh_token) ? null : $refresh_token->getValue() + ); + } + // normal oauth2.0 code flow + + $access_token = $token_service->createAccessToken($auth_code, $request->getRedirectUri()); + $refresh_token = $access_token->getRefreshToken(); + + return new OAuth2AccessTokenResponse + ( + $access_token->getValue(), + $access_token->getLifetime(), + is_null($refresh_token) ? null : $refresh_token->getValue() + ); + + } + + /** + * @param AuthorizationCode $auth_code + * @return bool + */ + static public function authCodeWasIssuedForOIDC(AuthorizationCode $auth_code) + { + return str_contains($auth_code->getScope(), OAuth2Protocol::OpenIdConnect_Scope); + } + +} \ No newline at end of file diff --git a/app/libs/oauth2/factories/OAuth2AuthorizationRequestFactory.php b/app/libs/OAuth2/Factories/OAuth2AuthorizationRequestFactory.php similarity index 77% rename from app/libs/oauth2/factories/OAuth2AuthorizationRequestFactory.php rename to app/libs/OAuth2/Factories/OAuth2AuthorizationRequestFactory.php index df79e509..37f55b6b 100644 --- a/app/libs/oauth2/factories/OAuth2AuthorizationRequestFactory.php +++ b/app/libs/OAuth2/Factories/OAuth2AuthorizationRequestFactory.php @@ -1,6 +1,6 @@ -client_service = $client_service; - $this->token_service = $token_service; - $this->log_service = $log_service; + $this->client_service = $client_service; + $this->client_repository = $client_repository; + $this->token_service = $token_service; + $this->log_service = $log_service; } /** * @param OAuth2Request $request - * @return mixed|void + * @return OAuth2Response * @throws MissingClientIdParam * @throws InvalidClientCredentials * @throws InvalidClientException @@ -76,9 +96,8 @@ abstract class AbstractGrantType implements IGrantType //get client credentials from request.. $this->client_auth_context = $this->client_service->getCurrentClientAuthInfo(); - //retrieve client from storage.. - $this->current_client = $this->client_service->getClientById($this->client_auth_context->getId()); + $this->current_client = $this->client_repository->getClientById($this->client_auth_context->getId()); if (is_null($this->current_client)) throw new InvalidClientException diff --git a/app/libs/oauth2/grant_types/AuthorizationCodeGrantType.php b/app/libs/OAuth2/GrantTypes/AuthorizationCodeGrantType.php similarity index 79% rename from app/libs/oauth2/grant_types/AuthorizationCodeGrantType.php rename to app/libs/OAuth2/GrantTypes/AuthorizationCodeGrantType.php index 1836276b..8234f4dc 100644 --- a/app/libs/oauth2/grant_types/AuthorizationCodeGrantType.php +++ b/app/libs/OAuth2/GrantTypes/AuthorizationCodeGrantType.php @@ -1,50 +1,52 @@ -auth_service->getCurrentUser(); - $client = $this->client_service->getClientById($request->getClientId()); // build current audience ... $audience = $this->scope_service->getStrAudienceByScopeNames diff --git a/app/libs/oauth2/grant_types/ClientCredentialsGrantType.php b/app/libs/OAuth2/GrantTypes/ClientCredentialsGrantType.php similarity index 64% rename from app/libs/oauth2/grant_types/ClientCredentialsGrantType.php rename to app/libs/OAuth2/GrantTypes/ClientCredentialsGrantType.php index 3b874f6f..266dc832 100644 --- a/app/libs/oauth2/grant_types/ClientCredentialsGrantType.php +++ b/app/libs/OAuth2/GrantTypes/ClientCredentialsGrantType.php @@ -1,21 +1,34 @@ -scope_service = $scope_service; } @@ -64,11 +80,10 @@ class ClientCredentialsGrantType extends AbstractGrantType return $request instanceof OAuth2TokenRequest && $request->isValid() && $request->getGrantType() == $this->getType(); } - /** * get grant type response type - * @return mixed|void - * @throws \oauth2\exceptions\InvalidOAuth2Request + * @return array + * @throws InvalidOAuth2Request */ public function getResponseType() { @@ -77,8 +92,8 @@ class ClientCredentialsGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return mixed|void - * @throws \oauth2\exceptions\InvalidOAuth2Request + * @return OAuth2Response + * @throws InvalidOAuth2Request */ public function handle(OAuth2Request $request) { @@ -87,11 +102,11 @@ class ClientCredentialsGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return mixed|OAuth2AccessTokenResponse|void - * @throws \oauth2\exceptions\ScopeNotAllowedException - * @throws \oauth2\exceptions\InvalidOAuth2Request - * @throws \oauth2\exceptions\InvalidApplicationType - * @throws \oauth2\exceptions\InvalidGrantTypeException + * @return OAuth2Response + * @throws ScopeNotAllowedException + * @throws InvalidOAuth2Request + * @throws InvalidApplicationType + * @throws InvalidGrantTypeException */ public function completeFlow(OAuth2Request $request) { @@ -157,7 +172,7 @@ class ClientCredentialsGrantType extends AbstractGrantType /** * get grant type - * @return mixed + * @return string */ public function getType() { diff --git a/app/libs/oauth2/grant_types/HybridGrantType.php b/app/libs/OAuth2/GrantTypes/HybridGrantType.php similarity index 83% rename from app/libs/oauth2/grant_types/HybridGrantType.php rename to app/libs/OAuth2/GrantTypes/HybridGrantType.php index 70ed0abc..c986c575 100644 --- a/app/libs/oauth2/grant_types/HybridGrantType.php +++ b/app/libs/OAuth2/GrantTypes/HybridGrantType.php @@ -1,4 +1,5 @@ -security_context_service = $security_context_service; $this->principal_service = $principal_service; @@ -148,6 +155,11 @@ abstract class InteractiveGrantType extends AbstractGrantType $this->jwk_set_reader_service = $jwk_set_reader_service; } + /** + * @param OAuth2Request $request + * @return OAuth2Response + * @throws Exception + */ public function handle(OAuth2Request $request) { try @@ -159,7 +171,7 @@ abstract class InteractiveGrantType extends AbstractGrantType } $client_id = $request->getClientId(); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); if (is_null($client)) { throw new InvalidClientException @@ -288,7 +300,7 @@ abstract class InteractiveGrantType extends AbstractGrantType $this->log_service->debug_msg(sprintf("Doing consent ... authorization_response %s should_prompt_consent %s",$authorization_response, $should_prompt_consent)); return $this->auth_strategy->doConsent($request); } - catch(\Exception $ex) + catch(Exception $ex) { $this->log_service->warning($ex); // clear save data ... @@ -354,10 +366,10 @@ abstract class InteractiveGrantType extends AbstractGrantType * @throws InteractionRequiredException * @throws InvalidClientException * @throws InvalidLoginHint - * @throws \jwk\exceptions\InvalidJWKAlgorithm - * @throws \oauth2\exceptions\InvalidClientType - * @throws \oauth2\exceptions\ServerKeyNotFoundException - * @throws \utils\exceptions\InvalidCompactSerializationException + * @throws InvalidJWKAlgorithm + * @throws InvalidClientType + * @throws ServerKeyNotFoundException + * @throws InvalidCompactSerializationException */ protected function processUserHint(OAuth2AuthenticationRequest $request) { @@ -383,7 +395,7 @@ abstract class InteractiveGrantType extends AbstractGrantType else if(!empty($token_hint)) { $client_id = $request->getClientId(); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); if (is_null($client)) { @@ -402,17 +414,6 @@ abstract class InteractiveGrantType extends AbstractGrantType if($jwt instanceof IJWE) { // decrypt using server key - - $recipient_key = RSAJWKFactory::build - ( - new RSAJWKPEMPrivateKeySpecification - ( - TestSeeder::$client_private_key_1, - RSAJWKPEMPrivateKeySpecification::WithoutPassword, - $jwt->getJOSEHeader()->getAlgorithm()->getString() - ) - ); - $heuristic = new ServerEncryptionKeyFinder($this->server_private_key_repository); $server_enc_private_key = $heuristic->find ( @@ -556,6 +557,7 @@ abstract class InteractiveGrantType extends AbstractGrantType * @param OAuth2AuthorizationRequest $request * @param IClient $client * @return bool + * @throws InteractionRequiredException */ protected function shouldForceReLogin(OAuth2AuthorizationRequest $request, IClient $client) { diff --git a/app/libs/oauth2/grant_types/RefreshBearerTokenGrantType.php b/app/libs/OAuth2/GrantTypes/RefreshBearerTokenGrantType.php similarity index 73% rename from app/libs/oauth2/grant_types/RefreshBearerTokenGrantType.php rename to app/libs/OAuth2/GrantTypes/RefreshBearerTokenGrantType.php index 8535b6ba..a688d39d 100644 --- a/app/libs/oauth2/grant_types/RefreshBearerTokenGrantType.php +++ b/app/libs/OAuth2/GrantTypes/RefreshBearerTokenGrantType.php @@ -1,43 +1,58 @@ -current_client->use_refresh_token) + if (!$this->current_client->useRefreshToken()) { throw new UseRefreshTokenException ( @@ -132,14 +147,14 @@ final class RefreshBearerTokenGrantType extends AbstractGrantType ); } - if ($refresh_token->getClientId() !== $this->current_client->client_id) + if ($refresh_token->getClientId() !== $this->current_client->getClientId()) { throw new InvalidGrantTypeException ( sprintf ( "refresh token %s does not belongs to client %s", - $refresh_token_value, $this->current_client->client_id + $refresh_token_value, $this->current_client->getClientId() ) ); } @@ -156,7 +171,7 @@ final class RefreshBearerTokenGrantType extends AbstractGrantType * legitimate client, one of them will present an invalidated refresh * token, which will inform the authorization server of the breach. */ - if ($this->current_client->rotate_refresh_token) + if ($this->current_client->useRotateRefreshTokenPolicy()) { $this->token_service->invalidateRefreshToken($refresh_token_value); $new_refresh_token = $this->token_service->createRefreshToken($access_token); @@ -182,6 +197,7 @@ final class RefreshBearerTokenGrantType extends AbstractGrantType } /** + * @return array * @throws InvalidOAuth2Request */ public function getResponseType() @@ -191,7 +207,7 @@ final class RefreshBearerTokenGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return null|OAuth2RefreshAccessTokenRequest + * @return null|OAuth2Response */ public function buildTokenRequest(OAuth2Request $request) { diff --git a/app/libs/oauth2/grant_types/RevokeBearerTokenGrantType.php b/app/libs/OAuth2/GrantTypes/RevokeBearerTokenGrantType.php similarity index 80% rename from app/libs/oauth2/grant_types/RevokeBearerTokenGrantType.php rename to app/libs/OAuth2/GrantTypes/RevokeBearerTokenGrantType.php index 5e24c8dd..932812b0 100644 --- a/app/libs/oauth2/grant_types/RevokeBearerTokenGrantType.php +++ b/app/libs/OAuth2/GrantTypes/RevokeBearerTokenGrantType.php @@ -1,24 +1,40 @@ -isValid(); + return $request instanceof OAuth2TokenRevocationRequest && $request->isValid(); } /** defines entry point for first request processing * @param OAuth2Request $request - * @throws \oauth2\exceptions\InvalidOAuth2Request - * @return mixed + * @throws InvalidOAuth2Request + * @return OAuth2Response */ public function handle(OAuth2Request $request) { @@ -74,16 +90,16 @@ class RevokeBearerTokenGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return OAuth2TokenRevocationResponse + * @return OAuth2Response * @throws BearerTokenDisclosureAttemptException * @throws Exception * @throws ExpiredAccessTokenException * @throws InvalidOAuth2Request * @throws UnAuthorizedClientException - * @throws \oauth2\exceptions\InvalidClientCredentials - * @throws \oauth2\exceptions\InvalidClientException - * @throws \oauth2\exceptions\LockedClientException - * @throws \oauth2\exceptions\MissingClientIdParam + * @throws InvalidClientCredentials + * @throws InvalidClientException + * @throws LockedClientException + * @throws MissingClientIdParam */ public function completeFlow(OAuth2Request $request) { @@ -233,12 +249,11 @@ class RevokeBearerTokenGrantType extends AbstractGrantType $ex->getMessage() ); } - } /** * get grant type - * @return mixed + * @return string */ public function getType() { @@ -246,8 +261,8 @@ class RevokeBearerTokenGrantType extends AbstractGrantType } /** get grant type response type - * @return mixed - * @throws \oauth2\exceptions\InvalidOAuth2Request + * @return array + * @throws InvalidOAuth2Request */ public function getResponseType() { @@ -256,8 +271,8 @@ class RevokeBearerTokenGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return mixed|void - * @throws \oauth2\exceptions\InvalidOAuth2Request + * @return OAuth2Response + * @throws InvalidOAuth2Request */ public function buildTokenRequest(OAuth2Request $request) { diff --git a/app/libs/OAuth2/GrantTypes/Strategies/IValidateBearerTokenStrategy.php b/app/libs/OAuth2/GrantTypes/Strategies/IValidateBearerTokenStrategy.php new file mode 100644 index 00000000..42ff67bd --- /dev/null +++ b/app/libs/OAuth2/GrantTypes/Strategies/IValidateBearerTokenStrategy.php @@ -0,0 +1,26 @@ +token_service = $token_service; + } + + /** + * @param AccessToken $access_token + * @param IClient $client + * @throws BearerTokenDisclosureAttemptException + * @throws InvalidApplicationType + * @throws LockedClientException + */ + public function validate(AccessToken $access_token, IClient $client) + { + // current client is a resource server, validate client type (must be confidential) + if ($client->getClientType() !== IClient::ClientType_Confidential) + { + throw new InvalidApplicationType + ( + 'resource server client is not of confidential type!' + ); + } + //validate resource server IP address + $current_ip = IPHelper::getUserIp(); + $resource_server = $client->getResourceServer(); + //check if resource server is active + if (!$resource_server->isActive()) + { + throw new LockedClientException + ( + 'resource server is disabled!' + ); + } + //check resource server ip address + if (!$resource_server->isOwn($current_ip)) + { + throw new BearerTokenDisclosureAttemptException + ( + sprintf + ( + 'resource server ip (%s) differs from current request ip %s', + $resource_server->getIPAddresses(), + $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 + ( + sprintf + ( + 'access token current audience does not match with current request ip %s', + $current_ip + ) + ); + } + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/GrantTypes/Strategies/ValidateBearerTokenStrategy.php b/app/libs/OAuth2/GrantTypes/Strategies/ValidateBearerTokenStrategy.php new file mode 100644 index 00000000..c72460de --- /dev/null +++ b/app/libs/OAuth2/GrantTypes/Strategies/ValidateBearerTokenStrategy.php @@ -0,0 +1,58 @@ +client_auth_context = $client_auth_context; + } + + /** + * @param AccessToken $access_token + * @param IClient $client + * @throws BearerTokenDisclosureAttemptException + */ + public function validate(AccessToken $access_token, IClient $client) + { + // if current client is not a resource server, then we could only access to our own tokens + if ($access_token->getClientId() !== $this->client_auth_context->getId()) + { + throw new BearerTokenDisclosureAttemptException + ( + sprintf + ( + 'access token %s does not belongs to client id %s', + $access_token->getValue(), + $this->client_auth_context->getId() + ) + ); + } + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/GrantTypes/Strategies/ValidateBearerTokenStrategyFactory.php b/app/libs/OAuth2/GrantTypes/Strategies/ValidateBearerTokenStrategyFactory.php new file mode 100644 index 00000000..13646ebe --- /dev/null +++ b/app/libs/OAuth2/GrantTypes/Strategies/ValidateBearerTokenStrategyFactory.php @@ -0,0 +1,37 @@ +isResourceServerClient()) + return new ValidateBearerTokenResourceServerStrategy($token_service); + return new ValidateBearerTokenStrategy($client_auth_context); + } +} \ No newline at end of file diff --git a/app/libs/oauth2/grant_types/ValidateBearerTokenGrantType.php b/app/libs/OAuth2/GrantTypes/ValidateBearerTokenGrantType.php similarity index 56% rename from app/libs/oauth2/grant_types/ValidateBearerTokenGrantType.php rename to app/libs/OAuth2/GrantTypes/ValidateBearerTokenGrantType.php index 89ca2e42..fb6f6d4a 100644 --- a/app/libs/oauth2/grant_types/ValidateBearerTokenGrantType.php +++ b/app/libs/OAuth2/GrantTypes/ValidateBearerTokenGrantType.php @@ -1,23 +1,38 @@ -auth_service = $auth_service; } @@ -94,8 +114,8 @@ class ValidateBearerTokenGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return mixed|void - * @throws \oauth2\exceptions\InvalidOAuth2Request + * @return OAuth2Response + * @throws InvalidOAuth2Request */ public function handle(OAuth2Request $request) { @@ -104,14 +124,14 @@ class ValidateBearerTokenGrantType extends AbstractGrantType /** * @param OAuth2Request $request - * @return OAuth2AccessTokenValidationResponse + * @return OAuth2Response * @throws BearerTokenDisclosureAttemptException * @throws ExpiredAccessTokenException * @throws InvalidApplicationType * @throws InvalidOAuth2Request * @throws LockedClientException - * @throws \oauth2\exceptions\InvalidClientCredentials - * @throws \oauth2\exceptions\InvalidClientException + * @throws InvalidClientCredentials + * @throws InvalidClientException */ public function completeFlow(OAuth2Request $request) { @@ -140,72 +160,26 @@ class ValidateBearerTokenGrantType extends AbstractGrantType ); } - 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->client_auth_context->getId()) - { - throw new BearerTokenDisclosureAttemptException - ( - sprintf - ( - 'access token %s does not belongs to client id %s', - $token_value, - $this->client_auth_context->getId() - ) - ); - } - } - else - { - // current client is a resource server, validate client type (must be confidential) - if ($this->current_client->getClientType() !== IClient::ClientType_Confidential) - { - throw new InvalidApplicationType - ( - '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 - ( - 'resource server is disabled!' - ); - } - //check resource server ip address - if (!$resource_server->isOwn($current_ip)) - { - throw new BearerTokenDisclosureAttemptException - ( - sprintf - ( - 'resource server ip (%s) differs from current request ip %s', - $resource_server->getIPAddresses(), - $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 - ( - sprintf - ( - 'access token current audience does not match with current request ip %s', - $current_ip - ) - ); - } - } - $this->log_service->debug_msg(sprintf("access token client id %s", $access_token->getClientId())); + $this->log_service->debug_msg + ( + sprintf + ( + "ValidateBearerTokenGrantType::completeFlow : access token %s - client id %s", + $access_token->getValue(), + $access_token->getClientId() + ) + ); - $issued_client = $this->client_service->getClientById($access_token->getClientId()); + $strategy = ValidateBearerTokenStrategyFactory::build + ( + $this->client_auth_context, + $this->token_service, + $this->current_client + ); + + $strategy->validate($access_token, $this->current_client); + + $issued_client = $this->client_repository->getClientById($access_token->getClientId()); if (is_null($issued_client)) { @@ -221,7 +195,7 @@ class ValidateBearerTokenGrantType extends AbstractGrantType } $user_id = $access_token->getUserId(); - $user = is_null($user_id) ? null: $this->auth_service->getUserById($user_id); + $user = !is_null($user_id) && $user_id > 0 ? $this->auth_service->getUserById($user_id) : null; return new OAuth2AccessTokenValidationResponse ( @@ -254,6 +228,7 @@ class ValidateBearerTokenGrantType extends AbstractGrantType } /** + * @return array * @throws InvalidOAuth2Request */ public function getResponseType() @@ -263,6 +238,7 @@ class ValidateBearerTokenGrantType extends AbstractGrantType /** * @param OAuth2Request $request + * @return OAuth2Response * @throws InvalidOAuth2Request */ public function buildTokenRequest(OAuth2Request $request) diff --git a/app/libs/oauth2/heuristics/ClientEncryptionKeyFinder.php b/app/libs/OAuth2/Heuristics/ClientEncryptionKeyFinder.php similarity index 90% rename from app/libs/oauth2/heuristics/ClientEncryptionKeyFinder.php rename to app/libs/OAuth2/Heuristics/ClientEncryptionKeyFinder.php index cc9f547a..5eccc091 100644 --- a/app/libs/oauth2/heuristics/ClientEncryptionKeyFinder.php +++ b/app/libs/OAuth2/Heuristics/ClientEncryptionKeyFinder.php @@ -1,4 +1,5 @@ -user_id = $auth_code->getUserId(); $instance->scope = $auth_code->getScope(); // client id (oauth2) not client identifier @@ -76,16 +95,27 @@ class AccessToken extends Token { return $instance; } + /** + * @return AuthorizationCode + */ public function getAuthCode(){ return $this->auth_code; } + /** + * @return RefreshToken + */ public function getRefreshToken(){ return $this->refresh_token; } + /** + * @param RefreshToken $refresh_token + * @return $this + */ public function setRefreshToken(RefreshToken $refresh_token){ - $this->refresh_token = $refresh_token;; + $this->refresh_token = $refresh_token; + return $this; } diff --git a/app/libs/oauth2/models/AuthorizationCode.php b/app/libs/OAuth2/Models/AuthorizationCode.php similarity index 91% rename from app/libs/oauth2/models/AuthorizationCode.php rename to app/libs/OAuth2/Models/AuthorizationCode.php index 0abf3567..0e53a91e 100644 --- a/app/libs/oauth2/models/AuthorizationCode.php +++ b/app/libs/OAuth2/Models/AuthorizationCode.php @@ -1,21 +1,43 @@ -is_hashed = false; - $this->issued = gmdate("Y-m-d H:i:s", time()); - $this->from_ip = IPHelper::getUserIp(); + $this->issued = gmdate("Y-m-d H:i:s", time()); + $this->from_ip = IPHelper::getUserIp(); } public function getIssued() @@ -45,6 +70,9 @@ abstract class Token extends Identifier return $this->issued; } + /** + * @return string + */ public function getScope() { return $this->scope; @@ -101,6 +129,9 @@ abstract class Token extends Identifier return $seconds; } + /** + * @return bool + */ public function isHashed() { return $this->is_hashed; diff --git a/app/libs/oauth2/models/TokenEndpointAuthInfo.php b/app/libs/OAuth2/Models/TokenEndpointAuthInfo.php similarity index 57% rename from app/libs/oauth2/models/TokenEndpointAuthInfo.php rename to app/libs/OAuth2/Models/TokenEndpointAuthInfo.php index 03023f20..1836f124 100644 --- a/app/libs/oauth2/models/TokenEndpointAuthInfo.php +++ b/app/libs/OAuth2/Models/TokenEndpointAuthInfo.php @@ -1,24 +1,20 @@ -container, true); return $string; } + /** + * @param string $param + * @return null|mixed + */ public function getParam($param) { return isset($this->container[$param])? $this->container[$param] : null; diff --git a/app/libs/oauth2/OAuth2Protocol.php b/app/libs/OAuth2/OAuth2Protocol.php similarity index 92% rename from app/libs/oauth2/OAuth2Protocol.php rename to app/libs/OAuth2/OAuth2Protocol.php index bc0e498e..f58bf29d 100644 --- a/app/libs/oauth2/OAuth2Protocol.php +++ b/app/libs/OAuth2/OAuth2Protocol.php @@ -1,6 +1,16 @@ -log_service = $log_service; $this->checkpoint_service = $checkpoint_service; $this->client_service = $client_service; + $this->client_repository = $client_repository; $this->auth_service = $auth_service; $this->principal_service = $principal_service; $this->token_service = $token_service; $this->authorize_endpoint = new AuthorizationEndpoint($this); $this->token_endpoint = new TokenEndpoint($this); - $this->revoke_endpoint = new TokenRevocationEndpoint($this,$client_service, $token_service, $log_service); - $this->introspection_endpoint = new TokenIntrospectionEndpoint($this, $client_service, $token_service, $auth_service, $log_service); + $this->revoke_endpoint = new TokenRevocationEndpoint($this, $client_service, $client_repository, $token_service, $log_service); + $this->introspection_endpoint = new TokenIntrospectionEndpoint($this, $client_service, $client_repository, $token_service, $auth_service, $log_service); } /** * @param OAuth2Request $request - * @return mixed|OAuth2IndirectErrorResponse - * @throws \Exception - * @throws exceptions\UriNotAllowedException + * @return OAuth2Response + * @throws Exception + * @throws UriNotAllowedException */ public function authorize(OAuth2Request $request = null) { @@ -966,7 +973,7 @@ final class OAuth2Protocol implements IOAuth2Protocol /** * @param OAuth2Request $request - * @return OAuth2DirectErrorResponse|void + * @return OAuth2Response */ public function token(OAuth2Request $request = null) { @@ -987,7 +994,7 @@ final class OAuth2Protocol implements IOAuth2Protocol $this->log_service->warning($ex1); $this->checkpoint_service->trackException($ex1); - return new OAuth2DirectErrorResponse($ex1->getError(), $ex1->getMessage());; + return new OAuth2DirectErrorResponse($ex1->getError(), $ex1->getMessage()); } catch (Exception $ex) { @@ -1004,9 +1011,9 @@ final class OAuth2Protocol implements IOAuth2Protocol /** * Revoke Token Endpoint - * http://tools.ietf.org/html/rfc7009 + * @see http://tools.ietf.org/html/rfc7009 * @param OAuth2Request $request - * @return mixed + * @return OAuth2Response */ public function revoke(OAuth2Request $request = null){ @@ -1031,9 +1038,9 @@ final class OAuth2Protocol implements IOAuth2Protocol /** * Introspection Token Endpoint - * http://tools.ietf.org/html/draft-richer-oauth-introspection-04 + * @see http://tools.ietf.org/html/draft-richer-oauth-introspection-04 * @param OAuth2Request $request - * @return mixed + * @return OAuth2Response */ public function introspection(OAuth2Request $request = null) { @@ -1084,8 +1091,8 @@ final class OAuth2Protocol implements IOAuth2Protocol */ static public function isClientAllowedToUseTokenEndpointAuth(IClient $client) { - return $client->client_type === IClient::ClientType_Confidential || - $client->application_type === IClient::ApplicationType_Native; + return $client->getClientType() === IClient::ClientType_Confidential || + $client->getApplicationType() === IClient::ApplicationType_Native; } static public function getTokenEndpointAuthMethodsPerClientType(IClient $client) @@ -1212,7 +1219,7 @@ final class OAuth2Protocol implements IOAuth2Protocol } /** - * http://openid.net/specs/openid-connect-discovery-1_0.html + * @see http://openid.net/specs/openid-connect-discovery-1_0.html * @return string */ public function getDiscoveryDocument() @@ -1314,9 +1321,9 @@ final class OAuth2Protocol implements IOAuth2Protocol } /** - * http://openid.net/specs/openid-connect-session-1_0.html#RPLogout - * @param OAuth2Request|null $request - * @return null|OAuth2DirectErrorResponse + * @see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout + * @param OAuth2Request $request + * @return OAuth2Response */ public function endSession(OAuth2Request $request = null) { @@ -1343,7 +1350,7 @@ final class OAuth2Protocol implements IOAuth2Protocol if(is_null($client_id)) throw new InvalidClientException('claim aud not set on id_token_hint!'); - $client = $this->client_service->getClientById($client_id->getString()); + $client = $this->client_repository->getClientById($client_id->getString()); if(is_null($client)) throw new InvalidClientException('client not found!'); @@ -1377,20 +1384,19 @@ final class OAuth2Protocol implements IOAuth2Protocol return null; } - - catch(OAuth2BaseException $ex1) + catch (UriNotAllowedException $ex1) { $this->log_service->warning($ex1); $this->checkpoint_service->trackException($ex1); - return new OAuth2DirectErrorResponse($ex1->getError(), $ex1->getMessage());; + return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient); } - catch (UriNotAllowedException $ex2) + catch(OAuth2BaseException $ex2) { $this->log_service->warning($ex2); $this->checkpoint_service->trackException($ex2); - return new OAuth2DirectErrorResponse(OAuth2Protocol::OAuth2Protocol_Error_UnauthorizedClient); + return new OAuth2DirectErrorResponse($ex2->getError(), $ex2->getMessage()); } catch (Exception $ex) { @@ -1427,7 +1433,7 @@ final class OAuth2Protocol implements IOAuth2Protocol $client_id = $request->getClientId(); if (is_null($client_id)) return null; - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); if (is_null($client)) return null; if (!$client->isUriAllowed($redirect_uri)) diff --git a/app/libs/OAuth2/OAuth2ServiceProvider.php b/app/libs/OAuth2/OAuth2ServiceProvider.php new file mode 100644 index 00000000..67ec82ec --- /dev/null +++ b/app/libs/OAuth2/OAuth2ServiceProvider.php @@ -0,0 +1,39 @@ +getRedirectUri(); + + if (is_null($redirect_uri)) + { + $this->last_validation_error = 'redirect_uri not set'; + return false; + } + + return true; + } + + /** + * @return null|string + */ + public function getRedirectUri() + { + return $this->getParam(OAuth2Protocol::OAuth2Protocol_RedirectUri); + } + + /** + * @return null|string + */ + public function getClientId() + { + return $this->getParam(OAuth2Protocol::OAuth2Protocol_ClientId); + } + + /** + * @return null|string + */ + public function getCode() + { + return $this->getParam(OAuth2Protocol::OAuth2Protocol_ResponseType_Code); + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Requests/OAuth2AccessTokenRequestClientCredentials.php b/app/libs/OAuth2/Requests/OAuth2AccessTokenRequestClientCredentials.php new file mode 100644 index 00000000..af090caf --- /dev/null +++ b/app/libs/OAuth2/Requests/OAuth2AccessTokenRequestClientCredentials.php @@ -0,0 +1,52 @@ +getParam(OAuth2Protocol::OAuth2Protocol_Scope); + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Requests/OAuth2AccessTokenValidationRequest.php b/app/libs/OAuth2/Requests/OAuth2AccessTokenValidationRequest.php new file mode 100644 index 00000000..81692b60 --- /dev/null +++ b/app/libs/OAuth2/Requests/OAuth2AccessTokenValidationRequest.php @@ -0,0 +1,55 @@ +last_validation_error = ''; + $token = $this->getToken(); + + if(is_null($token)) { + $this->last_validation_error = 'token not set'; + return false; + } + + return true; + } + + /** + * @return null|string + */ + public function getToken(){ + return $this->getParam(OAuth2Protocol::OAuth2Protocol_Token); + } +} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2AuthenticationRequest.php b/app/libs/OAuth2/Requests/OAuth2AuthenticationRequest.php similarity index 96% rename from app/libs/oauth2/requests/OAuth2AuthenticationRequest.php rename to app/libs/OAuth2/Requests/OAuth2AuthenticationRequest.php index f446e92f..e0c0b2a9 100644 --- a/app/libs/oauth2/requests/OAuth2AuthenticationRequest.php +++ b/app/libs/OAuth2/Requests/OAuth2AuthenticationRequest.php @@ -1,4 +1,4 @@ -getRefreshToken(); + + if(is_null($refresh_token)) { + $this->last_validation_error = 'refresh_token not set'; + return false; + } + + return true; + } + + /** + * @return null|string + */ + public function getRefreshToken(){ + return $this->getParam(OAuth2Protocol::OAuth2Protocol_RefreshToken); + } + + /** + * @return null|string + */ + public function getScope(){ + return $this->getParam(OAuth2Protocol::OAuth2Protocol_Scope); + } +} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2Request.php b/app/libs/OAuth2/Requests/OAuth2Request.php similarity index 64% rename from app/libs/oauth2/requests/OAuth2Request.php rename to app/libs/OAuth2/Requests/OAuth2Request.php index 1bb8267e..0aeb3a58 100644 --- a/app/libs/oauth2/requests/OAuth2Request.php +++ b/app/libs/OAuth2/Requests/OAuth2Request.php @@ -1,11 +1,22 @@ -last_validation_error = ''; + + $grant_type = $this->getGrantType(); + + if(is_null($grant_type)) { + $this->last_validation_error = 'grant_type not set'; + return false; + } + + return true; + } + + /** + * @return null|string + */ + public function getGrantType() + { + return $this->getParam(OAuth2Protocol::OAuth2Protocol_GrantType); + } +} \ No newline at end of file diff --git a/app/libs/OAuth2/Requests/OAuth2TokenRevocationRequest.php b/app/libs/OAuth2/Requests/OAuth2TokenRevocationRequest.php new file mode 100644 index 00000000..787d82b2 --- /dev/null +++ b/app/libs/OAuth2/Requests/OAuth2TokenRevocationRequest.php @@ -0,0 +1,63 @@ +last_validation_error = ''; + + $token = $this->getToken(); + + if(is_null($token)) { + $this->last_validation_error = 'token not set'; + return false; + } + + return true; + } + + /** + * @return null|string + */ + public function getToken(){ + return $this->getParam(OAuth2Protocol::OAuth2Protocol_Token); + } + + /** + * @return null|string + */ + public function getTokenHint(){ + return $this->getParam(OAuth2Protocol::OAuth2Protocol_TokenType_Hint); + } +} \ No newline at end of file diff --git a/app/libs/oauth2/resource_server/IUserService.php b/app/libs/OAuth2/ResourceServer/IUserService.php similarity index 53% rename from app/libs/oauth2/resource_server/IUserService.php rename to app/libs/OAuth2/ResourceServer/IUserService.php index 09977d04..66a0a40f 100644 --- a/app/libs/oauth2/resource_server/IUserService.php +++ b/app/libs/OAuth2/ResourceServer/IUserService.php @@ -1,12 +1,20 @@ -log_service = $log_service; + $this->resource_server_context = $resource_server_context; + } +} \ No newline at end of file diff --git a/app/config/packages/greggilbert/recaptcha/dev/.gitkeep b/app/libs/OAuth2/Responses/.gitkeep similarity index 100% rename from app/config/packages/greggilbert/recaptcha/dev/.gitkeep rename to app/libs/OAuth2/Responses/.gitkeep diff --git a/app/libs/oauth2/responses/OAuth2AccessTokenFragmentResponse.php b/app/libs/OAuth2/Responses/OAuth2AccessTokenFragmentResponse.php similarity index 51% rename from app/libs/oauth2/responses/OAuth2AccessTokenFragmentResponse.php rename to app/libs/OAuth2/Responses/OAuth2AccessTokenFragmentResponse.php index d8c694aa..e9dcdf72 100644 --- a/app/libs/oauth2/responses/OAuth2AccessTokenFragmentResponse.php +++ b/app/libs/OAuth2/Responses/OAuth2AccessTokenFragmentResponse.php @@ -1,22 +1,30 @@ -container); + return $json_encoded_format; + } + + public function getType() + { + return self::OAuth2DirectResponse; + } +} \ No newline at end of file diff --git a/app/libs/oauth2/responses/OAuth2HybridTokenFragmentResponse.php b/app/libs/OAuth2/Responses/OAuth2HybridTokenFragmentResponse.php similarity index 91% rename from app/libs/oauth2/responses/OAuth2HybridTokenFragmentResponse.php rename to app/libs/OAuth2/Responses/OAuth2HybridTokenFragmentResponse.php index 163de476..20199141 100644 --- a/app/libs/oauth2/responses/OAuth2HybridTokenFragmentResponse.php +++ b/app/libs/OAuth2/Responses/OAuth2HybridTokenFragmentResponse.php @@ -1,4 +1,5 @@ -realm = $realm; $this->error = $error; $this->error_description = $error_description; @@ -35,7 +71,9 @@ class OAuth2WWWAuthenticateErrorResponse extends OAuth2DirectResponse { return $value; } - + /** + * @return array + */ public function getContent() { $content = array( diff --git a/app/config/packages/greggilbert/recaptcha/local/.gitkeep b/app/libs/OAuth2/Services/.gitkeep similarity index 100% rename from app/config/packages/greggilbert/recaptcha/local/.gitkeep rename to app/libs/OAuth2/Services/.gitkeep diff --git a/app/libs/oauth2/services/AccessTokenGenerator.php b/app/libs/OAuth2/Services/AccessTokenGenerator.php similarity index 82% rename from app/libs/oauth2/services/AccessTokenGenerator.php rename to app/libs/OAuth2/Services/AccessTokenGenerator.php index fb0df891..1d4ccfa9 100644 --- a/app/libs/oauth2/services/AccessTokenGenerator.php +++ b/app/libs/OAuth2/Services/AccessTokenGenerator.php @@ -1,4 +1,4 @@ -getResponseType(false); diff --git a/app/libs/oauth2/strategies/OAuth2ResponseStrategyFactoryMethod.php b/app/libs/OAuth2/Strategies/OAuth2ResponseStrategyFactoryMethod.php similarity index 67% rename from app/libs/oauth2/strategies/OAuth2ResponseStrategyFactoryMethod.php rename to app/libs/OAuth2/Strategies/OAuth2ResponseStrategyFactoryMethod.php index fc5e9178..b7621656 100644 --- a/app/libs/oauth2/strategies/OAuth2ResponseStrategyFactoryMethod.php +++ b/app/libs/OAuth2/Strategies/OAuth2ResponseStrategyFactoryMethod.php @@ -1,21 +1,33 @@ -auth_service = $auth_service; - self::$available_properties[OpenIdAXExtension::Country] = "http://axschema.org/contact/country/home"; - self::$available_properties[OpenIdAXExtension::Email] = "http://axschema.org/contact/email"; + + self::$available_properties[OpenIdAXExtension::Country] = "http://axschema.org/contact/country/home"; + self::$available_properties[OpenIdAXExtension::Email] = "http://axschema.org/contact/email"; self::$available_properties[OpenIdAXExtension::FirstMame] = "http://axschema.org/namePerson/first"; - self::$available_properties[OpenIdAXExtension::LastName] = "http://axschema.org/namePerson/last"; - self::$available_properties[OpenIdAXExtension::Language] = "http://axschema.org/pref/language"; + self::$available_properties[OpenIdAXExtension::LastName] = "http://axschema.org/namePerson/last"; + self::$available_properties[OpenIdAXExtension::Language] = "http://axschema.org/pref/language"; } + /** + * @param OpenIdRequest $request + * @param RequestContext $context + * @return void + */ public function parseRequest(OpenIdRequest $request, RequestContext $context) { try { @@ -75,6 +97,12 @@ class OpenIdAXExtension extends OpenIdExtension } } + /** + * @param OpenIdRequest $request + * @param OpenIdResponse $response + * @param ResponseContext $context + * @return void + */ public function prepareResponse(OpenIdRequest $request, OpenIdResponse $response, ResponseContext $context) { try { @@ -113,16 +141,29 @@ class OpenIdAXExtension extends OpenIdExtension } } + /** + * @param string $separator + * @return string + */ public static function paramNamespace($separator = '.') { return OpenIdProtocol::OpenIdPrefix . $separator . OpenIdProtocol::OpenIDProtocol_NS . $separator . self::Prefix; } + /** + * @param $param + * @param string $separator + * @return string + */ public static function param($param, $separator = '.') { return OpenIdProtocol::OpenIdPrefix . $separator . self::Prefix . $separator . $param; } + /** + * @param OpenIdRequest $request + * @return array + */ public function getTrustedData(OpenIdRequest $request) { $data = array(); @@ -135,6 +176,7 @@ class OpenIdAXExtension extends OpenIdExtension } } } catch (Exception $ex) { + $this->log_service->debug_msg($request->__toString()); $this->log_service->error($ex); } return $data; diff --git a/app/libs/OpenId/Extensions/Implementations/OpenIdAXRequest.php b/app/libs/OpenId/Extensions/Implementations/OpenIdAXRequest.php new file mode 100644 index 00000000..12b669ff --- /dev/null +++ b/app/libs/OpenId/Extensions/Implementations/OpenIdAXRequest.php @@ -0,0 +1,98 @@ +attributes = array(); + } + + /** + * @return bool + * @throws InvalidOpenIdMessageException + */ + public function isValid() + { + + //check identifier + if (isset($this->message[OpenIdAXExtension::paramNamespace(HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]) + && $this->message[OpenIdAXExtension::paramNamespace(HttpMessage::PHP_REQUEST_VAR_SEPARATOR)] == OpenIdAXExtension::NamespaceUrl + ) { + + //check required fields + + if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]) + || $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)] != OpenIdAXExtension::FetchRequest + ) + throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidModeMessage); + + if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])) + throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidRequiredAttributesMessage); + + //get attributes + $attributes = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]; + $attributes = explode(",", $attributes); + + foreach ($attributes as $attr) { + $attr = trim($attr); + if (!isset(OpenIdAXExtension::$available_properties[$attr])) + continue; + + $attr_ns = OpenIdAXExtension::param(OpenIdAXExtension::Type, HttpMessage::PHP_REQUEST_VAR_SEPARATOR) . HttpMessage::PHP_REQUEST_VAR_SEPARATOR . $attr; + + if (!isset($this->message[$attr_ns])) + throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage,$attr_ns, $attr)); + + $ns = $this->message[$attr_ns]; + + if ($ns != OpenIdAXExtension::$available_properties[$attr]) + throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $ns, $attr)); + + array_push($this->attributes, $attr); + } + return true; + } + return false; + } + + /** + * @return array + */ + public function getRequiredAttributes() + { + return $this->attributes; + } +} \ No newline at end of file diff --git a/app/libs/openid/extensions/implementations/OpenIdOAuth2Extension.php b/app/libs/OpenId/Extensions/Implementations/OpenIdOAuth2Extension.php similarity index 76% rename from app/libs/openid/extensions/implementations/OpenIdOAuth2Extension.php rename to app/libs/OpenId/Extensions/Implementations/OpenIdOAuth2Extension.php index 1d457845..11af3916 100644 --- a/app/libs/openid/extensions/implementations/OpenIdOAuth2Extension.php +++ b/app/libs/OpenId/Extensions/Implementations/OpenIdOAuth2Extension.php @@ -1,27 +1,35 @@ -oauth2_protocol = $oauth2_protocol; - $this->client_service = $client_service; - $this->scope_service = $scope_service; + $this->client_repository = $client_repository; + $this->scope_repository = $scope_repository; $this->checkpoint_service = $checkpoint_service; } @@ -112,7 +133,7 @@ class OpenIdOAuth2Extension extends OpenIdExtension $scopes = $oauth2_request->getScope(); $client_id = $oauth2_request->getClientId(); - $client = $this->client_service->getClientById($client_id); + $client = $this->client_repository->getClientById($client_id); // do some validations to allow show the oauth2 sub view... if(is_null($client)){ $this->log_service->warning_msg(sprintf("OpenIdOAuth2Extension: client id %s not found!.",$client_id)); @@ -134,7 +155,7 @@ class OpenIdOAuth2Extension extends OpenIdExtension $scopes = explode(' ', $scopes); //get scopes entities - $requested_scopes = $this->scope_service->getScopesByName($scopes); + $requested_scopes = $this->scope_repository->getByName($scopes); // set view data @@ -183,7 +204,7 @@ class OpenIdOAuth2Extension extends OpenIdExtension // do oauth2 Authorization Code Grant 1st step (get auth code to exchange for an access token) // http://tools.ietf.org/html/rfc6749#section-4.1 $oauth2_response = $this->oauth2_protocol->authorize(new OAuth2AuthorizationRequest($oauth2_msg)); - if ( get_class($oauth2_response) =='oauth2\\responses\\OAuth2AuthorizationResponse') { + if ( $oauth2_response instanceof OAuth2AuthorizationResponse ) { //add namespace $response->addParam(self::paramNamespace(),self::NamespaceUrl ); $context->addSignParam(self::paramNamespace()); diff --git a/app/libs/openid/extensions/implementations/OpenIdOAuth2Request.php b/app/libs/OpenId/Extensions/Implementations/OpenIdOAuth2Request.php similarity index 57% rename from app/libs/openid/extensions/implementations/OpenIdOAuth2Request.php rename to app/libs/OpenId/Extensions/Implementations/OpenIdOAuth2Request.php index 97b40fcd..493c919c 100644 --- a/app/libs/openid/extensions/implementations/OpenIdOAuth2Request.php +++ b/app/libs/OpenId/Extensions/Implementations/OpenIdOAuth2Request.php @@ -1,16 +1,25 @@ -message[OpenIdOAuth2Extension::paramNamespace('_')]) - && $this->message[OpenIdOAuth2Extension::paramNamespace('_')] == OpenIdOAuth2Extension::NamespaceUrl + $ns = OpenIdOAuth2Extension::paramNamespace(HttpMessage::PHP_REQUEST_VAR_SEPARATOR); + if (isset($this->message[$ns]) + && $this->message[$ns] == OpenIdOAuth2Extension::NamespaceUrl ) { if(is_null($this->getClientId())) throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::OAuth2MissingRequiredParam,'client_id')); @@ -52,8 +62,8 @@ class OpenIdOAuth2Request extends OpenIdRequest { * @return null|string */ public function getApprovalPrompt(){ - return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Approval_Prompt, '_')])? - $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Approval_Prompt, '_')]:OAuth2Protocol::OAuth2Protocol_Approval_Prompt_Auto; + return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Approval_Prompt, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])? + $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Approval_Prompt, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]:OAuth2Protocol::OAuth2Protocol_Approval_Prompt_Auto; } /** @@ -64,31 +74,31 @@ class OpenIdOAuth2Request extends OpenIdRequest { * @return null|string */ public function getAccessType(){ - return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_AccessType, '_')])? - $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_AccessType, '_')]:OAuth2Protocol::OAuth2Protocol_AccessType_Online; + return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_AccessType, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])? + $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_AccessType, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]:OAuth2Protocol::OAuth2Protocol_AccessType_Online; } /** * @return null|string */ public function getClientId(){ - return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_ClientId, '_')])? - $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_ClientId, '_')]:null; + return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_ClientId, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])? + $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_ClientId, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]:null; } /** * @return null|string */ public function getScope(){ - return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Scope, '_')])? - $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Scope, '_')]:null; + return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Scope, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])? + $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_Scope, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]:null; } /** * @return null|string */ public function getState(){ - return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_State, '_')])? - $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_State, '_')]:null; + return isset($this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_State, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])? + $this->message[OpenIdOAuth2Extension::param(OAuth2Protocol::OAuth2Protocol_State, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]:null; } } \ No newline at end of file diff --git a/app/libs/OpenId/Extensions/Implementations/OpenIdPAPEExtension.php b/app/libs/OpenId/Extensions/Implementations/OpenIdPAPEExtension.php new file mode 100644 index 00000000..32a0db91 --- /dev/null +++ b/app/libs/OpenId/Extensions/Implementations/OpenIdPAPEExtension.php @@ -0,0 +1,82 @@ +auth_service = $auth_service; + self::$available_properties[OpenIdSREGExtension::Nickname] = OpenIdSREGExtension::Nickname; self::$available_properties[OpenIdSREGExtension::Email] = OpenIdSREGExtension::Email; self::$available_properties[OpenIdSREGExtension::FullName] = OpenIdSREGExtension::FullName; @@ -70,6 +87,7 @@ class OpenIdSREGExtension extends OpenIdExtension public function parseRequest(OpenIdRequest $request, RequestContext $context) { try { + $simple_reg_request = new OpenIdSREGRequest($request->getMessage()); if (!$simple_reg_request->isValid()) return; @@ -91,6 +109,12 @@ class OpenIdSREGExtension extends OpenIdExtension } } + /** + * @param OpenIdRequest $request + * @param OpenIdResponse $response + * @param ResponseContext $context + * @return void + */ public function prepareResponse(OpenIdRequest $request, OpenIdResponse $response, ResponseContext $context) { try { @@ -125,30 +149,47 @@ class OpenIdSREGExtension extends OpenIdExtension } } + /** + * @param string $separator + * @return string + */ public static function paramNamespace($separator = '.') { return OpenIdProtocol::OpenIdPrefix . $separator . OpenIdProtocol::OpenIDProtocol_NS . $separator . self::Prefix; } + /** + * @param $param + * @param string $separator + * @return string + */ public static function param($param, $separator = '.') { return OpenIdProtocol::OpenIdPrefix . $separator . self::Prefix . $separator . $param; } + /** + * @param OpenIdRequest $request + * @return array + */ public function getTrustedData(OpenIdRequest $request) { $data = array(); try { $simple_reg_request = new OpenIdSREGRequest($request->getMessage()); + if ($simple_reg_request->isValid()) { - $attributes = $simple_reg_request->getRequiredAttributes(); + + $attributes = $simple_reg_request->getRequiredAttributes(); $opt_attributes = $simple_reg_request->getOptionalAttributes(); - $attributes = array_merge($attributes, $opt_attributes); + $attributes = array_merge($attributes, $opt_attributes); + foreach ($attributes as $key => $value) { array_push($data, $key); } } } catch (Exception $ex) { + $this->log_service->debug_msg($request->__toString()); $this->log_service->error($ex); } return $data; diff --git a/app/libs/openid/extensions/implementations/OpenIdSREGRequest.php b/app/libs/OpenId/Extensions/Implementations/OpenIdSREGRequest.php similarity index 63% rename from app/libs/openid/extensions/implementations/OpenIdSREGRequest.php rename to app/libs/OpenId/Extensions/Implementations/OpenIdSREGRequest.php index c62d84cc..ebfb1e34 100644 --- a/app/libs/openid/extensions/implementations/OpenIdSREGRequest.php +++ b/app/libs/OpenId/Extensions/Implementations/OpenIdSREGRequest.php @@ -1,37 +1,62 @@ -attributes = array(); + $this->attributes = array(); $this->optional_attributes = array(); } + /** + * @return bool + * @throws Exception + */ public function isValid() { try { //check identifier - if (isset($this->message[OpenIdSREGExtension::paramNamespace('_')]) - && $this->message[OpenIdSREGExtension::paramNamespace('_')] == OpenIdSREGExtension::NamespaceUrl + if (isset($this->message[OpenIdSREGExtension::paramNamespace(HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]) + && $this->message[OpenIdSREGExtension::paramNamespace(HttpMessage::PHP_REQUEST_VAR_SEPARATOR)] == OpenIdSREGExtension::NamespaceUrl ) { /* @@ -52,50 +77,43 @@ class OpenIdSREGRequest extends OpenIdRequest //check required fields - if( !isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Required, '_')]) && - !isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Optional, '_')])) + if ( + !isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Required, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]) && + !isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Optional, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]) + ) throw new InvalidOpenIdMessageException("SREG: at least one of \"openid.sreg.required\" or \"openid.sreg.optional\" MUST be specified in the request."); - //get attributes - if (isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Required, '_')])) { - - $attributes = $this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Required, '_')]; + //get required attributes + if (isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Required, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])) { + $attributes = $this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Required, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]; $attributes = explode(",", $attributes); foreach ($attributes as $attr) { $attr = trim($attr); - if (!isset(OpenIdSREGExtension::$available_properties[$attr])) continue; - $this->attributes[$attr] = $attr; } } //get optional attributes - if (isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Optional, '_')])) { - - $opt_attributes = $this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Optional, '_')]; + if (isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Optional, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])) { + $opt_attributes = $this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::Optional, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]; $opt_attributes = explode(",", $opt_attributes); - foreach ($opt_attributes as $opt_attr) { $opt_attr = trim($opt_attr); - if (!isset(OpenIdSREGExtension::$available_properties[$opt_attr])) continue; - if (isset($this->attributes[$opt_attr])) throw new InvalidOpenIdMessageException(sprintf("SREG: optional attribute %s is already set as required one!", $opt_attr)); - $this->optional_attributes[$opt_attr] = $opt_attr; } } //check policy url.. - if (isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::PolicyUrl, '_')])) { - $this->policy_url = $this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::PolicyUrl, '_')]; + if (isset($this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::PolicyUrl, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)])) { + $this->policy_url = $this->message[OpenIdSREGExtension::param(OpenIdSREGExtension::PolicyUrl, HttpMessage::PHP_REQUEST_VAR_SEPARATOR)]; } - return true; } } catch (Exception $ex) { @@ -104,16 +122,25 @@ class OpenIdSREGRequest extends OpenIdRequest return false; } + /** + * @return array + */ public function getRequiredAttributes() { return $this->attributes; } + /** + * @return array + */ public function getOptionalAttributes() { return $this->optional_attributes; } + /** + * @return string + */ public function getPolicyUrl() { return $this->policy_url; diff --git a/app/libs/openid/extensions/OpenIdAuthenticationExtension.php b/app/libs/OpenId/Extensions/OpenIdAuthenticationExtension.php similarity index 68% rename from app/libs/openid/extensions/OpenIdAuthenticationExtension.php rename to app/libs/OpenId/Extensions/OpenIdAuthenticationExtension.php index b47dacfd..4ac3d6f4 100644 --- a/app/libs/openid/extensions/OpenIdAuthenticationExtension.php +++ b/app/libs/OpenId/Extensions/OpenIdAuthenticationExtension.php @@ -1,20 +1,28 @@ -memento_service = $memento_service; } + /** + * @param User $user + * @return void + * @throws AuthenticationException + */ public function process(User $user) { if(!$this->memento_service->exists()) return; diff --git a/app/libs/openid/extensions/OpenIdExtension.php b/app/libs/OpenId/Extensions/OpenIdExtension.php similarity index 52% rename from app/libs/openid/extensions/OpenIdExtension.php rename to app/libs/OpenId/Extensions/OpenIdExtension.php index f69d497b..9d67b485 100644 --- a/app/libs/openid/extensions/OpenIdExtension.php +++ b/app/libs/OpenId/Extensions/OpenIdExtension.php @@ -1,34 +1,57 @@ -log_service = $log_service; } + /** + * @return string + */ public function getNamespace() { return $this->namespace; diff --git a/app/libs/openid/handlers/factories/SessionAssociationRequestFactory.php b/app/libs/OpenId/Handlers/Factories/SessionAssociationRequestFactory.php similarity index 54% rename from app/libs/openid/handlers/factories/SessionAssociationRequestFactory.php rename to app/libs/OpenId/Handlers/Factories/SessionAssociationRequestFactory.php index 5a025a36..6cb8988a 100644 --- a/app/libs/openid/handlers/factories/SessionAssociationRequestFactory.php +++ b/app/libs/OpenId/Handlers/Factories/SessionAssociationRequestFactory.php @@ -1,23 +1,36 @@ -current_request->getAssocHandle()) || is_null($association = $this->association_service->getAssociation($assoc_handle))) { //create private association ... - $association = $this->association_service->addAssociation(AssociationFactory::getInstance()->buildPrivateAssociation($realm, - $this->server_configuration_service->getConfigValue("Private.Association.Lifetime"))); + $association = $this->association_service->addAssociation + ( + AssociationFactory::getInstance()->buildPrivateAssociation + ( + $realm, + $this->server_configuration_service->getConfigValue("Private.Association.Lifetime") + ) + ); + $response->setAssocHandle($association->getHandle()); + if (!empty($assoc_handle)) { $response->setInvalidateHandle($assoc_handle); } @@ -385,8 +402,8 @@ final class OpenIdAuthenticationRequestHandler extends OpenIdMessageHandler /** * @param $authorization_response - * @return OpenIdNonImmediateNegativeAssertion|OpenIdPositiveAssertionResponse - * @throws \Exception + * @return OpenIdResponse + * @throws Exception */ private function checkAuthorizationResponse($authorization_response) { diff --git a/app/libs/openid/handlers/OpenIdCheckAuthenticationRequestHandler.php b/app/libs/OpenId/Handlers/OpenIdCheckAuthenticationRequestHandler.php similarity index 73% rename from app/libs/openid/handlers/OpenIdCheckAuthenticationRequestHandler.php rename to app/libs/OpenId/Handlers/OpenIdCheckAuthenticationRequestHandler.php index 86718b27..6bc8ad75 100644 --- a/app/libs/openid/handlers/OpenIdCheckAuthenticationRequestHandler.php +++ b/app/libs/OpenId/Handlers/OpenIdCheckAuthenticationRequestHandler.php @@ -1,27 +1,35 @@ -openid_configuration_service = $openid_configuration_service; } + /** + * @param OpenIdMessage $message + * @return OpenIdCheckAuthenticationResponse|OpenIdDirectGenericErrorResponse + */ protected function internalHandle(OpenIdMessage $message) { $this->current_request = null; try { - $this->current_request = new OpenIdCheckAuthenticationRequest($message,$this->openid_configuration_service->getOPEndpointURL()); - if (!$this->current_request->isValid()) - throw new InvalidOpenIdMessageException(OpenIdErrorMessages::InvalidOpenIdCheckAuthenticationRequestMessage); + $this->current_request = new OpenIdCheckAuthenticationRequest + ( + $message,$this->openid_configuration_service->getOPEndpointURL() + ); + if (!$this->current_request->isValid()) + throw new InvalidOpenIdMessageException + ( + OpenIdErrorMessages::InvalidOpenIdCheckAuthenticationRequestMessage + ); /** * For verifying signatures an OP MUST only use private associations and MUST NOT @@ -111,7 +140,14 @@ final class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler $this->nonce_service->markNonceAsInvalid($claimed_nonce, $claimed_sig, $claimed_realm); - $res = OpenIdSignatureBuilder::verify($this->current_request, $stored_assoc->getMacFunction(), $stored_assoc->getSecret(), $claimed_sig); + $res = OpenIdSignatureBuilder::verify + ( + $this->current_request, + $stored_assoc->getMacFunction(), + $stored_assoc->getSecret(), + $claimed_sig + ); + //delete association $this->association_service->deleteAssociation($claimed_assoc); $is_valid = $res ? 'true':'false'; @@ -154,9 +190,12 @@ final class OpenIdCheckAuthenticationRequestHandler extends OpenIdMessageHandler } } + /** + * @param OpenIdMessage $message + * @return bool + */ protected function canHandle(OpenIdMessage $message) { - $res = OpenIdCheckAuthenticationRequest::IsOpenIdCheckAuthenticationRequest($message); - return $res; + return OpenIdCheckAuthenticationRequest::IsOpenIdCheckAuthenticationRequest($message); } } \ No newline at end of file diff --git a/app/libs/openid/handlers/OpenIdMessageHandler.php b/app/libs/OpenId/Handlers/OpenIdMessageHandler.php similarity index 70% rename from app/libs/openid/handlers/OpenIdMessageHandler.php rename to app/libs/OpenId/Handlers/OpenIdMessageHandler.php index 586d60df..498b2c2c 100644 --- a/app/libs/openid/handlers/OpenIdMessageHandler.php +++ b/app/libs/OpenId/Handlers/OpenIdMessageHandler.php @@ -1,23 +1,30 @@ -current_request = null; @@ -77,7 +101,6 @@ final class OpenIdSessionAssociationRequestHandler extends OpenIdMessageHandler * @return bool */ protected function canHandle(OpenIdMessage $message) { - $res = OpenIdAssociationSessionRequest::IsOpenIdAssociationSessionRequest($message); - return $res; + return OpenIdAssociationSessionRequest::IsOpenIdAssociationSessionRequest($message); } } \ No newline at end of file diff --git a/app/libs/OpenId/Handlers/Strategies/SessionAssociation/ISessionAssociationStrategy.php b/app/libs/OpenId/Handlers/Strategies/SessionAssociation/ISessionAssociationStrategy.php new file mode 100644 index 00000000..1f9fa384 --- /dev/null +++ b/app/libs/OpenId/Handlers/Strategies/SessionAssociation/ISessionAssociationStrategy.php @@ -0,0 +1,28 @@ +current_request->getDHConsumerPublic(); //create association - $association = $this->association_service->addAssociation(AssociationFactory::getInstance()->buildSessionAssociation($assoc_type, $this->server_configuration_service->getConfigValue("Session.Association.Lifetime"))); + $association = $this->association_service->addAssociation(AssociationFactory::getInstance() + ->buildSessionAssociation + ( + $assoc_type, + $this->server_configuration_service->getConfigValue("Session.Association.Lifetime") + ) + ); + $dh = new DiffieHellman($public_prime, $public_generator); $dh->generateKeys(); //server public key (g ^ xb mod p ), where xb is server private key @@ -76,7 +108,6 @@ class SessionAssociationDHStrategy implements ISessionAssociationStrategy } catch (InvalidArgumentException $exDH1) { $response = new OpenIdDirectGenericErrorResponse($exDH1->getMessage()); $this->log_service->error($exDH1); - } catch (RuntimeException $exDH2) { $response = new OpenIdDirectGenericErrorResponse($exDH2->getMessage()); $this->log_service->error($exDH2); diff --git a/app/libs/OpenId/Handlers/Strategies/SessionAssociation/Implementations/SessionAssociationUnencryptedStrategy.php b/app/libs/OpenId/Handlers/Strategies/SessionAssociation/Implementations/SessionAssociationUnencryptedStrategy.php new file mode 100644 index 00000000..e40a3a06 --- /dev/null +++ b/app/libs/OpenId/Handlers/Strategies/SessionAssociation/Implementations/SessionAssociationUnencryptedStrategy.php @@ -0,0 +1,112 @@ +current_request = $request; + $this->association_service = $association_service; + $this->server_configuration_service = $server_configuration_service; + $this->log_service = $log_service; + } + + /** + * @return OpenIdDirectGenericErrorResponse + */ + public function handle() + { + $response = null; + try { + $assoc_type = $this->current_request->getAssocType(); + $session_type = $this->current_request->getSessionType(); + $association = $this->association_service->addAssociation + ( + AssociationFactory::getInstance()->buildSessionAssociation + ( + $assoc_type, + $this->server_configuration_service->getConfigValue("Session.Association.Lifetime") + ) + ); + + $response = new OpenIdUnencryptedAssociationSessionResponse + ( + $association->getHandle(), + $session_type, + $assoc_type, + $association->getLifetime(), + $association->getSecret() + ); + + } catch (InvalidDHParam $exDH) { + $response = new OpenIdDirectGenericErrorResponse($exDH->getMessage()); + $this->log_service->error($exDH); + } catch (InvalidArgumentException $exDH1) { + $response = new OpenIdDirectGenericErrorResponse($exDH1->getMessage()); + $this->log_service->error($exDH1); + + } catch (RuntimeException $exDH2) { + $response = new OpenIdDirectGenericErrorResponse($exDH2->getMessage()); + $this->log_service->error($exDH2); + } + return $response; + } +} \ No newline at end of file diff --git a/app/libs/OpenId/Helpers/AssocHandleGenerator.php b/app/libs/OpenId/Helpers/AssocHandleGenerator.php new file mode 100644 index 00000000..0bbe5f8f --- /dev/null +++ b/app/libs/OpenId/Helpers/AssocHandleGenerator.php @@ -0,0 +1,40 @@ + 255) + throw new InvalidArgumentException(sprintf("assoc handle len must be lower or equal to 255(%d)", $len)); + $new_assoc_handle = Rand::getString($len, self::PrintableNonWhitespaceCharacters, true); + return $new_assoc_handle; + } +} \ No newline at end of file diff --git a/app/libs/OpenId/Helpers/AssociationFactory.php b/app/libs/OpenId/Helpers/AssociationFactory.php new file mode 100644 index 00000000..9b8f7668 --- /dev/null +++ b/app/libs/OpenId/Helpers/AssociationFactory.php @@ -0,0 +1,83 @@ +buildAssociation(IAssociation::TypePrivate, OpenIdProtocol::SignatureAlgorithmHMAC_SHA256, $lifetime, $realm); + } + + /** + * @param $mac_function + * @param $lifetime + * @return IAssociation + */ + public function buildSessionAssociation($mac_function, $lifetime) + { + return $this->buildAssociation(IAssociation::TypeSession, $mac_function, $lifetime, null); + } + + /** + * @param string $type + * @param string $mac_function + * @param int $lifetime + * @param string $realm + * @return IAssociation + */ + private function buildAssociation($type, $mac_function, $lifetime, $realm) + { + $new_secret = OpenIdCryptoHelper::generateSecret($mac_function); + $new_handle = AssocHandleGenerator::generate(); + $expires_in = intval($lifetime); + $issued = gmdate("Y-m-d H:i:s", time()); + + return new Association($new_handle, $new_secret, $mac_function, $expires_in, $issued, $type, $realm); + } + + private function __clone() + { + } +} \ No newline at end of file diff --git a/app/libs/openid/helpers/OpenIdCryptoHelper.php b/app/libs/OpenId/Helpers/OpenIdCryptoHelper.php similarity index 80% rename from app/libs/openid/helpers/OpenIdCryptoHelper.php rename to app/libs/OpenId/Helpers/OpenIdCryptoHelper.php index 65c0fe37..07f36af3 100644 --- a/app/libs/openid/helpers/OpenIdCryptoHelper.php +++ b/app/libs/OpenId/Helpers/OpenIdCryptoHelper.php @@ -1,31 +1,50 @@ - "sha1", - OpenIdProtocol::AssociationSessionTypeDHSHA1 => "sha1", - OpenIdProtocol::SignatureAlgorithmHMAC_SHA256 => "sha256", + /** + * @var array + */ + private static $signature_algorithms = array + ( + OpenIdProtocol::SignatureAlgorithmHMAC_SHA1 => "sha1", + OpenIdProtocol::AssociationSessionTypeDHSHA1 => "sha1", + OpenIdProtocol::SignatureAlgorithmHMAC_SHA256 => "sha256", OpenIdProtocol::AssociationSessionTypeDHSHA256 => "sha256", ); + /** + * @param $number + * @param string $inputFormat + * @param string $outputFormat + * @return string + */ public static function convert($number, $inputFormat = DiffieHellman::FORMAT_NUMBER, $outputFormat = DiffieHellman::FORMAT_BINARY) { - $math = Math\BigInteger\BigInteger::factory(); + $math = BigInteger::factory(); if ($inputFormat == $outputFormat) { return $number; } @@ -56,6 +75,10 @@ final class OpenIdCryptoHelper } } + /** + * @param $func + * @return string + */ public static function generateSecret($func) { if ($func == OpenIdProtocol::SignatureAlgorithmHMAC_SHA1) { @@ -85,7 +108,7 @@ final class OpenIdCryptoHelper * @param $data * @param $secret * @return string - * @throws \openid\exceptions\OpenIdCryptoException + * @throws OpenIdCryptoException */ static public function computeHMAC($macFunc, $data, $secret) { @@ -135,7 +158,7 @@ final class OpenIdCryptoHelper * @param string $func digest algorithm * @param string $data data to sign * @return string RAW digital signature - * @throws \Exception + * @throws Exception */ static public function digest($func, $data) { diff --git a/app/libs/openid/helpers/OpenIdErrorMessages.php b/app/libs/OpenId/Helpers/OpenIdErrorMessages.php similarity index 96% rename from app/libs/openid/helpers/OpenIdErrorMessages.php rename to app/libs/OpenId/Helpers/OpenIdErrorMessages.php index aae9d2c3..18a2a750 100644 --- a/app/libs/openid/helpers/OpenIdErrorMessages.php +++ b/app/libs/OpenId/Helpers/OpenIdErrorMessages.php @@ -1,10 +1,7 @@ -getParam($key_php); $data .= $key . ':' . $val . "\n"; } diff --git a/app/libs/openid/helpers/OpenIdUriHelper.php b/app/libs/OpenId/Helpers/OpenIdUriHelper.php similarity index 94% rename from app/libs/openid/helpers/OpenIdUriHelper.php rename to app/libs/OpenId/Helpers/OpenIdUriHelper.php index 748eeb0c..1cfc95a0 100644 --- a/app/libs/openid/helpers/OpenIdUriHelper.php +++ b/app/libs/OpenId/Helpers/OpenIdUriHelper.php @@ -1,8 +1,17 @@ -handle = $handle; + $this->secret = $secret; + $this->mac_function = $mac_function; + $this->lifetime = $lifetime; + $this->issued = $issued; + $this->type = $type; + $this->realm = $realm; + } + + public function getMacFunction() + { + return $this->mac_function; + } + + public function setMacFunction($mac_function) + { + // TODO: Implement setMacFunction() method. + } + + public function getSecret() + { + return $this->secret; + } + + public function setSecret($secret) + { + // TODO: Implement setSecret() method. + } + + public function getLifetime() + { + return intval($this->lifetime); + } + + public function setLifetime($lifetime) + { + // TODO: Implement setLifetime() method. + } + + public function getIssued() + { + return $this->issued; + } + + public function setIssued($issued) + { + // TODO: Implement setIssued() method. + } + + public function getType() + { + return $this->type; + } + + public function setType($type) + { + // TODO: Implement setType() method. + } + + public function getRealm() + { + return $this->realm; + } + + public function setRealm($realm) + { + // TODO: Implement setRealm() method. + } + + public function IsExpired() + { + // TODO: Implement IsExpired() method. + } + + public function getRemainingLifetime() + { + // TODO: Implement getRemainingLifetime() method. + } + + public function getHandle() + { + return $this->handle; + } + +} \ No newline at end of file diff --git a/app/libs/OpenId/Models/IAssociation.php b/app/libs/OpenId/Models/IAssociation.php new file mode 100644 index 00000000..a4a877e6 --- /dev/null +++ b/app/libs/OpenId/Models/IAssociation.php @@ -0,0 +1,92 @@ +value; } + /** + * @return string + */ public function getTimestamp() { return $this->timestamp; } + /** + * @return string + */ public function getUniqueId() { - return $this->$unique_id; + return $this->unique_id; } /** @@ -100,6 +124,11 @@ final class OpenIdNonce extends Identifier return parent::setValue($value); } + /** + * @param string $value + * @return OpenIdNonce + * @throws InvalidNonce + */ static public function fromValue($value) { $nonce = new OpenIdNonce(255); diff --git a/app/libs/openid/OpenIdMessage.php b/app/libs/OpenId/OpenIdMessage.php similarity index 67% rename from app/libs/openid/OpenIdMessage.php rename to app/libs/OpenId/OpenIdMessage.php index aa4df14e..ae78ba42 100644 --- a/app/libs/openid/OpenIdMessage.php +++ b/app/libs/OpenId/OpenIdMessage.php @@ -1,16 +1,24 @@ -getParam(OpenIdProtocol::OpenIDProtocol_Mode); @@ -46,6 +57,9 @@ class OpenIdMessage extends HttpMessage return null; } + /** + * @return bool + */ public function isValid() { $ns = $this->getParam(OpenIdProtocol::OpenIDProtocol_NS); @@ -59,12 +73,17 @@ class OpenIdMessage extends HttpMessage return false; } - + /** + * @param string $mode + * @return $this + * @throws InvalidOpenIdMessageMode + */ protected function setMode($mode) { if (!OpenIdProtocol::isValidMode($mode)) throw new InvalidOpenIdMessageMode(sprintf(OpenIdErrorMessages::InvalidOpenIdMessageModeMessage, $mode)); - $this->container[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)] = $mode;; + $this->container[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)] = $mode; + return $this; } /** diff --git a/app/libs/openid/OpenIdProtocol.php b/app/libs/OpenId/OpenIdProtocol.php similarity index 87% rename from app/libs/openid/OpenIdProtocol.php rename to app/libs/OpenId/OpenIdProtocol.php index 51bfeef4..bf5510b3 100644 --- a/app/libs/openid/OpenIdProtocol.php +++ b/app/libs/OpenId/OpenIdProtocol.php @@ -1,28 +1,36 @@ -addExtension( + new OpenIdAuthenticationExtension( + $memento_service, + $server_configuration_service + ) + ); + } + } + + public function provides() + { + return [\OpenId\IOpenIdProtocol::class]; + } +} \ No newline at end of file diff --git a/app/libs/OpenId/Repositories/IOpenIdAssociationRepository.php b/app/libs/OpenId/Repositories/IOpenIdAssociationRepository.php new file mode 100644 index 00000000..17259ed1 --- /dev/null +++ b/app/libs/OpenId/Repositories/IOpenIdAssociationRepository.php @@ -0,0 +1,33 @@ +name = $name; $this->data = $data; } + /** + * @return array|null + */ public function getData() { return $this->data; } + /** + * @return string + */ public function getName() { return $this->name; diff --git a/app/libs/openid/requests/contexts/RequestContext.php b/app/libs/OpenId/Requests/Contexts/RequestContext.php similarity index 67% rename from app/libs/openid/requests/contexts/RequestContext.php rename to app/libs/OpenId/Requests/Contexts/RequestContext.php index 813a3641..1efe9b75 100644 --- a/app/libs/openid/requests/contexts/RequestContext.php +++ b/app/libs/OpenId/Requests/Contexts/RequestContext.php @@ -1,14 +1,17 @@ -trusted_data = array(); } + /** + * @param PartialView $partial_view + * @return $this + */ public function addPartialView(PartialView $partial_view) { $this->partial_views[$partial_view->getName()] = $partial_view; + return $this; } + /** + * @return array + */ public function getPartials() { return $this->partial_views; @@ -36,12 +47,21 @@ class RequestContext return $this->trusted_data; } + /** + * @return $this + */ public function cleanTrustedData(){ $this->trusted_data = array(); + return $this; } + /** + * @param $trusted_data + * @return $this + */ public function setTrustedData($trusted_data) { $this->trusted_data = array_merge($this->trusted_data, $trusted_data); + return $this; } } \ No newline at end of file diff --git a/app/libs/openid/requests/OpenIdAssociationSessionRequest.php b/app/libs/OpenId/Requests/OpenIdAssociationSessionRequest.php similarity index 56% rename from app/libs/openid/requests/OpenIdAssociationSessionRequest.php rename to app/libs/OpenId/Requests/OpenIdAssociationSessionRequest.php index 01f310c8..f75fd2c1 100644 --- a/app/libs/openid/requests/OpenIdAssociationSessionRequest.php +++ b/app/libs/OpenId/Requests/OpenIdAssociationSessionRequest.php @@ -1,25 +1,40 @@ -getMode(); @@ -29,8 +44,8 @@ class OpenIdAssociationSessionRequest extends OpenIdRequest { /** * @return bool - * @throws \openid\exceptions\InvalidSessionTypeException - * @throws \openid\exceptions\InvalidAssociationTypeException + * @throws InvalidSessionTypeException + * @throws InvalidAssociationTypeException */ public function isValid() { @@ -57,11 +72,17 @@ class OpenIdAssociationSessionRequest extends OpenIdRequest { return true; } + /** + * @return string + */ public function getAssocType() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_AssocType); } + /** + * @return string + */ public function getSessionType() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_SessionType); diff --git a/app/libs/openid/requests/OpenIdAuthenticationRequest.php b/app/libs/OpenId/Requests/OpenIdAuthenticationRequest.php similarity index 86% rename from app/libs/openid/requests/OpenIdAuthenticationRequest.php rename to app/libs/OpenId/Requests/OpenIdAuthenticationRequest.php index 1feef7d9..213148ed 100644 --- a/app/libs/openid/requests/OpenIdAuthenticationRequest.php +++ b/app/libs/OpenId/Requests/OpenIdAuthenticationRequest.php @@ -1,15 +1,23 @@ -op_endpoint_url = $op_endpoint_url; } + /** + * @param OpenIdMessage $message + * @return bool + */ public static function IsOpenIdCheckAuthenticationRequest(OpenIdMessage $message) { $mode = $message->getMode(); if ($mode == OpenIdProtocol::CheckAuthenticationMode) { return true; } - return false; } + /** + * @return bool + * @throws InvalidOpenIdMessageException + */ public function isValid() { - $mode = $this->getMode(); - $claimed_assoc = $this->getAssocHandle(); - $claimed_nonce = $this->getNonce(); - $claimed_sig = $this->getSig(); + $mode = $this->getMode(); + $claimed_assoc = $this->getAssocHandle(); + $claimed_nonce = $this->getNonce(); + $claimed_sig = $this->getSig(); $claimed_op_endpoint = $this->getOPEndpoint(); - $claimed_identity = $this->getClaimedId(); - $claimed_realm = $this->getRealm(); - $claimed_returnTo = $this->getReturnTo(); - $signed = $this->getSigned(); - - $valid_realm = OpenIdUriHelper::checkRealm($claimed_realm, $claimed_returnTo); + $claimed_identity = $this->getClaimedId(); + $claimed_realm = $this->getRealm(); + $claimed_returnTo = $this->getReturnTo(); + $signed = $this->getSigned(); + $valid_realm = OpenIdUriHelper::checkRealm($claimed_realm, $claimed_returnTo); $res = !is_null($mode) && !empty($mode) && $mode == OpenIdProtocol::CheckAuthenticationMode && !is_null($claimed_returnTo) && !empty($claimed_returnTo) && OpenIdUriHelper::checkReturnTo($claimed_returnTo) @@ -58,7 +76,9 @@ class OpenIdCheckAuthenticationRequest extends OpenIdAuthenticationRequest && !is_null($claimed_nonce) && !empty($claimed_nonce) && !is_null($claimed_op_endpoint) && !empty($claimed_op_endpoint) && $claimed_op_endpoint == $this->op_endpoint_url && !is_null($claimed_identity) && !empty($claimed_identity) && OpenIdUriHelper::isValidUrl($claimed_identity); - if (!$res) { + + if (!$res) + { $msg = sprintf("return_to is empty? %b.", empty($claimed_returnTo)) . PHP_EOL; $msg = $msg . sprintf("realm is empty? %b.", empty($claimed_realm)) . PHP_EOL; $msg = $msg . sprintf("claimed_id is empty? %b.", empty($claimed_id)) . PHP_EOL; @@ -71,26 +91,41 @@ class OpenIdCheckAuthenticationRequest extends OpenIdAuthenticationRequest return $res; } + /** + * @return string + */ public function getNonce() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_Nonce); } + /** + * @return string + */ public function getSig() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_Sig); } + /** + * @return string + */ public function getOPEndpoint() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_OpEndpoint); } + /** + * @return string + */ public function getSigned() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_Signed); } + /** + * @return string + */ public function getInvalidateHandle() { return $this->getParam(OpenIdProtocol::OpenIDProtocol_InvalidateHandle); diff --git a/app/libs/openid/requests/OpenIdDHAssociationSessionRequest.php b/app/libs/OpenId/Requests/OpenIdDHAssociationSessionRequest.php similarity index 76% rename from app/libs/openid/requests/OpenIdDHAssociationSessionRequest.php rename to app/libs/OpenId/Requests/OpenIdDHAssociationSessionRequest.php index 901ad32d..918069b3 100644 --- a/app/libs/openid/requests/OpenIdDHAssociationSessionRequest.php +++ b/app/libs/OpenId/Requests/OpenIdDHAssociationSessionRequest.php @@ -1,17 +1,27 @@ -message = $message; + } + + /** + * @return OpenIdMessage + */ + public function getMessage() + { + return $this->message; + } + + /** + * @return string + */ + public function getMode() + { + return $this->message->getMode(); + } + + /** + * @return bool + */ + abstract public function isValid(); + + /** + * @param OpenIDProtocol_ * $param + * @return string + */ + public function getParam($param) + { + return $this->message->getParam($param); + } + + /** + * @return string + */ + public function __toString() + { + return $this->message->__toString(); + } +} \ No newline at end of file diff --git a/app/libs/openid/responses/contexts/ResponseContext.php b/app/libs/OpenId/Responses/Contexts/ResponseContext.php similarity index 61% rename from app/libs/openid/responses/contexts/ResponseContext.php rename to app/libs/OpenId/Responses/Contexts/ResponseContext.php index 5c176fe7..a1e0c2e5 100644 --- a/app/libs/openid/responses/contexts/ResponseContext.php +++ b/app/libs/OpenId/Responses/Contexts/ResponseContext.php @@ -1,13 +1,13 @@ -sign_params = array(); } + /** + * @param string $param + * @return $this + */ public function addSignParam($param) { array_push($this->sign_params, $param); + return $this; } + /** + * @return array + */ public function getSignParams() { ksort($this->sign_params); diff --git a/app/libs/openid/responses/OpenIdAssociationSessionResponse.php b/app/libs/OpenId/Responses/OpenIdAssociationSessionResponse.php similarity index 58% rename from app/libs/openid/responses/OpenIdAssociationSessionResponse.php rename to app/libs/OpenId/Responses/OpenIdAssociationSessionResponse.php index 4caf0e22..831af86d 100644 --- a/app/libs/openid/responses/OpenIdAssociationSessionResponse.php +++ b/app/libs/OpenId/Responses/OpenIdAssociationSessionResponse.php @@ -1,28 +1,36 @@ -setMode(OpenIdProtocol::SetupNeededMode); + if (!is_null($return_url) && !empty($return_url)) { + $this->setReturnTo($return_url); + } + } +} \ No newline at end of file diff --git a/app/libs/OpenId/Responses/OpenIdIndirectGenericErrorResponse.php b/app/libs/OpenId/Responses/OpenIdIndirectGenericErrorResponse.php new file mode 100644 index 00000000..f423c01f --- /dev/null +++ b/app/libs/OpenId/Responses/OpenIdIndirectGenericErrorResponse.php @@ -0,0 +1,48 @@ +setHttpCode(self::HttpErrorResponse); + $this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Error)] = $error; + //opt values + if (!is_null($contact)) + $this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Contact)] = $contact; + if (!is_null($reference)) + $this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Reference)] = $reference; + + if (!is_null($request)) { + $return_to = $request->getParam(OpenIdProtocol::OpenIDProtocol_ReturnTo); + if (!is_null($return_to) && !empty($return_to) && OpenIdUriHelper::checkReturnTo($return_to)) + $this->setReturnTo($return_to); + } + } + +} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdIndirectResponse.php b/app/libs/OpenId/Responses/OpenIdIndirectResponse.php similarity index 64% rename from app/libs/openid/responses/OpenIdIndirectResponse.php rename to app/libs/OpenId/Responses/OpenIdIndirectResponse.php index cb1a5db8..bf2120c7 100644 --- a/app/libs/openid/responses/OpenIdIndirectResponse.php +++ b/app/libs/OpenId/Responses/OpenIdIndirectResponse.php @@ -1,18 +1,26 @@ -setMode(OpenIdProtocol::CancelMode); + if (!is_null($return_url) && !empty($return_url)) { + $this->setReturnTo($return_url); + } + } +} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdPositiveAssertionResponse.php b/app/libs/OpenId/Responses/OpenIdPositiveAssertionResponse.php similarity index 52% rename from app/libs/openid/responses/OpenIdPositiveAssertionResponse.php rename to app/libs/OpenId/Responses/OpenIdPositiveAssertionResponse.php index 98d9f2cc..fa126d88 100644 --- a/app/libs/openid/responses/OpenIdPositiveAssertionResponse.php +++ b/app/libs/OpenId/Responses/OpenIdPositiveAssertionResponse.php @@ -1,12 +1,33 @@ -container[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)] = $mode;; + } + +} \ No newline at end of file diff --git a/app/libs/OpenId/Responses/OpenIdUnencryptedAssociationSessionResponse.php b/app/libs/OpenId/Responses/OpenIdUnencryptedAssociationSessionResponse.php new file mode 100644 index 00000000..a980d64b --- /dev/null +++ b/app/libs/OpenId/Responses/OpenIdUnencryptedAssociationSessionResponse.php @@ -0,0 +1,34 @@ + becomes $_REQUEST["a_b"]. + */ + const PHP_REQUEST_VAR_SEPARATOR = "_"; /** * @var array */ diff --git a/app/libs/utils/http/HttpResponse.php b/app/libs/Utils/Http/HttpResponse.php similarity index 59% rename from app/libs/utils/http/HttpResponse.php rename to app/libs/Utils/Http/HttpResponse.php index 8e03ba10..509dc576 100644 --- a/app/libs/utils/http/HttpResponse.php +++ b/app/libs/Utils/Http/HttpResponse.php @@ -1,19 +1,26 @@ -http_code = $http_code; @@ -22,25 +29,45 @@ abstract class HttpResponse extends HttpMessage abstract public function getContent(); + /** + * @return int + */ public function getHttpCode() { return $this->http_code; } + /** + * @param int $http_code + * @return $this; + */ protected function setHttpCode($http_code) { $this->http_code = $http_code; + return $this; } + /** + * @return string + */ public function getContentType() { return $this->content_type; } + /** + * @return mixed + */ abstract public function getType(); + /** + * @param string $name + * @param mixed $value + * @return $this + */ public function addParam($name, $value) { $this[$name] = $value; + return $this; } } \ No newline at end of file diff --git a/app/libs/utils/http/HttpUtils.php b/app/libs/Utils/Http/HttpUtils.php similarity index 91% rename from app/libs/utils/http/HttpUtils.php rename to app/libs/Utils/Http/HttpUtils.php index cfb77c40..ce5acc7d 100644 --- a/app/libs/utils/http/HttpUtils.php +++ b/app/libs/Utils/Http/HttpUtils.php @@ -1,4 +1,4 @@ -getTimestamp(); + } +} \ No newline at end of file diff --git a/app/libs/Utils/MathUtils.php b/app/libs/Utils/MathUtils.php new file mode 100644 index 00000000..91ce0a6e --- /dev/null +++ b/app/libs/Utils/MathUtils.php @@ -0,0 +1,59 @@ += 0 && $p[$i] >= $p[$i + 1]; --$i) {} + + // if this doesn't occur, we've finished our permutations + // the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1) + if ($i == -1) + { + return false; + } + + // slide down the array looking for a bigger number than what we found before + for ($j = $size; $p[$j] <= $p[$i]; --$j) {} + + // swap them + $tmp = $p[$i]; + $p[$i] = $p[$j]; + $p[$j] = $tmp; + + // now reverse the elements in between by swapping the ends + for (++$i, $j = $size; $i < $j; ++$i, --$j) + { + $tmp = $p[$i]; + $p[$i] = $p[$j]; + $p[$j] = $tmp; + } + + return $p; + } +} \ No newline at end of file diff --git a/app/libs/Utils/Model/BaseModelEloquent.php b/app/libs/Utils/Model/BaseModelEloquent.php new file mode 100644 index 00000000..0329d934 --- /dev/null +++ b/app/libs/Utils/Model/BaseModelEloquent.php @@ -0,0 +1,208 @@ +whereRaw($filter['raw']); + else + $query = $query->where($filter['name'], $filter['op'], $filter['value']); + } + return $query; + } + + public function __construct($attributes = array()) + { + parent::__construct($attributes); + $this->class = new ReflectionClass(get_class($this)); + if ($this->useSti()) { + $this->setAttribute($this->stiClassField, $this->class->getShortName()); + } + } + + public function toArray() + { + $values = parent::toArray(); + + if (count($this->array_mappings)) { + $new_values = array(); + foreach ($this->array_mappings as $old_key => $new_key) { + $value = isset($values[$old_key])? $values[$old_key] : + ( + isset($values['pivot'])? ( + isset($values['pivot'][$old_key]) ? $values['pivot'][$old_key] : null + ): null + ); + + $new_key = preg_split('/:/',$new_key); + if(count($new_key) > 1) + { + //we have a formatter ... + switch(strtolower($new_key[1])) + { + case 'datetime_epoch': + { + if(!is_null($value)) { + $datetime = new \DateTime($value); + $value = $datetime->getTimestamp(); + } + } + break; + case 'json_string': + { + $value = JsonUtils::toJsonString($value); + } + break; + case 'json_boolean': + { + $value = JsonUtils::toJsonBoolean($value); + } + break; + case 'json_int': + { + $value = JsonUtils::toJsonInt($value); + } + break; + case 'json_float': + { + $value = JsonUtils::toJsonFloat($value); + } + break; + } + } + $new_values[$new_key[0]] = $value; + } + $values = $new_values; + } + + return $values; + } + + private function useSti() + { + return ($this->stiClassField && $this->stiBaseClass); + } + + private function useMti() + { + return $this->mtiClassType; + } + + public function newQuery($excludeDeleted = true) + { + $builder = parent::newQuery($excludeDeleted); + // If I am using STI, and I am not the base class, + // then filter on the class name. + if ($this->useMti()) { + $query = $builder->getQuery(); + $class = $this->class->getName(); + $parents = $this->get_class_lineage(new $class); + $base_table_set = false; + $current_class_name = null; + + if ($this->mtiClassType === 'concrete') { + $current_class_name = $this->class->getShortName(); + $query = $query->from($current_class_name); + $base_table_set = true; + } + + foreach ($parents as $parent) { + + if(!$this->isAllowedParent($parent)) + { + continue; + } + + $parent = new $parent; + if ($parent->mtiClassType === 'abstract') { + continue; + } + + $table_name = $parent->class->getShortName(); + + if ($base_table_set === true) { + $query->leftJoin($table_name, $current_class_name . '.ID', '=', $table_name . '.ID'); + } else { + $query = $query->from($table_name); + $base_table_set = true; + $current_class_name = $table_name; + } + } + + } else { + if ($this->useSti() && $this->stiBaseClass !== get_class($this)) { + $builder->where($this->stiClassField, "=", $this->class->getShortName()); + } + } + + return $builder; + } + + protected function isAllowedParent($parent_name) + { + $res = str_contains($parent_name, $this->class->getName()) || + str_contains($parent_name, Model::class) || + str_contains($parent_name, BaseModelEloquent::class); + return !$res; + } + + private function get_class_lineage($object) + { + $class_name = get_class($object); + $parents = array_values(class_parents($class_name)); + + return array_merge(array($class_name), $parents); + } + + public function newFromBuilder($attributes = array(), $connection = null) + { + if ($this->useSti() && $attributes->{$this->stiClassField}) { + $class = $this->class->getName(); + $instance = new $class; + $instance->exists = true; + $instance->setRawAttributes((array)$attributes, true); + + return $instance; + } else { + return parent::newFromBuilder($attributes, $connection); + } + } + + /** + * @return int + */ + public function getId() + { + return (int)$this->id; + } +} \ No newline at end of file diff --git a/app/libs/utils/model/IEntity.php b/app/libs/Utils/Model/IEntity.php similarity index 92% rename from app/libs/utils/model/IEntity.php rename to app/libs/Utils/Model/IEntity.php index bc98fedf..c7017750 100644 --- a/app/libs/utils/model/IEntity.php +++ b/app/libs/Utils/Model/IEntity.php @@ -1,4 +1,4 @@ -ClassName = $this->table; + } + + /** + * @return int + */ + public function getId() + { + return (int)$this->ID; + } +} \ No newline at end of file diff --git a/app/libs/utils/services/IAuthService.php b/app/libs/Utils/Services/IAuthService.php similarity index 74% rename from app/libs/utils/services/IAuthService.php rename to app/libs/Utils/Services/IAuthService.php index c332a3ea..e05ea6a9 100644 --- a/app/libs/utils/services/IAuthService.php +++ b/app/libs/Utils/Services/IAuthService.php @@ -1,13 +1,20 @@ -extensions = array(); - } - /** - * @return array - */ - public function getExtensions() - { - return $this->extensions; - } - - /** - * @param IAuthenticationExtension $extension - * @return bool - */ - public function addExtension(IAuthenticationExtension $extension) - { - array_push($this->extensions, $extension); - } -} \ No newline at end of file diff --git a/app/libs/auth/AuthenticationServiceProvider.php b/app/libs/auth/AuthenticationServiceProvider.php deleted file mode 100644 index 384f5058..00000000 --- a/app/libs/auth/AuthenticationServiceProvider.php +++ /dev/null @@ -1,31 +0,0 @@ -identifier = $identifier; - parent::__construct($message, 0, null); - } - - public function getIdentifier(){ - return $this->identifier; - } - -} \ No newline at end of file diff --git a/app/libs/auth/exceptions/AuthenticationLockedUserLoginAttempt.php b/app/libs/auth/exceptions/AuthenticationLockedUserLoginAttempt.php deleted file mode 100644 index 65368c59..00000000 --- a/app/libs/auth/exceptions/AuthenticationLockedUserLoginAttempt.php +++ /dev/null @@ -1,23 +0,0 @@ -identifier = $identifier; - parent::__construct($message, 0, null); - } - - public function getIdentifier(){ - return $this->identifier; - } - -} \ No newline at end of file diff --git a/app/libs/oauth2/.gitkeep b/app/libs/oauth2/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/libs/oauth2/OAuth2ServiceProvider.php b/app/libs/oauth2/OAuth2ServiceProvider.php deleted file mode 100644 index 4a988fe7..00000000 --- a/app/libs/oauth2/OAuth2ServiceProvider.php +++ /dev/null @@ -1,27 +0,0 @@ -protocol = $protocol; - } - - /** - * @param OAuth2Request $request - * @return mixed - * @throws \oauth2\exceptions\InvalidOAuth2Request - * @throws \oauth2\exceptions\InvalidClientException - * @throws \oauth2\exceptions\UriNotAllowedException - * @throws \oauth2\exceptions\ScopeNotAllowedException - * @throws \oauth2\exceptions\UnsupportedResponseTypeException - * @throws \oauth2\exceptions\UnAuthorizedClientException - * @throws \oauth2\exceptions\AccessDeniedException - * @throws \oauth2\exceptions\OAuth2GenericException - */ - public function handle(OAuth2Request $request) - { - foreach($this->protocol->getAvailableGrants() as $key => $grant){ - if($grant->canHandle($request)) - return $grant->handle($request); - } - throw new InvalidOAuth2Request; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/endpoints/IOAuth2Endpoint.php b/app/libs/oauth2/endpoints/IOAuth2Endpoint.php deleted file mode 100644 index e485a697..00000000 --- a/app/libs/oauth2/endpoints/IOAuth2Endpoint.php +++ /dev/null @@ -1,18 +0,0 @@ -protocol = $protocol; - $this->grant_type = new ValidateBearerTokenGrantType($client_service, $token_service, $auth_service, $log_service); - } - - - /** - * @param OAuth2Request $request - * @return mixed|\oauth2\responses\OAuth2AccessTokenValidationResponse|void - * @throws InvalidOAuth2Request - * @throws \oauth2\exceptions\BearerTokenDisclosureAttemptException - * @throws \oauth2\exceptions\ExpiredAccessTokenException - * @throws \oauth2\exceptions\InvalidApplicationType - * @throws \oauth2\exceptions\InvalidOAuth2Request - * @throws \oauth2\exceptions\LockedClientException - */ - public function handle(OAuth2Request $request) - { - if($this->grant_type->canHandle($request)) - { - return $this->grant_type->completeFlow($request); - } - throw new InvalidOAuth2Request; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/endpoints/TokenRevocationEndpoint.php b/app/libs/oauth2/endpoints/TokenRevocationEndpoint.php deleted file mode 100644 index b1ad29fb..00000000 --- a/app/libs/oauth2/endpoints/TokenRevocationEndpoint.php +++ /dev/null @@ -1,63 +0,0 @@ -protocol = $protocol; - $this->grant_type = new RevokeBearerTokenGrantType($client_service, $token_service, $log_service); - } - - /** - * @param OAuth2Request $request - * @return \oauth2\responses\OAuth2TokenRevocationResponse - * @throws InvalidOAuth2Request - * @throws \Exception - * @throws \oauth2\exceptions\BearerTokenDisclosureAttemptException - * @throws \oauth2\exceptions\ExpiredAccessTokenException - * @throws \oauth2\exceptions\UnAuthorizedClientException - */ - public function handle(OAuth2Request $request) - { - if($this->grant_type->canHandle($request)) - { - return $this->grant_type->completeFlow($request); - } - throw new InvalidOAuth2Request; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/exceptions/AbsentClientException.php b/app/libs/oauth2/exceptions/AbsentClientException.php deleted file mode 100644 index 693af292..00000000 --- a/app/libs/oauth2/exceptions/AbsentClientException.php +++ /dev/null @@ -1,16 +0,0 @@ -client_id = $client_id; - $message = "OAuth2 Client Base Exception : " . $message; - parent::__construct($message, 0, null); - } - - public function getClientId(){ - return $this->client_id; - } - -} \ No newline at end of file diff --git a/app/libs/oauth2/exceptions/OAuth2GenericException.php b/app/libs/oauth2/exceptions/OAuth2GenericException.php deleted file mode 100644 index ebec91ea..00000000 --- a/app/libs/oauth2/exceptions/OAuth2GenericException.php +++ /dev/null @@ -1,20 +0,0 @@ -http_code = $http_code; - $this->error = $error; - $this->error_description = $error_description; - $this->scope = $scope; - $message = "Resource Server Exception : " . sprintf('http code : %s - error : %s - error description: %s',$http_code,$error, $error_description); - parent::__construct($message, 0, null); - } - - public function getError() - { - return $this->error; - } - - public function getErrorDescription() - { - return $this->error_description; - } - - public function getScope() - { - return $this->scope; - } - - public function getHttpCode() - { - return $this->http_code; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/exceptions/ReplayAttackAuthCodeException.php b/app/libs/oauth2/exceptions/ReplayAttackAuthCodeException.php deleted file mode 100644 index 4f490c32..00000000 --- a/app/libs/oauth2/exceptions/ReplayAttackAuthCodeException.php +++ /dev/null @@ -1,22 +0,0 @@ -token = $token; - parent::__construct($description); - } - /** - * @var string - */ - private $token; - - /** - * @return string - */ - public function getToken() - { - return $this->token; - } - /** - * @return string - */ - public function getError() - { - return OAuth2Protocol::OAuth2Protocol_Error_InvalidGrant; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/exceptions/ReplayAttackRefreshTokenException.php b/app/libs/oauth2/exceptions/ReplayAttackRefreshTokenException.php deleted file mode 100644 index 5aa307ab..00000000 --- a/app/libs/oauth2/exceptions/ReplayAttackRefreshTokenException.php +++ /dev/null @@ -1,28 +0,0 @@ -getResponseType() - ); - - $is_hybrid_flow = OAuth2Protocol::responseTypeBelongsToFlow - ( - $response_type, - OAuth2Protocol::OAuth2Protocol_GrantType_Hybrid - ); - - if($is_hybrid_flow) - { - - if(in_array(OAuth2Protocol::OAuth2Protocol_ResponseType_Token, $response_type)) - { - - $access_token = $token_service->createAccessToken($auth_code, $request->getRedirectUri()); - } - - // check if should emmit id token - - if(in_array(OAuth2Protocol::OAuth2Protocol_ResponseType_IdToken, $response_type)) - { - - $id_token = $token_service->createIdToken - ( - $auth_code->getNonce(), - $auth_code->getClientId(), - $access_token - ); - } - - if(is_null($id_token) && is_null($access_token)) throw new InvalidOAuth2Request; - } - else - { - $access_token = $token_service->createAccessToken($auth_code, $request->getRedirectUri()); - - $id_token = $token_service->createIdToken - ( - $auth_code->getNonce(), - $auth_code->getClientId(), - $access_token - ); - } - - if(!is_null($access_token)) - $refresh_token = $access_token->getRefreshToken(); - - $response = new OAuth2IdTokenResponse - ( - is_null($access_token) ? null : $access_token->getValue(), - is_null($access_token) ? null : $access_token->getLifetime(), - is_null($id_token) ? null : $id_token->toCompactSerialization(), - is_null($refresh_token) ? null : $refresh_token->getValue() - ); - } - else // normal oauth2.0 code flow - { - $access_token = $token_service->createAccessToken($auth_code, $request->getRedirectUri()); - $refresh_token = $access_token->getRefreshToken(); - - $response = new OAuth2AccessTokenResponse - ( - $access_token->getValue(), - $access_token->getLifetime(), - is_null($refresh_token) ? null : $refresh_token->getValue() - ); - } - - return $response; - } - - /** - * @param AuthorizationCode $auth_code - * @return bool - */ - static public function authCodewasIssuedForOIDC(AuthorizationCode $auth_code) - { - return str_contains($auth_code->getScope(), OAuth2Protocol::OpenIdConnect_Scope); - } - -} \ No newline at end of file diff --git a/app/libs/oauth2/grant_types/.gitkeep b/app/libs/oauth2/grant_types/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/libs/oauth2/models/.gitkeep b/app/libs/oauth2/models/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/libs/oauth2/models/IApi.php b/app/libs/oauth2/models/IApi.php deleted file mode 100644 index e61ed543..00000000 --- a/app/libs/oauth2/models/IApi.php +++ /dev/null @@ -1,28 +0,0 @@ -getRedirectUri(); - - if (is_null($redirect_uri)) - { - $this->last_validation_error = 'redirect_uri not set'; - return false; - } - - return true; - } - - public function getRedirectUri() - { - return $this->getParam(OAuth2Protocol::OAuth2Protocol_RedirectUri); - } - - public function getClientId() - { - return $this->getParam(OAuth2Protocol::OAuth2Protocol_ClientId); - } - - public function getCode() - { - return $this->getParam(OAuth2Protocol::OAuth2Protocol_ResponseType_Code); - } -} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2AccessTokenRequestClientCredentials.php b/app/libs/oauth2/requests/OAuth2AccessTokenRequestClientCredentials.php deleted file mode 100644 index 854a331a..00000000 --- a/app/libs/oauth2/requests/OAuth2AccessTokenRequestClientCredentials.php +++ /dev/null @@ -1,32 +0,0 @@ -getParam(OAuth2Protocol::OAuth2Protocol_Scope); - } -} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2AccessTokenValidationRequest.php b/app/libs/oauth2/requests/OAuth2AccessTokenValidationRequest.php deleted file mode 100644 index a770a000..00000000 --- a/app/libs/oauth2/requests/OAuth2AccessTokenValidationRequest.php +++ /dev/null @@ -1,35 +0,0 @@ -last_validation_error = ''; - $token = $this->getToken(); - - if(is_null($token)) { - $this->last_validation_error = 'token not set'; - return false; - } - - return true; - } - - public function getToken(){ - return $this->getParam(OAuth2Protocol::OAuth2Protocol_Token); - } -} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2RefreshAccessTokenRequest.php b/app/libs/oauth2/requests/OAuth2RefreshAccessTokenRequest.php deleted file mode 100644 index 29de1843..00000000 --- a/app/libs/oauth2/requests/OAuth2RefreshAccessTokenRequest.php +++ /dev/null @@ -1,37 +0,0 @@ -getRefreshToken(); - - if(is_null($refresh_token)) { - $this->last_validation_error = 'refresh_token not set'; - return false; - } - - return true; - } - - public function getRefreshToken(){ - return $this->getParam(OAuth2Protocol::OAuth2Protocol_RefreshToken); - } - - public function getScope(){ - return $this->getParam(OAuth2Protocol::OAuth2Protocol_Scope); - } -} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2TokenRequest.php b/app/libs/oauth2/requests/OAuth2TokenRequest.php deleted file mode 100644 index 61927c85..00000000 --- a/app/libs/oauth2/requests/OAuth2TokenRequest.php +++ /dev/null @@ -1,39 +0,0 @@ -last_validation_error = ''; - - $grant_type = $this->getGrantType(); - - if(is_null($grant_type)) { - $this->last_validation_error = 'grant_type not set'; - return false; - } - - return true; - } - - public function getGrantType() - { - return $this->getParam(OAuth2Protocol::OAuth2Protocol_GrantType); - } -} \ No newline at end of file diff --git a/app/libs/oauth2/requests/OAuth2TokenRevocationRequest.php b/app/libs/oauth2/requests/OAuth2TokenRevocationRequest.php deleted file mode 100644 index d9762777..00000000 --- a/app/libs/oauth2/requests/OAuth2TokenRevocationRequest.php +++ /dev/null @@ -1,36 +0,0 @@ -last_validation_error = ''; - - $token = $this->getToken(); - - if(is_null($token)) { - $this->last_validation_error = 'token not set'; - return false; - } - - return true; - } - - public function getToken(){ - return $this->getParam(OAuth2Protocol::OAuth2Protocol_Token); - } - - public function getTokenHint(){ - return $this->getParam(OAuth2Protocol::OAuth2Protocol_TokenType_Hint); - } -} \ No newline at end of file diff --git a/app/libs/oauth2/resource_server/OAuth2ProtectedService.php b/app/libs/oauth2/resource_server/OAuth2ProtectedService.php deleted file mode 100644 index 2aa51300..00000000 --- a/app/libs/oauth2/resource_server/OAuth2ProtectedService.php +++ /dev/null @@ -1,34 +0,0 @@ -log_service = $log_service; - $this->resource_server_context = $resource_server_context; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/responses/.gitkeep b/app/libs/oauth2/responses/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/libs/oauth2/responses/OAuth2DirectResponse.php b/app/libs/oauth2/responses/OAuth2DirectResponse.php deleted file mode 100644 index 52db994f..00000000 --- a/app/libs/oauth2/responses/OAuth2DirectResponse.php +++ /dev/null @@ -1,29 +0,0 @@ -container); - return $json_encoded_format; - } - - public function getType() - { - return self::OAuth2DirectResponse; - } -} \ No newline at end of file diff --git a/app/libs/oauth2/responses/OAuth2Response.php b/app/libs/oauth2/responses/OAuth2Response.php deleted file mode 100644 index 6f39f26f..00000000 --- a/app/libs/oauth2/responses/OAuth2Response.php +++ /dev/null @@ -1,9 +0,0 @@ -addExtension( - new OpenIdAuthenticationExtension( - $memento_service, - $server_configuration_service - ) - ); - } - } - - public function provides() - { - return array('openid'); - } -} \ No newline at end of file diff --git a/app/libs/openid/exceptions/InvalidAssociation.php b/app/libs/openid/exceptions/InvalidAssociation.php deleted file mode 100644 index 62d18808..00000000 --- a/app/libs/openid/exceptions/InvalidAssociation.php +++ /dev/null @@ -1,18 +0,0 @@ -attributes = array(); - } - - /** - * @return bool - * @throws InvalidOpenIdMessageException - */ - public function isValid() - { - - //check identifier - if (isset($this->message[OpenIdAXExtension::paramNamespace('_')]) - && $this->message[OpenIdAXExtension::paramNamespace('_')] == OpenIdAXExtension::NamespaceUrl - ) { - - //check required fields - - if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, '_')]) - || $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Mode, '_')] != OpenIdAXExtension::FetchRequest - ) - throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidModeMessage); - - if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, '_')])) - throw new InvalidOpenIdMessageException(OpenIdErrorMessages::AXInvalidRequiredAttributesMessage); - - //get attributes - $attributes = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::RequiredAttributes, '_')]; - $attributes = explode(",", $attributes); - - foreach ($attributes as $attr) { - $attr = trim($attr); - if (!isset(OpenIdAXExtension::$available_properties[$attr])) - continue; - if (!isset($this->message[OpenIdAXExtension::param(OpenIdAXExtension::Type, '_') . "_" . $attr])) - throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $attr)); - $ns = $this->message[OpenIdAXExtension::param(OpenIdAXExtension::Type, "_") . "_" . $attr]; - if ($ns != OpenIdAXExtension::$available_properties[$attr]) - throw new InvalidOpenIdMessageException(sprintf(OpenIdErrorMessages::AXInvalidNamespaceMessage, $attr)); - array_push($this->attributes, $attr); - } - return true; - } - return false; - } - - public function getRequiredAttributes() - { - return $this->attributes; - } -} \ No newline at end of file diff --git a/app/libs/openid/extensions/implementations/OpenIdPAPEExtension.php b/app/libs/openid/extensions/implementations/OpenIdPAPEExtension.php deleted file mode 100644 index 8232b773..00000000 --- a/app/libs/openid/extensions/implementations/OpenIdPAPEExtension.php +++ /dev/null @@ -1,55 +0,0 @@ -current_request = $request; - $this->association_service = $association_service; - $this->server_configuration_service = $server_configuration_service; - $this->log_service = $log_service; - } - - /** - * @return null|OpenIdDirectGenericErrorResponse|OpenIdAssociationSessionResponse|OpenIdUnencryptedAssociationSessionResponse - */ - public function handle() - { - $response = null; - try { - $assoc_type = $this->current_request->getAssocType(); - $session_type = $this->current_request->getSessionType(); - $association = $this->association_service->addAssociation(AssociationFactory::getInstance()->buildSessionAssociation($assoc_type,$this->server_configuration_service->getConfigValue("Session.Association.Lifetime"))); - $response = new OpenIdUnencryptedAssociationSessionResponse($association->getHandle() , $session_type, $assoc_type, $association->getLifetime(), $association->getSecret()); - - } catch (InvalidDHParam $exDH) { - $response = new OpenIdDirectGenericErrorResponse($exDH->getMessage()); - $this->log_service->error($exDH); - } catch (InvalidArgumentException $exDH1) { - $response = new OpenIdDirectGenericErrorResponse($exDH1->getMessage()); - $this->log_service->error($exDH1); - - } catch (RuntimeException $exDH2) { - $response = new OpenIdDirectGenericErrorResponse($exDH2->getMessage()); - $this->log_service->error($exDH2); - } - return $response; - } -} \ No newline at end of file diff --git a/app/libs/openid/helpers/AssocHandleGenerator.php b/app/libs/openid/helpers/AssocHandleGenerator.php deleted file mode 100644 index 9e90cb67..00000000 --- a/app/libs/openid/helpers/AssocHandleGenerator.php +++ /dev/null @@ -1,30 +0,0 @@ - 255) throw new \InvalidArgumentException(sprintf("assoc handle len must be lower or equal to 255(%d)", $len)); - $new_assoc_handle = Rand::getString($len, self::PrintableNonWhitespaceCharacters, true); - return $new_assoc_handle; - } -} \ No newline at end of file diff --git a/app/libs/openid/helpers/AssociationFactory.php b/app/libs/openid/helpers/AssociationFactory.php deleted file mode 100644 index 53bd627e..00000000 --- a/app/libs/openid/helpers/AssociationFactory.php +++ /dev/null @@ -1,66 +0,0 @@ -buildAssociation(IAssociation::TypePrivate,OpenIdProtocol::SignatureAlgorithmHMAC_SHA256,$lifetime,$realm); - } - - /** - * @param $mac_function - * @param $lifetime - * @return IAssociation - */ - public function buildSessionAssociation($mac_function,$lifetime){ - return $this->buildAssociation(IAssociation::TypeSession,$mac_function,$lifetime,null); - } - - /** - * @param $type - * @param $mac_function - * @param $lifetime - * @param $realm - * @return IAssociation - */ - private function buildAssociation($type,$mac_function,$lifetime,$realm){ - $new_secret = OpenIdCryptoHelper::generateSecret($mac_function); - $new_handle = AssocHandleGenerator::generate(); - $expires_in = intval($lifetime); - $issued = gmdate("Y-m-d H:i:s", time()); - return new Association($new_handle, $new_secret, $mac_function, $expires_in, $issued, $type, $realm); - } - - private function __clone() - { - } -} \ No newline at end of file diff --git a/app/libs/openid/model/Association.php b/app/libs/openid/model/Association.php deleted file mode 100644 index 97d398dd..00000000 --- a/app/libs/openid/model/Association.php +++ /dev/null @@ -1,103 +0,0 @@ -handle = $handle; - $this->secret = $secret; - $this->mac_function = $mac_function; - $this->lifetime = $lifetime; - $this->issued = $issued; - $this->type = $type; - $this->realm = $realm; - } - - public function getMacFunction() - { - return $this->mac_function; - } - - public function setMacFunction($mac_function) - { - // TODO: Implement setMacFunction() method. - } - - public function getSecret() - { - return $this->secret; - } - - public function setSecret($secret) - { - // TODO: Implement setSecret() method. - } - - public function getLifetime() - { - return intval($this->lifetime); - } - - public function setLifetime($lifetime) - { - // TODO: Implement setLifetime() method. - } - - public function getIssued() - { - return $this->issued; - } - - public function setIssued($issued) - { - // TODO: Implement setIssued() method. - } - - public function getType() - { - return $this->type; - } - - public function setType($type) - { - // TODO: Implement setType() method. - } - - public function getRealm() - { - return $this->realm; - } - - public function setRealm($realm) - { - // TODO: Implement setRealm() method. - } - - public function IsExpired() - { - // TODO: Implement IsExpired() method. - } - - public function getRemainingLifetime() - { - // TODO: Implement getRemainingLifetime() method. - } - - public function getHandle() - { - return $this->handle; - } -} \ No newline at end of file diff --git a/app/libs/openid/model/IAssociation.php b/app/libs/openid/model/IAssociation.php deleted file mode 100644 index 91d19cf5..00000000 --- a/app/libs/openid/model/IAssociation.php +++ /dev/null @@ -1,44 +0,0 @@ -message = $message; - } - - public function getMessage() - { - return $this->message; - } - - public function getMode() - { - return $this->message->getMode(); - } - - abstract public function isValid(); - - /** - * @param OpenIDProtocol_ * $param - * @return string - */ - public function getParam($param) - { - return $this->message->getParam($param); - } - - /** - * @return string - */ - public function __toString() - { - return $this->message->__toString(); - } -} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdAssociationSessionUnsuccessfulResponse.php b/app/libs/openid/responses/OpenIdAssociationSessionUnsuccessfulResponse.php deleted file mode 100644 index 8ba5f20d..00000000 --- a/app/libs/openid/responses/OpenIdAssociationSessionUnsuccessfulResponse.php +++ /dev/null @@ -1,22 +0,0 @@ -setMode(OpenIdProtocol::SetupNeededMode); - if (!is_null($return_url) && !empty($return_url)) { - $this->setReturnTo($return_url); - } - } -} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdIndirectGenericErrorResponse.php b/app/libs/openid/responses/OpenIdIndirectGenericErrorResponse.php deleted file mode 100644 index d2e06bf7..00000000 --- a/app/libs/openid/responses/OpenIdIndirectGenericErrorResponse.php +++ /dev/null @@ -1,30 +0,0 @@ -setHttpCode(self::HttpErrorResponse); - $this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Error)] = $error; - //opt values - if (!is_null($contact)) - $this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Contact)] = $contact; - if (!is_null($reference)) - $this[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Reference)] = $reference; - - if (!is_null($request)) { - $return_to = $request->getParam(OpenIdProtocol::OpenIDProtocol_ReturnTo); - if (!is_null($return_to) && !empty($return_to) && OpenIdUriHelper::checkReturnTo($return_to)) - $this->setReturnTo($return_to); - } - } - -} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdNonImmediateNegativeAssertion.php b/app/libs/openid/responses/OpenIdNonImmediateNegativeAssertion.php deleted file mode 100644 index 55033792..00000000 --- a/app/libs/openid/responses/OpenIdNonImmediateNegativeAssertion.php +++ /dev/null @@ -1,25 +0,0 @@ -setMode(OpenIdProtocol::CancelMode); - if (!is_null($return_url) && !empty($return_url)) { - $this->setReturnTo($return_url); - } - } -} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdResponse.php b/app/libs/openid/responses/OpenIdResponse.php deleted file mode 100644 index a08638f5..00000000 --- a/app/libs/openid/responses/OpenIdResponse.php +++ /dev/null @@ -1,29 +0,0 @@ -container[OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Mode)] = $mode;; - } - -} \ No newline at end of file diff --git a/app/libs/openid/responses/OpenIdUnencryptedAssociationSessionResponse.php b/app/libs/openid/responses/OpenIdUnencryptedAssociationSessionResponse.php deleted file mode 100644 index 95b59c80..00000000 --- a/app/libs/openid/responses/OpenIdUnencryptedAssociationSessionResponse.php +++ /dev/null @@ -1,26 +0,0 @@ -where($filter['name'],$filter['op'], $filter['value']); - } - return $query; - } - - public function __construct($attributes = array()) - { - parent::__construct($attributes); - $this->class = new ReflectionClass(get_class($this)); - if ($this->useSti()) { - $this->setAttribute($this->stiClassField, $this->class->getName()); - } - } - - private function useSti() { - return ($this->stiClassField && $this->stiBaseClass); - } - - public function newQuery($excludeDeleted = true) - { - $builder = parent::newQuery($excludeDeleted); - // If I am using STI, and I am not the base class, - // then filter on the class name. - if ($this->useSti() && $this->stiBaseClass !== get_class($this)) { - $builder->where($this->stiClassField, "=", $this->class->getShortName()); - } - return $builder; - } - - public function newFromBuilder($attributes = array()) - { - if ($this->useSti() && property_exists($attributes, $this->stiClassField) ) { - $class = $this->class->getName(); - $instance = new $class; - $instance->exists = true; - $instance->setRawAttributes((array) $attributes, true); - return $instance; - } else { - return parent::newFromBuilder($attributes); - } - } -} \ No newline at end of file diff --git a/app/libs/utils/services/ICheckPointService.php b/app/libs/utils/services/ICheckPointService.php deleted file mode 100644 index 0c2fc02a..00000000 --- a/app/libs/utils/services/ICheckPointService.php +++ /dev/null @@ -1,31 +0,0 @@ -belongsTo('auth\User'); - } -} \ No newline at end of file diff --git a/app/models/Group.php b/app/models/Group.php deleted file mode 100644 index cf9d0e87..00000000 --- a/app/models/Group.php +++ /dev/null @@ -1,13 +0,0 @@ -belongsTo('auth\User'); - } -} \ No newline at end of file diff --git a/app/models/UserExceptionTrail.php b/app/models/UserExceptionTrail.php deleted file mode 100644 index 4746ed12..00000000 --- a/app/models/UserExceptionTrail.php +++ /dev/null @@ -1,6 +0,0 @@ -belongsTo('RefreshToken'); - } - - public function client(){ - return $this->belongsTo('Client'); - } - - public function user(){ - return $this->belongsTo('auth\User'); - } - - public function isVoid(){ - //check lifetime... - $created_at = $this->created_at; - $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); - $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); - return ($now > $created_at); - } - - public function getFriendlyScopes(){ - return $this->friendly_scopes; - } - - public function setFriendlyScopes($friendly_scopes){ - $this->friendly_scopes = $friendly_scopes; - } - - public function getRemainingLifetime() - { - //check is refresh token is stills alive... (ZERO is infinite lifetime) - if (intval($this->lifetime) == 0) return 0; - $created_at = new DateTime($this->created_at, new DateTimeZone("UTC")); - $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); - $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); - //check validity... - if ($now > $created_at) - return -1; - $seconds = abs($created_at->getTimestamp() - $now->getTimestamp());; - return $seconds; - } -} \ No newline at end of file diff --git a/app/models/oauth2/OAuth2TrailException.php b/app/models/oauth2/OAuth2TrailException.php deleted file mode 100644 index a816c8f4..00000000 --- a/app/models/oauth2/OAuth2TrailException.php +++ /dev/null @@ -1,6 +0,0 @@ -hasMany('AccessToken'); - } - - public function client(){ - return $this->belongsTo('Client'); - } - - public function user(){ - return $this->belongsTo('auth\User'); - } - - public function isVoid(){ - if(intval($this->lifetime) == 0) return false; - //check lifetime... - $created_at = $this->created_at; - $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); - $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); - return ($now > $created_at); - } - - - public function getRemainingLifetime() - { - //check is refresh token is stills alive... (ZERO is infinite lifetime) - if (intval($this->lifetime) == 0) return 0; - $created_at = new DateTime($this->created_at, new DateTimeZone("UTC")); - $created_at->add(new DateInterval('PT' . intval($this->lifetime) . 'S')); - $now = new DateTime(gmdate("Y-m-d H:i:s", time()), new DateTimeZone("UTC")); - //check validity... - if ($now > $created_at) - return -1; - $seconds = abs($created_at->getTimestamp() - $now->getTimestamp());; - return $seconds; - } - - public function getFriendlyScopes(){ - return $this->friendly_scopes; - } - - public function setFriendlyScopes($friendly_scopes){ - $this->friendly_scopes = $friendly_scopes; - } -} \ No newline at end of file diff --git a/app/models/oauth2/UserConsent.php b/app/models/oauth2/UserConsent.php deleted file mode 100644 index 1463f22d..00000000 --- a/app/models/oauth2/UserConsent.php +++ /dev/null @@ -1,35 +0,0 @@ -belongsTo('auth\User'); - } - - public function client() - { - return $this->belongsTo('Client'); - } - - public function getScope() - { - return $this->scope; - } - - public function getClient() - { - return $this->client()->first(); - } - - public function getUser() - { - return $this->user()->first(); - } -} \ No newline at end of file diff --git a/app/models/openid/IOpenIdAssociationRepository.php b/app/models/openid/IOpenIdAssociationRepository.php deleted file mode 100644 index 45aa0f87..00000000 --- a/app/models/openid/IOpenIdAssociationRepository.php +++ /dev/null @@ -1,15 +0,0 @@ -realm; - } - - public function getUITrustedData() - { - $data = $this->getData(); - $str = ''; - foreach ($data as $val) { - $str .= $val . ', '; - } - return trim($str, ', '); - } - - public function getData() - { - $res = is_null($this->data)?'[]':$this->data; - return json_decode($res); - } - - public function getUser() - { - return $this->user(); - } - - public function user() - { - return $this->belongsTo('auth\User'); - } - - public function getAuthorizationPolicy() - { - return $this->policy; - } - -} \ No newline at end of file diff --git a/app/models/openid/ServerExtension.php b/app/models/openid/ServerExtension.php deleted file mode 100644 index 2f27eaf5..00000000 --- a/app/models/openid/ServerExtension.php +++ /dev/null @@ -1,6 +0,0 @@ -member = $member; - $this->log_service = $log_service; - } - /** - * @param $id - * @return Member - */ - public function get($id) - { - return $this->member->find($id); - } - - /** - * @param $email - * @return Member - */ - public function getByEmail($email) - { - return $this->member->where('Email', '=', $email)->first(); - } -} \ No newline at end of file diff --git a/app/repositories/EloquentOpenIdAssociationRepository.php b/app/repositories/EloquentOpenIdAssociationRepository.php deleted file mode 100644 index 1ebd331a..00000000 --- a/app/repositories/EloquentOpenIdAssociationRepository.php +++ /dev/null @@ -1,50 +0,0 @@ -association = $association; - } - - public function add(OpenIdAssociation $a) - { - return $a->Save(); - } - - public function deleteById($id) - { - return $this->delete($this->get($id)); - } - - public function getByHandle($handle) - { - return $this->association->where('identifier', '=', $handle)->first(); - } - - public function delete(OpenIdAssociation $a) - { - if (!is_null($a)) { - return $a->delete(); - } - - return false; - } - - public function get($id) - { - return $this->association->find($id); - } -} \ No newline at end of file diff --git a/app/repositories/EloquentOpenIdTrustedSiteRepository.php b/app/repositories/EloquentOpenIdTrustedSiteRepository.php deleted file mode 100644 index 0d994896..00000000 --- a/app/repositories/EloquentOpenIdTrustedSiteRepository.php +++ /dev/null @@ -1,64 +0,0 @@ -openid_trusted_site = $openid_trusted_site; - } - /** - * @param OpenIdTrustedSite $s - * @return bool - */ - public function add(OpenIdTrustedSite $s) - { - return $s->Save(); - } - - public function deleteById($id) - { - return $this->delete($this->get($id)); - } - - public function delete(OpenIdTrustedSite $s) - { - if(!is_null($s)) - return $s->delete(); - return false; - } - - public function get($id) - { - return $this->openid_trusted_site->find($id); - } - - /** - * @param int $user_id - * @param array $sub_domains - * @param array $data - * @return array - */ - public function getMatchingOnesByUserId($user_id, array $sub_domains, array $data) - { - $query = $this->openid_trusted_site->where("user_id", "=", intval($user_id)); - //add or condition for all given sub-domains - if (count($sub_domains)) { - $query = $query->where(function ($query) use ($sub_domains) { - foreach ($sub_domains as $sub_domain) { - $query = $query->orWhere(function ($query_aux) use ($sub_domain) { - $query_aux->where('realm', '=', $sub_domain); - }); - } - }); - } - //add conditions for all possible pre approved data - foreach ($data as $value) { - $query = $query->where("data", "LIKE", '%"' . $value . '"%'); - } - return $query->get(); - } -} \ No newline at end of file diff --git a/app/repositories/RepositoriesProvider.php b/app/repositories/RepositoriesProvider.php deleted file mode 100644 index f4047349..00000000 --- a/app/repositories/RepositoriesProvider.php +++ /dev/null @@ -1,31 +0,0 @@ - "ssl"), function () { - - Route::get('/', "HomeController@index"); - Route::get('/discovery', "DiscoveryController@idp"); - /* - * If the Claimed Identifier was not previously discovered by the Relying Party - * (the "openid.identity" in the request was "http://specs.openid.net/auth/2.0/identifier_select" - * or a different Identifier, or if the OP is sending an unsolicited positive assertion), - * the Relying Party MUST perform discovery on the Claimed Identifier in - * the response to make sure that the OP is authorized to make assertions about the Claimed Identifier. - */ - Route::get("/{identifier}", "UserController@getIdentity"); - Route::get("/accounts/user/ud/{identifier}", - "DiscoveryController@user")->where(array('identifier' => '[\d\w\.\#]+')); - - //op endpoint url - Route::post('/accounts/openid2', 'OpenIdProviderController@endpoint'); - Route::get('/accounts/openid2', 'OpenIdProviderController@endpoint'); - - //user interaction - Route::get('/accounts/user/login', "UserController@getLogin"); - Route::post('/accounts/user/login', "UserController@postLogin"); - Route::get('/accounts/user/login/cancel', "UserController@cancelLogin"); -}); - -//oauth2 endpoints - -Route::group( array( 'before' => 'ssl|oauth2.enabled' ), function () { - Route::get('/.well-known/openid-configuration',"OAuth2ProviderController@discovery"); -}); - -Route::group(array('prefix' => 'oauth2', 'before' => 'ssl|oauth2.enabled'), function () { - Route::get('/check-session',"OAuth2ProviderController@checkSessionIFrame"); - Route::get('/end-session',"OAuth2ProviderController@endSession"); - Route::get('/end-session/cancel',"OAuth2ProviderController@cancelLogout"); - Route::post('/end-session',"OAuth2ProviderController@endSession"); - - //authorization endpoint - Route::any('/auth', "OAuth2ProviderController@authorize"); - // OIDC - // certificates - Route::get('/certs',"OAuth2ProviderController@certs"); - // discovery document - Route::get('/.well-known/openid-configuration',"OAuth2ProviderController@discovery"); - //token endpoint - Route::group(array('prefix' => 'token'), function () { - Route::post('/', "OAuth2ProviderController@token"); - Route::post('/revoke', "OAuth2ProviderController@revoke"); - Route::post('/introspection', "OAuth2ProviderController@introspection"); - }); -}); - -Route::group(array("before" => array("ssl", "auth")), function () { - Route::get('/accounts/user/consent', "UserController@getConsent"); - Route::post('/accounts/user/consent', "UserController@postConsent"); - Route::any("/accounts/user/logout", "UserController@logout"); - Route::any("/accounts/user/profile", "UserController@getProfile"); - Route::any("/accounts/user/profile/trusted_site/delete/{id}", "UserController@deleteTrustedSite"); - Route::post('/accounts/user/profile/update', 'UserController@postUserProfileOptions'); -}); - -Route::group(array('prefix' => 'admin', 'before' => 'ssl|auth'), function () { - //client admin UI - Route::get('clients/edit/{id}', array('before' => 'oauth2.enabled|user.can.edit.client.policy', 'uses' => 'AdminController@editRegisteredClient')); - Route::get('clients', array('before' => 'oauth2.enabled', 'uses' => 'AdminController@listOAuth2Clients')); - Route::get('/grants', array('before' => 'oauth2.enabled', 'uses' => 'AdminController@editIssuedGrants')); - //oauth2 server admin UI - Route::group(array('before' => 'oauth2.enabled|oauth2.server.admin'), function () { - Route::get('/api-scope-groups', 'AdminController@listApiScopeGroups'); - Route::get('/api-scope-groups/{id}', 'AdminController@editApiScopeGroup'); - Route::get('/resource-servers', 'AdminController@listResourceServers'); - Route::get('/resource-server/{id}', 'AdminController@editResourceServer'); - Route::get('/api/{id}', 'AdminController@editApi'); - Route::get('/scope/{id}', 'AdminController@editScope'); - Route::get('/endpoint/{id}', 'AdminController@editEndpoint'); - Route::get('/locked-clients', 'AdminController@listLockedClients'); - // server private keys - Route::get('/private-keys', 'AdminController@listServerPrivateKeys'); - }); - - Route::group(array('before' => 'openstackid.server.admin'), function () { - Route::get('/locked-users', 'AdminController@listLockedUsers'); - Route::get('/server-config', 'AdminController@listServerConfig'); - Route::post('/server-config', 'AdminController@saveServerConfig'); - Route::get('/banned-ips', 'AdminController@listBannedIPs'); - }); -}); - -//Admin Backend API -Route::group(array('prefix' => 'admin/api/v1', 'before' => 'ssl|auth'), function () { - Route::group(array('prefix' => 'users'), function () { - Route::delete('/{id}/locked',array('before' => 'openstackid.server.admin.json', 'uses' => 'UserApiController@unlock')); - Route::delete('/{id}/token/{value}', array('before' => 'is.current.user', 'uses' => 'UserApiController@revokeToken')); - Route::get('/fetch', array('before' => 'user.logged', 'uses' => "UserApiController@fetch")); - }); - - Route::group(array('prefix' => 'banned-ips', 'before' => 'openstackid.server.admin.json'), function () { - Route::get('/{id}', "ApiBannedIPController@get"); - Route::get('/', "ApiBannedIPController@getByPage"); - Route::delete('/{id?}', "ApiBannedIPController@delete"); - }); - - //client api - Route::group(array('prefix' => 'clients'), function () { - - // public keys - Route::post('/{id}/public_keys', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientPublicKeyApiController@create')); - Route::get('/{id}/public_keys', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientPublicKeyApiController@getByPage')); - Route::delete('/{id}/public_keys/{public_key_id}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientPublicKeyApiController@delete')); - Route::put('/{id}/public_keys/{public_key_id}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientPublicKeyApiController@update')); - - Route::post('/', array('before' => 'is.current.user', 'uses' => 'ClientApiController@create')); - Route::put('/', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@update')); - Route::get('/{id}', "ClientApiController@get"); - Route::get('/', array('before' => 'is.current.user', 'uses' => 'ClientApiController@getByPage')); - Route::delete('/{id}', array('before' => 'user.owns.client.policy', 'uses' => 'ClientApiController@delete')); - //allowed redirect uris endpoints - Route::get('/{id}/uris', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@getRegisteredUris')); - Route::post('/{id}/uris', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@addAllowedRedirectUri')); - Route::delete('/{id}/uris/{uri_id}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@deleteClientAllowedUri')); - - //allowed origin endpoints endpoints - Route::get('/{id}/origins', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@geAllowedOrigins')); - Route::post('/{id}/origins', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@addAllowedOrigin')); - Route::delete('/{id}/origins/{origin_id}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@deleteClientAllowedOrigin')); - Route::delete('/{id}/lock', array('before' => 'openstackid.server.admin.json', 'uses' => 'ClientApiController@unlock')); - Route::put('/{id}/secret', array('before' => 'user.owns.client.policy', 'uses' => 'ClientApiController@regenerateClientSecret')); - Route::put('/{id}/use-refresh-token', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@setRefreshTokenClient')); - Route::put('/{id}/rotate-refresh-token', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@setRotateRefreshTokenPolicy')); - Route::get('/{id}/access-token', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@getAccessTokens')); - Route::get('/{id}/refresh-token', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@getRefreshTokens')); - Route::delete('/{id}/token/{value}/{hint}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@revokeToken')); - Route::put('/{id}/scopes/{scope_id}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@addAllowedScope')); - Route::delete('/{id}/scopes/{scope_id}', array('before' => 'user.can.edit.client.policy', 'uses' => 'ClientApiController@removeAllowedScope')); - Route::put('/{id}/active', array('before' => 'user.owns.client.policy', 'uses' => 'ClientApiController@activate')); - Route::delete('/{id}/active', array('before' => 'user.owns.client.policy', 'uses' => 'ClientApiController@deactivate')); - - }); - - // resource servers - Route::group(array('prefix' => 'resource-servers', 'before' => 'oauth2.server.admin.json'), function () { - Route::get('/{id}', "ApiResourceServerController@get"); - Route::get('/', "ApiResourceServerController@getByPage"); - Route::post('/', "ApiResourceServerController@create"); - Route::delete('/{id}', "ApiResourceServerController@delete"); - Route::put('/', "ApiResourceServerController@update"); - Route::put('/{id}/client-secret', "ApiResourceServerController@regenerateClientSecret"); - Route::put('/{id}/active', "ApiResourceServerController@activate"); - Route::delete('/{id}/active', "ApiResourceServerController@deactivate"); - }); - - // api scope groups - Route::group(array('prefix' => 'api-scope-groups', 'before' => 'oauth2.server.admin.json'), function () { - Route::get('/{id}', "ApiScopeGroupController@get"); - Route::get('/', "ApiScopeGroupController@getByPage"); - Route::put('/', "ApiScopeGroupController@update"); - Route::post('/', "ApiScopeGroupController@create"); - Route::delete('/{id}', "ApiScopeGroupController@delete"); - Route::put('/{id}/active', "ApiScopeGroupController@activate"); - Route::delete('/{id}/active', "ApiScopeGroupController@deactivate"); - }); - - // apis - Route::group(array('prefix' => 'apis', 'before' => 'oauth2.server.admin.json'), function () { - Route::get('/{id}', "ApiController@get"); - Route::get('/', "ApiController@getByPage"); - Route::post('/', "ApiController@create"); - Route::delete('/{id}', "ApiController@delete"); - Route::put('/', "ApiController@update"); - Route::put('/{id}/active', "ApiController@activate"); - Route::delete('/{id}/active', "ApiController@deactivate"); - }); - - // scopes - Route::group(array('prefix' => 'scopes', 'before' => 'oauth2.server.admin.json'), function () { - Route::get('/{id}', "ApiScopeController@get"); - Route::get('/', "ApiScopeController@getByPage"); - Route::post('/', "ApiScopeController@create"); - Route::delete('/{id}', "ApiScopeController@delete"); - Route::put('/', "ApiScopeController@update"); - Route::put('/{id}/active', "ApiScopeController@activate"); - Route::delete('/{id}/active', "ApiScopeController@deactivate"); - }); - - // endpoints - Route::group(array('prefix' => 'endpoints', 'before' => 'oauth2.server.admin.json'), function () { - Route::get('/{id}', "ApiEndpointController@get"); - Route::get('/', "ApiEndpointController@getByPage"); - Route::post('/', "ApiEndpointController@create"); - Route::delete('/{id}', "ApiEndpointController@delete"); - Route::put('/', "ApiEndpointController@update"); - Route::put('/{id}/scope/{scope_id}', "ApiEndpointController@addRequiredScope"); - Route::delete('/{id}/scope/{scope_id}', "ApiEndpointController@removeRequiredScope"); - Route::put('/{id}/active', "ApiEndpointController@activate"); - Route::delete('/{id}/active', "ApiEndpointController@deactivate"); - }); - - // private keys - Route::group(array('prefix' => 'private-keys', 'before' => 'oauth2.server.admin.json'), function () { - Route::get('/', "ServerPrivateKeyApiController@getByPage"); - Route::post('/', "ServerPrivateKeyApiController@create"); - Route::delete('/{id}', "ServerPrivateKeyApiController@delete"); - Route::put('/{id}', "ServerPrivateKeyApiController@update"); - }); - -}); - -//OAuth2 Protected API -Route::group(array( - 'prefix' => 'api/v1', - 'before' => 'ssl|oauth2.enabled|oauth2.protected.endpoint', - 'after' => '' -), function () { - - Route::group(array('prefix' => 'users'), function () { - Route::get('/me', 'OAuth2UserApiController@me'); - Route::get('/info', 'OAuth2UserApiController@userInfo'); - Route::post('/info', 'OAuth2UserApiController@userInfo'); - }); -}); \ No newline at end of file diff --git a/app/services/IUserActionService.php b/app/services/IUserActionService.php deleted file mode 100644 index 59827f97..00000000 --- a/app/services/IUserActionService.php +++ /dev/null @@ -1,16 +0,0 @@ -setCounterMeasure($delay_counter_measure); - - $revoke_tokens_counter_measure = App::make("services\\RevokeAuthorizationCodeRelatedTokens"); - - $authorization_code_redeem_Policy = App::make("services\\AuthorizationCodeRedeemPolicy"); - $authorization_code_redeem_Policy->setCounterMeasure($revoke_tokens_counter_measure); - - $lock_user_counter_measure = App::make("services\\LockUserCounterMeasure"); - - $lock_user_security_policy = App::make("services\\LockUserSecurityPolicy"); - $lock_user_security_policy->setCounterMeasure($lock_user_counter_measure); - - $oauth2_lock_client_counter_measure = App::make("services\\OAuth2LockClientCounterMeasure"); - $oauth2_security_policy = App::make("services\\OAuth2SecurityPolicy"); - $oauth2_security_policy->setCounterMeasure($oauth2_lock_client_counter_measure); - - $checkpoint_service = new CheckPointService($blacklist_security_policy); - $checkpoint_service->addPolicy($lock_user_security_policy); - $checkpoint_service->addPolicy($authorization_code_redeem_Policy); - $checkpoint_service->addPolicy($oauth2_security_policy); - return $checkpoint_service; - }); - - } - - public function provides() - { - return array('application.services'); - } -} \ No newline at end of file diff --git a/app/services/UserActionService.php b/app/services/UserActionService.php deleted file mode 100644 index 36b59e24..00000000 --- a/app/services/UserActionService.php +++ /dev/null @@ -1,31 +0,0 @@ -from_ip = $ip; - $action->user_action = $user_action; - $action->realm = $realm; - $user = User::find($user->getId()); - if ($user) { - $user->actions()->save($action); - return true; - } - return false; - } catch (Exception $ex) { - Log::error($ex); - return false; - } - } -} \ No newline at end of file diff --git a/app/services/facades/ServerConfigurationService.php b/app/services/facades/ServerConfigurationService.php deleted file mode 100644 index d871e18e..00000000 --- a/app/services/facades/ServerConfigurationService.php +++ /dev/null @@ -1,16 +0,0 @@ -tx_service = $tx_service; - } - - /** - * @param $url - * @param $http_method - * @return IApiEndpoint - */ - public function getApiEndpointByUrlAndMethod($url, $http_method) - { - return ApiEndpoint::where('route','=',$url)->where('http_method','=',$http_method)->first(); - } - - /** - * @param $url - * @return IApiEndpoint - */ - public function getApiEndpointByUrl($url) - { - return ApiEndpoint::where('route','=',$url)->first(); - } - - - /** - * @param $id - * @return IApiEndpoint - */ - public function get($id){ - return ApiEndpoint::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 ApiEndpoint::Filter($filters)->paginate($page_size,$fields); - } - - /** - * Adds a new api endpoint to an existent api - * @param string $name - * @param string $description - * @param boolean $active - * @param boolean $allow_cors - * @param string $route - * @param string $http_method - * @param integer $api_id - * @param integer $rate_limit - * @return IApiEndpoint - */ - public function add($name, $description, $active,$allow_cors, $route, $http_method, $api_id, $rate_limit) - { - $instance = null; - - $this->tx_service->transaction(function () use ($name, $description, $active,$allow_cors, $route, $http_method, $api_id, $rate_limit, &$instance) { - - //check that does not exists an endpoint with same http method and same route - if(ApiEndpoint::where('http_method','=',$http_method)->where('route','=',$route)->where('api_id','=',$api_id)->count()>0) - throw new InvalidApiEndpoint(sprintf('there is already an endpoint api with route %s and http method %s',$route,$http_method)); - - $instance = new ApiEndpoint( - array( - 'name' => $name, - 'description' => $description, - 'active' => $active, - 'route' => $route, - 'http_method' => $http_method, - 'api_id' => $api_id, - 'allow_cors' => $allow_cors, - 'rate_limit' => (int)$rate_limit, - ) - ); - $instance->Save(); - }); - return $instance; - } - - /** - * @param int $id - * @param array $params - * @return bool - * @throws \oauth2\exceptions\InvalidApiEndpoint - */ - public function update($id, array $params){ - - $res = false; - $this_var = $this; - - $this->tx_service->transaction(function () use ($id,$params, &$res,&$this_var){ - $endpoint = ApiEndpoint::find($id); - if(is_null($endpoint)) - throw new InvalidApiEndpoint(sprintf('api endpoint id %s does not exists!',$id)); - - $allowed_update_params = array('name','description','active','route','http_method','allow_cors', 'rate_limit'); - foreach($allowed_update_params as $param){ - if(array_key_exists($param,$params)){ - $endpoint->{$param} = $params[$param]; - } - } - //check that does not exists an endpoint with same http method and same route - if(ApiEndpoint::where('http_method', '=' , $endpoint->http_method)->where('route', '=', $endpoint->route)->where('id', '<>' ,$endpoint->id)->where('api_id','=',$endpoint->api_id)->count()>0) - throw new InvalidApiEndpoint(sprintf('there is already an endpoint api with route %s and http method %s',$endpoint->route,$endpoint->http_method)); - $res = $this_var->save($endpoint); - }); - return $res; - } - - /** - * Adds a new required scope to a given api endpoint, - * given scope must belongs to owner api of the given endpoint - * @param int $api_endpoint_id - * @param int $scope_id - * @return boolean - * @throws \oauth2\exceptions\InvalidApiScope - * @throws \oauth2\exceptions\InvalidApiEndpoint - */ - public function addRequiredScope($api_endpoint_id, $scope_id) - { - $res = false; - - $this->tx_service->transaction(function () use($api_endpoint_id, $scope_id,&$res){ - - $api_endpoint = ApiEndpoint::find($api_endpoint_id); - - if(is_null($api_endpoint)) - throw new InvalidApiEndpoint(sprintf("api endpoint id %s does not exists!.",$api_endpoint_id)); - - $scope = ApiScope::find($scope_id); - - if(is_null($scope)) - throw new InvalidApiScope(sprintf("api scope id %s does not exists!.",$scope_id)); - - if($scope->api_id!==$api_endpoint->api_id) - throw new InvalidApiScope(sprintf("api scope id %s does not belong to api id %s !.",$scope_id,$api_endpoint->api_id)); - - $res = $api_endpoint->scopes()->where('id','=',$scope_id)->count(); - - if($res>0) - throw new InvalidApiScope(sprintf("api scope id %s already belongs to endpoint id %s!.",$scope_id,$api_endpoint->id)); - - $api_endpoint->scopes()->attach($scope_id); - - $res = true; - }); - return $res; - } - - - /** - * Removes a required scope to a given api endpoint, - * given scope must belongs to owner api of the given endpoint - * @param int $api_endpoint_id - * @param int $scope_id - * @return boolean - * @throws \oauth2\exceptions\InvalidApiScope - * @throws \oauth2\exceptions\InvalidApiEndpoint - */ - public function removeRequiredScope($api_endpoint_id, $scope_id) - { - - $res = false; - - $this->tx_service->transaction(function () use($api_endpoint_id, $scope_id,&$res){ - - $api_endpoint = ApiEndpoint::find($api_endpoint_id); - - if(is_null($api_endpoint)) - throw new InvalidApiEndpoint(sprintf("api endpoint id %s does not exists!.",$api_endpoint_id)); - - $scope = ApiScope::find($scope_id); - - if(is_null($scope)) - throw new InvalidApiScope(sprintf("api scope id %s does not exists!.",$scope_id)); - - if($scope->api_id !== $api_endpoint->api_id) - throw new InvalidApiScope(sprintf("api scope id %s does not belongs to api id %s!.",$scope_id,$api_endpoint->api_id)); - - $res = $api_endpoint->scopes()->where('id','=',$scope_id)->count(); - - if($res==0) - throw new InvalidApiScope(sprintf("api scope id %s does not belongs to endpoint id %s !.",$scope_id,$api_endpoint->id)); - - $api_endpoint->scopes()->detach($scope_id); - - $res = true; - }); - return $res; - } - - /** - * deletes a given api endpoint - * @param int $id - * @return boolean - */ - public function delete($id) - { - $res = false; - $this->tx_service->transaction(function () use ($id,&$res) { - $endpoint = ApiEndpoint::find($id); - if(!is_null($endpoint)){ - $res = $endpoint->delete(); - } - }); - return $res; - } - - public function save(IApiEndpoint $api_endpoint) - { - if(!$api_endpoint->exists() || count($api_endpoint->getDirty())>0){ - return $api_endpoint->Save(); - } - return true; - } - - /** - * @param int $id - * @param boolean $active - * @return boolean - */ - public function setStatus($id, $active) - { - $endpoint = ApiEndpoint::find($id); - if(is_null($endpoint)) return false; - return $endpoint->update(array('active'=>$active)); - } -} \ No newline at end of file diff --git a/app/services/oauth2/ApiService.php b/app/services/oauth2/ApiService.php deleted file mode 100644 index 1277c109..00000000 --- a/app/services/oauth2/ApiService.php +++ /dev/null @@ -1,164 +0,0 @@ -tx_service = $tx_service; - } - - /** - * @param $api_id - * @return IApi - */ - public function get($api_id) - { - return Api::find($api_id); - } - - /** - * @param $api_name - * @return IApi - */ - public function getByName($api_name) - { - return Api::where('name','=',$api_name)->first(); - } - - /** - * @param $id - * @return bool - */ - public function delete($id) - { - $res = false; - $this->tx_service->transaction(function () use ($id,&$res) { - $api = Api::find($id); - if(!is_null($api)){ - $res = $api->delete(); - } - }); - return $res; - } - - /** - * @param $name - * @param $description - * @param $active - * @param $resource_server_id - * @return null|IApi - */ - public function add($name, $description, $active, $resource_server_id) - { - $instance = null; - if(is_string($active)){ - $active = strtoupper($active) == 'TRUE'?true:false; - } - - $this->tx_service->transaction(function () use ($name, $description, $active, $resource_server_id, &$instance) { - - $count = Api::where('name','=',$name)->where('resource_server_id','=',$resource_server_id)->count(); - if($count>0) - throw new InvalidApi(sprintf('api name %s already exists!',$name)); - - $instance = new Api( - array( - 'name' => $name, - 'description' => $description, - 'active' => $active, - 'resource_server_id' => $resource_server_id - ) - ); - - $instance->Save(); - }); - return $instance; - } - - /** - * @param $id - * @param array $params - * @return bool - */ - public function update($id, array $params){ - - $res = false; - $this_var = $this; - - $this->tx_service->transaction(function () use ($id,$params, &$res, &$this_var) { - - $api = Api::find($id); - if(is_null($api)) - throw new InvalidApi(sprintf('api id %s does not exists!',$id)); - - $allowed_update_params = array('name','description','active'); - foreach($allowed_update_params as $param){ - if(array_key_exists($param,$params)){ - - if($param=='name'){ - if(Api::where('name','=',$params[$param])->where('id','<>',$id)->where('resource_server_id','=',$api->resource_server_id)->count()>0) - throw new InvalidApi(sprintf('api name %s already exists!',$params[$param])); - } - - $api->{$param} = $params[$param]; - } - } - $res = $this_var->save($api); - }); - return $res; - } - - /** - * @param IApi $api - * @return bool|void - */ - public function save(IApi $api) - { - if(!$api->exists() || count($api->getDirty())>0){ - return $api->Save(); - } - return true; - } - - /** - * @param $id - * @param $active - * @return bool - * @throws \oauth2\exceptions\InvalidApi - */ - public function setStatus($id, $active) - { - $api = Api::find($id); - if(is_null($api)) - throw new InvalidApi(sprintf("api id %s does not exists!",$id)); - return $api->update(array('active'=>$active)); - } - - /** - * @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 Api::Filter($filters)->paginate($page_size,$fields); - } -} \ No newline at end of file diff --git a/app/services/oauth2/CORS/CORSMiddleware.php b/app/services/oauth2/CORS/CORSMiddleware.php deleted file mode 100644 index 5b6aac5a..00000000 --- a/app/services/oauth2/CORS/CORSMiddleware.php +++ /dev/null @@ -1,314 +0,0 @@ -endpoint_service = $endpoint_service; - $this->cache_service = $cache_service; - $this->client_service = $client_service; - - $this->allowed_headers = Config::get('cors.AllowedHeaders', self::DefaultAllowedHeaders); - $this->allowed_methods = Config::get('cors.AllowedMethods', self::DefaultAllowedMethods); - } - - /** - * User agents can discover via a preflight request whether a cross-origin resource is prepared to - * accept requests, using a non-simple method, from a given origin. - * @param Request $request - * @param IApiEndpoint $endpoint - * @return Response - */ - private function makePreflightResponse(Request $request, IApiEndpoint $endpoint) - { - - $response = new Response(); - - $allow_credentials = Config::get('cors.AllowCredentials', ''); - - if (!empty($allow_credentials)) { - // The Access-Control-Allow-Credentials header indicates whether the response to request - // can be exposed when the omit credentials flag is unset. When part of the response to a preflight request - // it indicates that the actual request can include user credentials. - $response->headers->set('Access-Control-Allow-Credentials', $allow_credentials); - } - - if (Config::get('cors.UsePreflightCaching', false)) { - // The Access-Control-Max-Age header indicates how long the response can be cached, so that for - // subsequent requests, within the specified time, no preflight request has to be made. - $response->headers->set('Access-Control-Max-Age', Config::get('cors.MaxAge', 32000)); - } - // The Access-Control-Allow-Headers header indicates, as part of the response to a preflight request, - // which header field names can be used during the actual request - $response->headers->set('Access-Control-Allow-Headers', $this->allowed_headers); - - if (!$this->checkOrigin($request)) { - $response->headers->set('Access-Control-Allow-Origin', 'null'); - $response->setStatusCode(403); - - return $response; - } - - $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin')); - - // The Access-Control-Request-Method header indicates which method will be used in the actual - // request as part of the preflight request - // check request method - - if ($request->headers->get('Access-Control-Request-Method') != $endpoint->getHttpMethod()) { - $response->setStatusCode(405); - - return $response; - } - //The Access-Control-Allow-Methods header indicates, as part of the response to a preflight request, - // which methods can be used during the actual request. - $response->headers->set('Access-Control-Allow-Methods', $this->allowed_methods); - - // The Access-Control-Request-Headers header indicates which headers will be used in the actual request - // as part of the preflight request. - - $headers = $request->headers->get('Access-Control-Request-Headers'); - - if ($headers) { - $headers = trim(strtolower($headers)); - $allow_headers = explode(', ', $this->allowed_headers); - foreach (preg_split('{, *}', $headers) as $header) { - //if they are simple headers then skip them - if (in_array($header, self::$simple_headers, true)) { - continue; - } - //check is the requested header is on the list of allowed headers - if (!in_array($header, $allow_headers, true)) { - $response->setStatusCode(400); - $response->setContent('Unauthorized header ' . $header); - break; - } - } - } - //OK - No Content - $response->setStatusCode(204); - - return $response; - } - - private function checkOrigin(Request $request) - { - // check origin - $origin = $request->headers->get('Origin'); - if ($this->cache_service->getSingleValue($origin)) { - return true; - } - if ($client = $this->client_service->getByOrigin($origin)) - { - $this->cache_service->addSingleValue($origin, $origin); - return true; - } - Log::warning(sprintf('CORS: origin %s not allowed!', $origin)); - - return false; - } - - public function verifyRequest($request) - { - try { - /** - * The presence of the Origin header does not necessarily mean that the request is a cross-origin request. - * While all cross-origin requests will contain an Origin header, - * some same-origin requests might have one as well. For example, Firefox doesn't include an - * Origin header on same-origin requests. But Chrome and Safari include an Origin header on - * same-origin POST/PUT/DELETE requests (same-origin GET requests will not have an Origin header). - */ - - if (!$request->headers->has('Origin')) { - return; - } - //https://www.owasp.org/index.php/CORS_OriginHeaderScrutiny - $origin = $request->headers->get('Origin', null, false); - $host = $request->headers->get('Host', null, false); - if (is_array($origin) && count($origin) > 1) { - // If we reach this point it means that we have multiple instance of the "Origin" header - $response = new Response(); - $response->setStatusCode(403); - - return $response; - } - //now get the first one - $origin = $request->headers->get('Origin'); - $server_name = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; - $origin_host = @parse_url($origin, PHP_URL_HOST); - - //Have only one and non empty instance of the host header, - if (is_array($host) && count($host) > 1) { - // If we reach this point it means that we have multiple instance of the "Host" header - $response = new Response(); - $response->setStatusCode(403); - - return; - } - //now get the first one - $host = $request->headers->get('Host'); - - if (is_null($host) || $server_name != $host || is_null($origin_host) || $origin_host == $server_name) { - return; - } - - $method = $request->getMethod(); - $preflight = false; - - //preflight checks - if ($method == 'OPTIONS') { - $request_method = $request->headers->get('Access-Control-Request-Method'); - if (!is_null($request_method)) { - // sets the original method on request in order to be able to find the - // correct route - $request->setMethod($request_method); - $preflight = true; - } - } - - //gets routes from container and try to find the route - $router = App::make('router'); - $routes = $router->getRoutes(); - $route = $routes->match($request); - $url = $route->getPath(); - - if (strpos($url, '/') != 0) { - $url = '/' . $url; - } - - $endpoint = $this->endpoint_service->getApiEndpointByUrl($url); - //check if api endpoint exists or not, if active and if supports cors - if (is_null($endpoint) || !$endpoint->isActive() || !$endpoint->supportCORS()) { - - if (is_null($endpoint)) { - Log::warning(sprintf("does not exists an endpoint for url %s.", $url)); - } else { - if (!$endpoint->isActive()) { - Log::warning(sprintf("endpoint %s is not active.", $url)); - } else { - if (!$endpoint->supportCORS()) { - Log::warning(sprintf("endpoint %s does not support CORS.", $url)); - } - } - } - - return; - } - - //perform preflight checks - if ($preflight) { - return $this->makePreflightResponse($request, $endpoint); - } - //Actual Request - if (!$this->checkOrigin($request)) { - return new Response('', 403, array('Access-Control-Allow-Origin' => 'null')); - } - - $this->actual_request = true; - - // Save response headers - $this->headers['Access-Control-Allow-Origin'] = $request->headers->get('Origin'); - $allow_credentials = Config::get('cors.AllowCredentials', ''); - if (!empty($allow_credentials)) { - // The Access-Control-Allow-Credentials header indicates whether the response to request - // can be exposed when the omit credentials flag is unset. When part of the response to a preflight request - // it indicates that the actual request can include user credentials. - $this->headers['Access-Control-Allow-Credentials'] = $allow_credentials; - } - - /** - * During a CORS request, the getResponseHeader() method can only access simple response headers. - * Simple response headers are defined as follows: - ** Cache-Control - ** Content-Language - ** Content-Type - ** Expires - ** Last-Modified - ** Pragma - * If you want clients to be able to access other headers, - * you have to use the Access-Control-Expose-Headers header. - * The value of this header is a comma-delimited list of response headers you want to expose - * to the client. - */ - $exposed_headers = Config::get('cors.ExposedHeaders', ''); - if (!empty($exposed_headers)) { - $this->headers['Access-Control-Expose-Headers'] = $exposed_headers; - } - - } catch (Exception $ex) { - Log::error($ex); - } - } - - public function modifyResponse($request, $response) - { - if (!$this->actual_request) { - return $response; - } - // add CORS response headers - Log::info('CORS: Adding CORS HEADERS.'); - $response->headers->add($this->headers); - - return $response; - } - -} \ No newline at end of file diff --git a/app/services/oauth2/CORS/CORSProvider.php b/app/services/oauth2/CORS/CORSProvider.php deleted file mode 100644 index 848c2575..00000000 --- a/app/services/oauth2/CORS/CORSProvider.php +++ /dev/null @@ -1,31 +0,0 @@ -getJWKSUri(); - if(empty($jwk_set_uri)) return null; - - $client = new HttpClient; - $client->setSslVerification(false); - $request = $client->get($jwk_set_uri); - $response = $request->send(); - if($response->getStatusCode() !== 200) return null; - $content_type = $response->getHeader('content-type'); - if(is_null($content_type)) return null; - if(!$content_type->hasValue(HttpContentType::Json)) return null; - return JWKSet::fromJson($response->getBody()); - } -} \ No newline at end of file diff --git a/app/services/oauth2/OAuth2ServiceProvider.php b/app/services/oauth2/OAuth2ServiceProvider.php deleted file mode 100644 index 98d3406d..00000000 --- a/app/services/oauth2/OAuth2ServiceProvider.php +++ /dev/null @@ -1,85 +0,0 @@ -client_service = $client_service; - $this->tx_service = $tx_service; - } - - /** - * @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 ResourceServer::Filter($filters)->paginate($page_size, $fields); - } - - /** - * @param $id - * @param array $params - * @return bool - * @throws \oauth2\exceptions\InvalidResourceServer - */ - public function update($id, array $params) - { - - $res = false; - $this_var = $this; - - $this->tx_service->transaction(function () use ($id, $params, &$res, &$this_var) { - - $resource_server = ResourceServer::find($id); - - if (is_null($resource_server)) { - throw new InvalidResourceServer(sprintf('resource server id %s does not exists!', $id)); - } - $allowed_update_params = array('host', 'ips', 'active', 'friendly_name'); - - foreach ($allowed_update_params as $param) { - if (array_key_exists($param, $params)) { - - if ($param == 'host') { - if (ResourceServer::where('host', '=', $params[$param])->where('id', '<>', $id)->count() > 0) { - throw new InvalidResourceServer(sprintf('there is already another resource server with that hostname (%s).', - $params[$param])); - } - } - - if ($param == 'friendly_name') { - if (ResourceServer::where('friendly_name', '=', $params[$param])->where('id', '<>', - $id)->count() > 0 - ) { - throw new InvalidResourceServer(sprintf('there is already another resource server with that friendly name (%s).', - $params[$param])); - } - } - - $resource_server->{$param} = $params[$param]; - } - } - $res = $this_var->save($resource_server); - }); - - return $res; - } - - /** - * @param IResourceServer $resource_server - * @return bool - */ - public function save(IResourceServer $resource_server) - { - if (!$resource_server->exists() || count($resource_server->getDirty()) > 0) { - return $resource_server->Save(); - } - - return true; - } - - /** - * sets resource server status (active/deactivated) - * @param $id id of resource server - * @param bool $active status (active/non active) - * @return bool - */ - public function setStatus($id, $active) - { - return ResourceServer::find($id)->update(array('active' => $active)); - } - - /** - * deletes a resource server - * @param id $id - * @return bool - */ - public function delete($id) - { - $res = false; - $client_service = $this->client_service; - - $this->tx_service->transaction(function () use ($id, &$res, &$client_service) { - - $resource_server = ResourceServer::find($id); - - if (!is_null($resource_server)) { - $client = $resource_server->client()->first(); - if (!is_null($client)) { - $client_service->deleteClientByIdentifier($client->id); - } - $resource_server->delete(); - $res = true; - } - }); - - return $res; - } - - /** - * get a resource server by id - * @param $id id of resource server - * @return IResourceServer - */ - public function get($id) - { - return ResourceServer::find($id); - } - - /** Creates a new resource server instance - * @param $host - * @param $ips - * @param $friendly_name - * @param bool $active - * @return IResourceServer - */ - public function add($host, $ips, $friendly_name, $active) - { - - $client_service = $this->client_service; - - if (is_string($active)) - { - $active = strtoupper($active) == 'TRUE' ? true : false; - } - - return $this->tx_service->transaction(function () use ( - $host, - $ips, - $friendly_name, - $active, - $client_service - ) { - - if (ResourceServer::where('host', '=', $host)->count() > 0) { - throw new InvalidResourceServer(sprintf('there is already another resource server with that hostname (%s).', - $host)); - } - - if (ResourceServer::where('ips','like', '%'.$ips.'%')->count() > 0) - { - throw new InvalidResourceServer(sprintf('there is already another resource server with that ip (%s).', - $ips)); - } - - if (ResourceServer::where('friendly_name', '=', $friendly_name)->count() > 0) { - throw new InvalidResourceServer(sprintf('there is already another resource server with that friendly name (%s).', - $friendly_name)); - } - - $instance = new ResourceServer - ( - array - ( - 'host' => $host, - 'ips' => $ips, - 'active' => $active, - 'friendly_name' => $friendly_name - ) - ); - - $instance->Save(); - - // creates a new client for this brand new resource server - $new_client = $client_service->addClient - ( - IClient::ApplicationType_Service, - null, - $host . '.confidential.application', - $friendly_name . ' confidential oauth2 application', '' - ); - - $new_client->resource_server()->associate($instance); - // does not expires ... - $new_client->client_secret_expires_at = null; - $new_client->Save(); - return $instance; - }); - - } - - /** - * @param $id - * @return bool - */ - public function regenerateClientSecret($id) - { - $res = null; - $client_service = $this->client_service; - - $this->tx_service->transaction(function () use ($id, &$res, &$client_service) { - - $resource_server = ResourceServer::find($id); - - if (!is_null($resource_server)) { - $client = $resource_server->client()->first(); - if (!is_null($client)) { - $res = $client_service->regenerateClientSecret($client->id); - } - } - }); - - return $res; - } - - /** - * @param string $ip - * @return IResourceServer - */ - public function getByIPAddress($ip) - { - return ResourceServer::where('ips','like', '%'.$ip.'%')->first(); - } -} diff --git a/app/services/oauth2/UserConsentService.php b/app/services/oauth2/UserConsentService.php deleted file mode 100644 index 3da61ce8..00000000 --- a/app/services/oauth2/UserConsentService.php +++ /dev/null @@ -1,138 +0,0 @@ -nextPermutation($perm, $size) and ++$j); - - $scope_conditions = array(); - - $query1 = UserConsent::where('user_id', '=', $user_id)->where('client_id', '=', $client_id); - - $query2 = UserConsent::where('user_id', '=', $user_id)->where('client_id', '=', $client_id); - - - $query1 = $query1->where(function ($query) use($perms) - { - foreach ($perms as $p) - { - $str = join(' ', $p); - $query = $query->orWhere('scopes', '=', $str); - } - - return $query; - }); - - - $query2 = $query2->where(function ($query) use($perms) - { - foreach ($perms as $p) - { - $str = join(' ', $p); - $query = $query->orWhere('scopes', 'like', '%'.$str.'%'); - } - - return $query; - }); - - - $consent = $query1->first(); - - if (is_null($consent)) { - $consent = $query2->first(); - } - - return $consent; - } - - - /** - * @param $p - * @param $size - * @return bool - * - * http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm - * - */ - private function nextPermutation($p, $size) - { - // slide down the array looking for where we're smaller than the next guy - for ($i = $size - 1; $i >= 0 && $p[$i] >= $p[$i + 1]; --$i) {} - - // if this doesn't occur, we've finished our permutations - // the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1) - if ($i == -1) - { - return false; - } - - // slide down the array looking for a bigger number than what we found before - for ($j = $size; $p[$j] <= $p[$i]; --$j) {} - - // swap them - $tmp = $p[$i]; - $p[$i] = $p[$j]; - $p[$j] = $tmp; - - // now reverse the elements in between by swapping the ends - for (++$i, $j = $size; $i < $j; ++$i, --$j) - { - $tmp = $p[$i]; - $p[$i] = $p[$j]; - $p[$j] = $tmp; - } - - return $p; - } - - - /** - * @param $user_id - * @param $client_id - * @param $scopes - * @return IUserConsent|void - * @throws \oauth2\exceptions\AbsentClientException - */ - public function add($user_id, $client_id, $scopes) - { - $consent = new UserConsent(); - - if (is_null(Client::find($client_id))) { - throw new AbsentClientException; - } - - $consent->client_id = $client_id; - $consent->user_id = $user_id; - $consent->scopes = $scopes; - $consent->Save(); - } -} \ No newline at end of file diff --git a/app/services/openid/AssociationService.php b/app/services/openid/AssociationService.php deleted file mode 100644 index b6160190..00000000 --- a/app/services/openid/AssociationService.php +++ /dev/null @@ -1,196 +0,0 @@ -lock_manager_service = $lock_manager_service; - $this->cache_service = $cache_service; - $this->repository = $repository; - } - - /** - * gets a given association by handle, and if association exists and its type is private, then lock it - * to prevent subsequent usage ( private association could be used once) - * @param $handle - * @param null $realm - * @return null|IAssociation|OpenIdAssociation - * @throws \openid\exceptions\ReplayAttackException - * @throws \openid\exceptions\InvalidAssociation - * @throws \openid\exceptions\OpenIdInvalidRealmException - */ - public function getAssociation($handle, $realm = null) - { - - $lock_name = 'lock.get.assoc.' . $handle; - - try { - // check if association is on cache - if (!$this->cache_service->exists($handle)) { - // if not , check on db - $assoc = $this->repository->getByHandle($handle); - if (is_null($assoc)) { - throw new InvalidAssociation(sprintf('openid association %s does not exists!', $handle)); - } - //check association lifetime ... - $remaining_lifetime = $assoc->getRemainingLifetime(); - if ($remaining_lifetime < 0) { - $this->deleteAssociation($handle); - - return null; - } - //convert secret to hexa representation - // bin2hex - $secret_unpack = \unpack('H*', $assoc->secret); - $secret_unpack = array_shift($secret_unpack); - //repopulate cache - $this->cache_service->storeHash($handle, array( - "type" => $assoc->type, - "mac_function" => $assoc->mac_function, - "issued" => $assoc->issued, - "lifetime" => $assoc->lifetime, - "secret" => $secret_unpack, - "realm" => $assoc->realm - ), - $remaining_lifetime); - } - - //get hash from cache - $cache_values = $this->cache_service->getHash($handle, array( - "type", - "mac_function", - "issued", - "lifetime", - "secret", - "realm" - )); - - if ($cache_values['type'] == IAssociation::TypePrivate) { - if (is_null($realm) || empty($realm) || $cache_values['realm'] != $realm) { - throw new OpenIdInvalidRealmException(sprintf(OpenIdErrorMessages::InvalidPrivateAssociationMessage, - $handle, $realm)); - } - // only one time we could use this handle - $this->lock_manager_service->acquireLock($lock_name); - } - - //convert hex 2 bin - $secret = \pack('H*', $cache_values['secret']); - $assoc = new OpenIdAssociation(); - - $assoc->type = $cache_values['type']; - $assoc->mac_function = $cache_values['mac_function']; - $assoc->issued = $cache_values['issued']; - $assoc->lifetime = intval($cache_values['lifetime']); - $assoc->secret = $secret; - $realm = $cache_values['realm']; - if (!empty($realm)) { - $assoc->realm = $realm; - } - - return $assoc; - - } catch (UnacquiredLockException $ex1) { - throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackPrivateAssociationAlreadyUsed, - $handle)); - } - } - - /** - * @param $handle - * @return bool - */ - public function deleteAssociation($handle) - { - $this->cache_service->delete($handle); - $assoc = $this->repository->getByHandle($handle); - if (!is_null($assoc)) { - return $this->repository->delete($assoc); - } - - return false; - } - - /** - * @param IAssociation $association - * @return IAssociation|OpenIdAssociation - * @throws \openid\exceptions\ReplayAttackException - */ - public function addAssociation(IAssociation $association) - { - $assoc = new OpenIdAssociation(); - try { - $lock_name = 'lock.add.assoc.' . $association->getHandle(); - $this->lock_manager_service->acquireLock($lock_name); - - $assoc->identifier = $association->getHandle();; - $assoc->secret = $association->getSecret(); - $assoc->type = $association->getType();; - $assoc->mac_function = $association->getMacFunction(); - $assoc->lifetime = intval($association->getLifetime()); - $assoc->issued = $association->getIssued(); - - if (!is_null($association->getRealm())) { - $assoc->realm = $association->getRealm(); - } - - if ($association->getType() == IAssociation::TypeSession) { - $this->repository->add($assoc); - } - //convert secret to hexa representation - // bin2hex - $secret_unpack = \unpack('H*', $association->getSecret()); - $secret_unpack = array_shift($secret_unpack); - - $this->cache_service->storeHash($association->getHandle(), - array( - "type" => $association->getType(), - "mac_function" => $association->getMacFunction(), - "issued" => $association->getIssued(), - "lifetime" => intval($association->getLifetime()), - "secret" => $secret_unpack, - "realm" => !is_null($association->getRealm()) ? $association->getRealm() : '' - ), - intval($association->getLifetime()) - ); - - } catch (UnacquiredLockException $ex1) { - throw new ReplayAttackException(sprintf(OpenIdErrorMessages::ReplayAttackPrivateAssociationAlreadyUsed, - $association->getHandle())); - } - - return $assoc; - } - -} \ No newline at end of file diff --git a/app/services/openid/OpenIdProvider.php b/app/services/openid/OpenIdProvider.php deleted file mode 100644 index 771375ee..00000000 --- a/app/services/openid/OpenIdProvider.php +++ /dev/null @@ -1,42 +0,0 @@ -get(); - $res = array(); - foreach ($extensions as $extension) { - $class_name = $extension->extension_class; - if (empty($class_name)) continue; - - $class = new ReflectionClass($class_name); - $constructor = $class->getConstructor(); - $constructor_params = $constructor->getParameters(); - - $deps = array(); - - foreach($constructor_params as $constructor_param){ - $param_class = $constructor_param->getClass(); - $name = $constructor_param->getName(); - if(is_null($param_class)){ - array_push($deps,$extension->$name); - } - else{ - $service = ServiceLocator::getInstance()->getService($param_class->getName()); - array_push($deps,$service); - } - } - - $implementation = $class->newInstanceArgs($deps); - - array_push($res, $implementation); - } - return $res; - } -} \ No newline at end of file diff --git a/app/services/openid/UserService.php b/app/services/openid/UserService.php deleted file mode 100644 index 56aaa311..00000000 --- a/app/services/openid/UserService.php +++ /dev/null @@ -1,287 +0,0 @@ -repository = $repository; - $this->user_name_generator = $user_name_generator; - $this->configuration_service = $configuration_service; - $this->log_service = $log_service; - $this->tx_service = $tx_service; - } - - - /** - * @param $identifier - * @return mixed|void - * @throws \Exception - */ - public function updateLastLoginDate($identifier) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - $user->last_login_date = gmdate("Y-m-d H:i:s", time()); - $this->repository->update($user); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - } - - /** - * @param $identifier - * @return mixed|void - * @throws \Exception - */ - public function updateFailedLoginAttempts($identifier) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - $user->login_failed_attempt += 1; - $this->repository->update($user); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - } - - /** - * @param $identifier - * @return mixed|void - * @throws \Exception - */ - public function lockUser($identifier) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - - $user->lock = true; - $this->repository->update($user); - $support_email = $this->configuration_service->getConfigValue('SupportEmail'); - Mail::send('emails.auth.user_locked', array - ( - 'user_name' => $user->getFullName(), - 'attempts' => $user->login_failed_attempt, - 'support_email' => $support_email, - ), function($message) use ($user, $support_email) - { - $message - ->from($support_email, 'OpenStack Support Team') - ->to($user->getEmail(), $user->getFullName()) - ->subject('OpenStackId - your user has been locked!'); - }); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - } - - /** - * @param $identifier - * @return void - * @throws \Exception - */ - public function unlockUser($identifier) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - - $user->lock = false; - $this->repository->update($user); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - } - - /** - * @param $identifier - * @return mixed|void - * @throws \Exception - */ - public function activateUser($identifier) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - $user->active = true; - $this->repository->update($user); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - } - - /** - * @param $identifier - * @return mixed|void - * @throws \Exception - */ - public function deActivateUser($identifier) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - $user->active = false; - $this->repository->update($user); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - } - - /** - * @param $identifier - * @param $show_pic - * @param $show_full_name - * @param $show_email - * @return bool - * @throws \Exception - */ - public function saveProfileInfo($identifier, $show_pic, $show_full_name, $show_email) - { - try { - $user = $this->repository->get($identifier); - if (!is_null($user)) { - $user->public_profile_show_photo = $show_pic; - $user->public_profile_show_fullname = $show_full_name; - $user->public_profile_show_email = $show_email; - - return $this->repository->update($user); - } - } catch (Exception $ex) { - $this->log_service->error($ex); - throw $ex; - } - - return false; - } - - public function get($id) - { - return $this->repository->get($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('*')) - { - return $this->repository->getAll($page_nbr, $page_size, $filters, $fields); - } - - /** - * @param \Member $member - * @return IOpenIdUser - */ - public function buildUser(\Member $member) - { - $repository = $this->repository; - $user_name_generator = $this->user_name_generator; - - return $this->tx_service->transaction(function () use($member, $user_name_generator, $repository){ - //create user - $old_user = $repository->getByExternalId($member->ID); - if(!is_null($old_user)) - throw new ValidationException(sprintf('already exists an user with external_identifier %s', $member->ID)); - - $user = new User(); - $user->external_identifier = $member->ID; - $user->identifier = $member->ID; - $user->last_login_date = gmdate("Y-m-d H:i:s", time()); - $user->active = true; - $user->lock = false; - $user->login_failed_attempt = 0; - - $done = false; - $fragment_nbr = 1; - $identifier = $original_identifier = $user_name_generator->generate($member); - do - { - $old_user = $repository->getByIdentifier($identifier); - if(!is_null($old_user)) - { - $identifier = $original_identifier . IUserNameGeneratorService::USER_NAME_CHAR_CONNECTOR . $fragment_nbr; - $fragment_nbr++; - continue; - } - $user->identifier = $identifier; - break; - } while (1); - $repository->add($user); - return $user; - }); - } - -} \ No newline at end of file diff --git a/app/services/security_policies/DelayCounterMeasure.php b/app/services/security_policies/DelayCounterMeasure.php deleted file mode 100644 index 89f5219e..00000000 --- a/app/services/security_policies/DelayCounterMeasure.php +++ /dev/null @@ -1,36 +0,0 @@ -cache_service = $cache_service; - } - - public function trigger(array $params = array()) - { - try { - $remote_address = IPHelper::getUserIp(); - if ($this->cache_service->exists($remote_address)) { - Log::warning(sprintf("DelayCounterMeasure: attempt from banned ip %s",$remote_address)); - $hits = intval($this->cache_service->getSingleValue($remote_address)); - sleep(2 ^ $hits); - } - } catch (Exception $ex) { - Log::error($ex); - } - } -} \ No newline at end of file diff --git a/app/services/security_policies/LockUserCounterMeasure.php b/app/services/security_policies/LockUserCounterMeasure.php deleted file mode 100644 index b3fbac21..00000000 --- a/app/services/security_policies/LockUserCounterMeasure.php +++ /dev/null @@ -1,51 +0,0 @@ -user_service = $user_service; - $this->server_configuration = $server_configuration; - $this->repository = $repository; - } - - public function trigger(array $params = array()) - { - try { - - if (!isset($params["user_identifier"])) { - return; - } - $user_identifier = $params["user_identifier"]; - - $user = $this->repository->getByExternalId($user_identifier); - if (is_null($user)) { - return; - } - //apply lock policy - if (intval($user->login_failed_attempt) < intval($this->server_configuration->getConfigValue("MaxFailed.Login.Attempts"))) { - $this->user_service->updateFailedLoginAttempts($user->id); - } else { - $this->user_service->lockUser($user->id); - } - } catch (Exception $ex) { - Log::error($ex); - } - } -} \ No newline at end of file diff --git a/app/services/security_policies/LockUserSecurityPolicy.php b/app/services/security_policies/LockUserSecurityPolicy.php deleted file mode 100644 index 08354158..00000000 --- a/app/services/security_policies/LockUserSecurityPolicy.php +++ /dev/null @@ -1,50 +0,0 @@ -counter_measure = $counter_measure; - } - - /** - * Apply security policy on a exception - * @param Exception $ex - * @return void - */ - public function apply(Exception $ex) - { - try { - if($ex instanceof AuthenticationInvalidPasswordAttemptException) { - $user_identifier = $ex->getIdentifier(); - if (!is_null($user_identifier) && !empty($user_identifier)) - $this->counter_measure->trigger(array('user_identifier' => $user_identifier)); - } - } catch (Exception $ex) { - Log::error($ex); - } - } -} \ No newline at end of file diff --git a/app/services/security_policies/OAuth2LockClientCounterMeasure.php b/app/services/security_policies/OAuth2LockClientCounterMeasure.php deleted file mode 100644 index 1a8846b4..00000000 --- a/app/services/security_policies/OAuth2LockClientCounterMeasure.php +++ /dev/null @@ -1,35 +0,0 @@ -client_service = $client_service; - } - - public function trigger(array $params = array()) - { - try{ - - if (!isset($params["client_id"])) return; - $client_id = $params['client_id']; - $client = $this->client_service->getClientByIdentifier($client_id); - if(is_null($client)) - return; - //apply lock policy - $this->client_service->lockClient($client->id); - } - catch(Exception $ex){ - Log::error($ex); - } - } -} \ No newline at end of file diff --git a/app/services/security_policies/OAuth2SecurityPolicy.php b/app/services/security_policies/OAuth2SecurityPolicy.php deleted file mode 100644 index 45083e88..00000000 --- a/app/services/security_policies/OAuth2SecurityPolicy.php +++ /dev/null @@ -1,100 +0,0 @@ -server_configuration_service = $server_configuration_service; - $this->client_service = $client_service; - - $this->exception_dictionary = array( - 'auth2\exceptions\BearerTokenDisclosureAttemptException' => array('OAuth2SecurityPolicy.MaxBearerTokenDisclosureAttempts'), - 'auth2\exceptions\InvalidClientException' => array('OAuth2SecurityPolicy.MaxInvalidClientExceptionAttempts'), - 'auth2\exceptions\InvalidRedeemAuthCodeException' => array('OAuth2SecurityPolicy.MaxInvalidRedeemAuthCodeAttempts'), - 'auth2\exceptions\InvalidClientCredentials' => array('OAuth2SecurityPolicy.MaxInvalidClientCredentialsAttempts'), - ); - } - /** - * Check if current security policy is meet or not - * @return boolean - */ - public function check() - { - return true; - } - - /** - * Apply security policy on a exception - * @param Exception $ex - * @return mixed - */ - public function apply(Exception $ex) - { - try { - if(get_parent_class($ex)=='oauth2\\exceptions\\OAuth2ClientBaseException'){ - $client_id = $ex->getClientId(); - //save oauth2 exception by client id - if (!is_null($client_id) && !empty($client_id)){ - $client = $this->client_service->getClientById($client_id); - if(is_null($client)){ - Log::warning(sprintf("client id %s does not exists!",$client)); - return; - } - - $exception_class = get_class($ex); - $trail = new OAuth2TrailException(); - $trail->from_ip = IPHelper::getUserIp(); - $trail->exception_type = $exception_class; - $trail->client_id = $client->getId(); - $trail->Save(); - - //check exception count by type on last "MinutesWithoutExceptions" minutes... - $exception_count = intval(OAuth2TrailException::where('client_id', '=', intval($client->getId())) - ->where('exception_type', '=', $exception_class) - ->where('created_at', '>', DB::raw('( UTC_TIMESTAMP() - INTERVAL ' . $this->server_configuration_service->getConfigValue("OAuth2SecurityPolicy.MinutesWithoutExceptions") . ' MINUTE )')) - ->count()); - - if(array_key_exists($exception_class,$this->exception_dictionary)){ - $params = $this->exception_dictionary[$exception_class]; - $max_attempts = !is_null($params[0]) && !empty($params[0])? intval($this->server_configuration_service->getConfigValue($params[0])):0; - if ($exception_count >= $max_attempts) - $this->counter_measure->trigger(array('client_id' => $client->getId())); - } - - - } - } - - } catch (Exception $ex) { - Log::error($ex); - } - } - - public function setCounterMeasure(ISecurityPolicyCounterMeasure $counter_measure) - { - $this->counter_measure = $counter_measure; - } -} \ No newline at end of file diff --git a/app/services/security_policies/RevokeAuthorizationCodeRelatedTokens.php b/app/services/security_policies/RevokeAuthorizationCodeRelatedTokens.php deleted file mode 100644 index ede6e8c9..00000000 --- a/app/services/security_policies/RevokeAuthorizationCodeRelatedTokens.php +++ /dev/null @@ -1,49 +0,0 @@ -token_service = $token_service; - } - - /** - * @param array $params - */ - public function trigger(array $params = array()) - { - try { - if (!isset($params["auth_code"])) return; - $auth_code = $params["auth_code"]; - $this->token_service->revokeAuthCodeRelatedTokens($auth_code); - } catch (Exception $ex) { - Log::error($ex); - } - } -} \ No newline at end of file diff --git a/app/services/utils/EloquentTransactionService.php b/app/services/utils/EloquentTransactionService.php deleted file mode 100644 index 72458fd0..00000000 --- a/app/services/utils/EloquentTransactionService.php +++ /dev/null @@ -1,27 +0,0 @@ -boot(); - }); - - $this->app['serverconfigurationservice'] = App::share(function ($app) { - return new ServerConfigurationService(App::make(UtilsServiceCatalog::CacheService),App::make(UtilsServiceCatalog::TransactionService)); - }); - - $this->app['externalurlservice'] = App::share(function ($app) { - return new ExternalUrlService(); - }); - - // Shortcut so developers don't need to add an Alias in app/config/app.php - App::booting(function () { - $loader = AliasLoader::getInstance(); - $loader->alias('ServerConfigurationService', 'services\\facades\\ServerConfigurationService'); - $loader->alias('ExternalUrlService', 'services\\facades\\ExternalUrlService'); - }); - - App::singleton(UtilsServiceCatalog::LogService, 'services\\utils\\LogService'); - App::singleton(UtilsServiceCatalog::LockManagerService, 'services\\utils\\LockManagerService'); - App::singleton(UtilsServiceCatalog::ServerConfigurationService, 'services\\utils\\ServerConfigurationService'); - App::singleton(UtilsServiceCatalog::BannedIpService, 'services\\utils\\BannedIPService'); - - } - - public function provides() - { - return array('utils.services'); - } - - public function when(){ - return array('redis'); - } -} \ No newline at end of file diff --git a/app/start/artisan.php b/app/start/artisan.php deleted file mode 100644 index 1df850bc..00000000 --- a/app/start/artisan.php +++ /dev/null @@ -1,13 +0,0 @@ -setLevel(Config::get('server.EmailLog_Level', 'error')); - $mono_log->pushHandler($handler); -} - -if (Config::get('database.log', false)){ - - Event::listen('illuminate.query', function($query, $bindings, $time, $name) - { - $data = compact('bindings', 'time', 'name'); - - // Format binding data for sql insertion - foreach ($bindings as $i => $binding) - { - if ($binding instanceof \DateTime) - { - $bindings[$i] = $binding->format('\'Y-m-d H:i:s\''); - } - else if (is_string($binding)) - { - $bindings[$i] = "'$binding'"; - } - } - - // Insert bindings into query - $query = str_replace(array('%', '?'), array('%%', '%s'), $query); - $query = vsprintf($query, $bindings); - - Log::info($query, $data); - }); -} -/* -|-------------------------------------------------------------------------- -| Application Error Handler -|-------------------------------------------------------------------------- -| -| Here you may handle any errors that occur in your application, including -| logging them or displaying custom views for specific errors. You may -| even register several error handlers to handle different types of -| exceptions. If nothing is returned, the default error view is -| shown, which includes a detailed stack trace during debug. -| -*/ - -App::error(function (Exception $exception, $code) { - Log::error($exception); - if(!App::runningInConsole()) { - $checkpoint_service = ServiceLocator::getInstance()->getService(UtilsServiceCatalog::CheckPointService); - if ($checkpoint_service) { - $checkpoint_service->trackException($exception); - } - return Response::view('404', array(), 404); - } -}); - -App::error(function (InvalidOpenIdMessageException $exception, $code) { - Log::warning($exception); - if(!App::runningInConsole()) { - $checkpoint_service = ServiceLocator::getInstance()->getService(UtilsServiceCatalog::CheckPointService); - if ($checkpoint_service) { - $checkpoint_service->trackException($exception); - } - return Response::view('404', array(), 404); - } -}); - -App::error(function(\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $exception, $code){ - Log::warning($exception); - if(!App::runningInConsole()) { - return Response::view('404', array(), 404); - } -}); - -App::error(function(\Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException $exception, $code){ - Log::warning($exception); - if(!App::runningInConsole()) { - return Response::view('404', array(), 404); - } -}); - -App::error(function(Illuminate\Session\TokenMismatchException $exception, $code){ - Log::warning($exception); - if(!App::runningInConsole()) { - return Response::view('404', array(), 404); - } -}); - -App::error(function (InvalidOAuth2Request $exception, $code) { - Log::warning($exception); - if(!App::runningInConsole()) { - $checkpoint_service = ServiceLocator::getInstance()->getService(UtilsServiceCatalog::CheckPointService); - if ($checkpoint_service) { - $checkpoint_service->trackException($exception); - } - return Response::view('404', array(), 404); - } -}); - -/* -|-------------------------------------------------------------------------- -| Maintenance Mode Handler -|-------------------------------------------------------------------------- -| -| The "down" Artisan command gives you the ability to put an application -| into maintenance mode. Here, you will define what is displayed back -| to the user if maintenace mode is in effect for this application. -| -*/ - -App::down(function () { - return Response::make("Be right back!", 503); -}); - -/* -|-------------------------------------------------------------------------- -| Require The Filters File -|-------------------------------------------------------------------------- -| -| Next we will load the filters file for the application. This gives us -| a nice separate location to store our route and application filter -| definitions instead of putting them all in the main routes file. -| -*/ - -require app_path() . '/filters.php'; -require app_path() . '/validators.php'; \ No newline at end of file diff --git a/app/start/local.php b/app/start/local.php deleted file mode 100644 index adab104c..00000000 --- a/app/start/local.php +++ /dev/null @@ -1,3 +0,0 @@ -getContent(), $response->getHttpCode()); - $http_response->header('Content-Type', $response->getContentType()); - $http_response->header('Cache-Control','no-cache, no-store, max-age=0, must-revalidate'); - $http_response->header('Pragma','no-cache'); - return $http_response; - } -} \ No newline at end of file diff --git a/app/strategies/IConsentStrategy.php b/app/strategies/IConsentStrategy.php deleted file mode 100644 index 38e5ab28..00000000 --- a/app/strategies/IConsentStrategy.php +++ /dev/null @@ -1,8 +0,0 @@ -getContent(); - $return_to = $response->getReturnTo(); - - if (is_null($return_to) || empty($return_to)) { - return Response::view('404', array(), 404); - } - $return_to = (strpos($return_to, "?") == false) ? $return_to . "?" . $query_string : $return_to . "&" . $query_string; - - return Redirect::to($return_to) - ->header('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') - ->header('Pragma','no-cache'); - } -} \ No newline at end of file diff --git a/app/strategies/IndirectResponseUrlFragmentStrategy.php b/app/strategies/IndirectResponseUrlFragmentStrategy.php deleted file mode 100644 index 692d4a70..00000000 --- a/app/strategies/IndirectResponseUrlFragmentStrategy.php +++ /dev/null @@ -1,36 +0,0 @@ -getContent(); - $return_to = $response->getReturnTo(); - - if (is_null($return_to) || empty($return_to)) { - return Response::view('404', array(), 404);; - } - - $return_to = (strpos($return_to, "#") == false) ? $return_to . "#" . $fragment : $return_to . "&" . $fragment; - - return Redirect::to($return_to) - ->header('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') - ->header('Pragma','no-cache'); - } -} \ No newline at end of file diff --git a/app/strategies/OAuth2AuthenticationStrategy.php b/app/strategies/OAuth2AuthenticationStrategy.php deleted file mode 100644 index 04f97e1d..00000000 --- a/app/strategies/OAuth2AuthenticationStrategy.php +++ /dev/null @@ -1,26 +0,0 @@ -memento_service = $memento_service; - - parent::__construct($user_action_service, $auth_service); - } - - public function getLogin() - { - if (Auth::guest()) { - $msg = OpenIdMessage::buildFromMemento($this->memento_service->load()); - $auth_request = new OpenIdAuthenticationRequest($msg); - $params = array('realm' => $auth_request->getRealm()); - - if (!$auth_request->isIdentitySelectByOP()) { - $params['claimed_id'] = $auth_request->getClaimedId(); - $params['identity'] = $auth_request->getIdentity(); - $params['identity_select'] = false; - } else { - $params['identity_select'] = true; - } - - return View::make("login", $params); - } else { - return Redirect::action("UserController@getProfile"); - } - } - - public function postLogin() - { - //go to authentication flow again - $msg = OpenIdMessage::buildFromMemento($this->memento_service->load()); - $this->user_action_service->addUserAction($this->auth_service->getCurrentUser(), IPHelper::getUserIp(), - IUserActionService::LoginAction, $msg->getParam(OpenIdProtocol::OpenIDProtocol_Realm)); - - return Redirect::action("OpenIdProviderController@endpoint"); - } - - public function cancelLogin() - { - $this->auth_service->setUserAuthenticationResponse(IAuthService::AuthenticationResponse_Cancel); - - return Redirect::action("OpenIdProviderController@endpoint"); - } -} \ No newline at end of file diff --git a/app/strategies/StrategyProvider.php b/app/strategies/StrategyProvider.php deleted file mode 100644 index 2dcdc145..00000000 --- a/app/strategies/StrategyProvider.php +++ /dev/null @@ -1,46 +0,0 @@ -app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildPrivateAssociation('https://www.test.com/', 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - } - - - public function testAddSessionAssociation(){ - - $cache_stub = new CacheServiceStub; - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildSessionAssociation(OpenIdProtocol::AssociationSessionTypeDHSHA256, 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - } - - public function testGetSessionAssociationRedisCrash(){ - - $cache_mock = Mockery::mock('utils\services\ICacheService'); - $cache_mock->shouldReceive('storeHash')->once(); - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_mock); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildSessionAssociation(OpenIdProtocol::AssociationSessionTypeDHSHA256, 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - $hash = null; - $cache_mock->shouldReceive('storeHash')->once()->andReturnUsing(function($name, $values, $ttl) use(&$hash){ - $hash = $values; - }); - $cache_mock->shouldReceive('exists')->once()->andReturn(false); - $cache_mock->shouldReceive('getHash')->once()->andReturnUsing(function($name, $values) use(&$hash){ - return $hash; - }); - - $res2 = $service->getAssociation($res->getHandle()); - - $this->assertTrue(!is_null($res2)); - - $this->assertTrue($res2->getSecret()===$res->getSecret()); - } - - - /** - * @expectedException \openid\exceptions\InvalidAssociation - */ - public function testGetSessionAssociationMustFail_InvalidAssociation(){ - - $cache_mock = Mockery::mock('utils\services\ICacheService'); - $cache_mock->shouldReceive('storeHash')->once(); - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_mock); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $repo_mock = Mockery::mock('openid\repositories\IOpenIdAssociationRepository'); - $this->app->instance('openid\repositories\IOpenIdAssociationRepository',$repo_mock); - $repo_mock->shouldReceive('add')->once(); - $repo_mock->shouldReceive('getByHandle')->once()->andReturnNull(); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildSessionAssociation(OpenIdProtocol::AssociationSessionTypeDHSHA256, 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - $hash = null; - $cache_mock->shouldReceive('exists')->once()->andReturn(false); - $service->getAssociation($res->getHandle()); - } - - - /** - * @expectedException \openid\exceptions\ReplayAttackException - */ - public function testAddPrivateAssociationMustFail_ReplayAttackException(){ - - $cache_stub = new CacheServiceStub; - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildPrivateAssociation('https://www.test.com/', 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - $lock_manager_service_mock->shouldReceive('acquireLock')->once()->andThrow(new UnacquiredLockException); - $service->addAssociation($assoc); - } - - public function testGetPrivateAssociation(){ - - $cache_stub = new CacheServiceStub; - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->twice(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildPrivateAssociation('https://www.test.com/', 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - - $res2 = $service->getAssociation($res->getHandle(),'https://www.test.com/'); - - $this->assertTrue(!is_null($res2)); - - $this->assertTrue($res2->getSecret()===$res->getSecret()); - } - - - /** - * @expectedException \openid\exceptions\OpenIdInvalidRealmException - */ - public function testGetPrivateAssociationMustFail_OpenIdInvalidRealmException(){ - - $cache_stub = new CacheServiceStub; - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildPrivateAssociation('https://www.test.com/', 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - - $service->getAssociation($res->getHandle(),'https://www1.test.com/'); - } - - /** - * @expectedException \openid\exceptions\InvalidAssociation - */ - public function testGetPrivateAssociationMustFail_InvalidAssociation(){ - - $cache_stub = new CacheServiceStub; - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->once(); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildPrivateAssociation('https://www.test.com/', 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - - $service->getAssociation('123456','https://www1.test.com/'); - } - - - /** - * @expectedException \openid\exceptions\ReplayAttackException - */ - public function testGetPrivateAssociationMustFail_ReplayAttackException(){ - - - $cache_stub = new CacheServiceStub; - $this->app->instance(UtilsServiceCatalog::CacheService,$cache_stub); - - $lock_manager_service_mock = Mockery::mock('utils\services\ILockManagerService'); - $lock_manager_service_mock->shouldReceive('acquireLock')->times(2); - - $this->app->instance(UtilsServiceCatalog::LockManagerService ,$lock_manager_service_mock); - - $service = $this->app[OpenIdServiceCatalog::AssociationService]; - $assoc = AssociationFactory::getInstance()->buildPrivateAssociation('https://www.test.com/', 3600); - $res = $service->addAssociation($assoc); - - $this->assertTrue(!is_null($res)); - - $res2 = $service->getAssociation($res->getHandle(),'https://www.test.com/'); - - $this->assertTrue(!is_null($res2)); - - $this->assertTrue($res2->getSecret()===$res->getSecret()); - $lock_manager_service_mock->shouldReceive('acquireLock')->once()->andThrow(new UnacquiredLockException); - $service->getAssociation($res->getHandle(),'https://www.test.com/'); - } -} \ No newline at end of file diff --git a/app/tests/ExceptionTest.php b/app/tests/ExceptionTest.php deleted file mode 100644 index 0852f0b6..00000000 --- a/app/tests/ExceptionTest.php +++ /dev/null @@ -1,20 +0,0 @@ -getExName($ex1); - $this->assertTrue($class_name == 'openid\exceptions\ReplayAttackException'); - } -} \ No newline at end of file diff --git a/app/tests/OpenIdProviderControllerTest.php b/app/tests/OpenIdProviderControllerTest.php deleted file mode 100644 index 39189de0..00000000 --- a/app/tests/OpenIdProviderControllerTest.php +++ /dev/null @@ -1,19 +0,0 @@ - "http://specs.openid.net/auth/2.0", - "openid.claimed_id" => "http://specs.openid.net/auth/2.0/identifier_select", - "openid.identity" => "http://specs.openid.net/auth/2.0/identifier_select", - "openid.return_to" => "http://www.test.com", - "openid.realm" => "http://www.test.com/", - "openid.mode" => "checkid_setup" - ); - - $response = $this->action("POST", "OpenIdProviderController@endpoint", $params); - } -} \ No newline at end of file diff --git a/app/tests/ServerExtensionTest.php b/app/tests/ServerExtensionTest.php deleted file mode 100644 index 8cb1ecd4..00000000 --- a/app/tests/ServerExtensionTest.php +++ /dev/null @@ -1,18 +0,0 @@ -name = 'AX'; - $new_ext->description = 'OpenID service extension for exchanging identity information between endpoints'; - $new_ext->namespace = 'http://openid.net/srv/ax/1.0'; - $new_ext->active = true; - $new_ext->extension_class = ''; - $new_ext->save(); - $ax = ServerExtension::where('name', '=', 'AX')->firstOrFail(); - $this->assertTrue($ax !== null); - } -} \ No newline at end of file diff --git a/app/tests/TestCase.php b/app/tests/TestCase.php deleted file mode 100644 index ea8d6de7..00000000 --- a/app/tests/TestCase.php +++ /dev/null @@ -1,46 +0,0 @@ -redis = \RedisLV4::connection(); - $this->redis->flushall(); - $this->prepareForTests(); - } - - - /** - * Migrates the database and set the mailer to 'pretend'. - * This will cause the tests to run quickly. - * - */ - protected function prepareForTests() - { - Artisan::call('migrate'); - Mail::pretend(true); - $this->seed('TestSeeder'); - } - - /** - * Creates the application. - * - * @return Symfony\Component\HttpKernel\HttpKernelInterface - */ - public function createApplication() - { - $unitTesting = true; - - $testEnvironment = 'testing'; - - return require __DIR__.'/../../bootstrap/start.php'; - } - -} diff --git a/app/validators.php b/app/validators.php deleted file mode 100644 index edce4da5..00000000 --- a/app/validators.php +++ /dev/null @@ -1,6 +0,0 @@ - - -
- - - -Dear {{$user_name}}, your user got blocked after {{$attempts}} failed login attempts.
-Please send an email to {{$support_email}} in order to reactive it again.
-Cheers,
OpenStack Support Team
** {{$app_name}} Application and OpenStack will use this information in accordance with their respective terms of service and privacy policies.
-Issued | -Scopes | -Remaining Lifetime | -- |
---|---|---|---|
{{ $access_token->created_at }} | -{{ $access_token->scope }} | -{{ $access_token->getRemainingLifetime() }} | -{{ HTML::link(URL::action("ClientApiController@revokeToken",array("id"=>$client->id,"value"=>$access_token->value,'hint'=>'access-token')),'Revoke',array('class'=>'btn btn-default btn-md active btn-delete revoke-token revoke-access-token','title'=>'Revoke Access Token','data-value'=>$access_token->value,'data-hint'=>'access-token')) }} | -
Issued | -Scopes | -Remaining Lifetime | -- | |
---|---|---|---|---|
{{ $refresh_token->created_at }} | -{{ $refresh_token->scope }} | - @if($refresh_token->getRemainingLifetime()===0) -Not Expire | - @else -{{ $refresh_token->getRemainingLifetime() }} | - @endif -{{ HTML::link(URL::action("ClientApiController@revokeToken",array("id"=>$client->id,"value"=>$refresh_token->value,'hint'=>'refresh-token')),'Revoke',array('class'=>'btn btn-default btn-md active btn-delete revoke-token revoke-refresh-token','title'=>'Revoke Refresh Token','data-value'=>$refresh_token->value,'data-hint'=>'refresh-token')) }} | -
- You have granted the following services access to your OpenstackId Account:
-
Application Type | -Application Name | -Granted Scopes | -- |
---|---|---|---|
{{$access_token->client()->first()->getFriendlyApplicationType()}} | -{{$access_token->client()->first()->app_name}} | -{{$access_token->scope}} | -{{ HTML::link(URL::action("UserApiController@revokeToken",array("id"=>$user_id,"value"=>$access_token->value, "hint"=>'access_token')),'Revoke Access',array('data-value' => $access_token->value,'data-hint'=>'access_token','class'=>'btn btn-default btn-md active btn-delete revoke-access','title'=>'Revoke Access Token')) }} | -
Application Type | -Application Name | -Granted Scopes | -- |
---|---|---|---|
{{$refresh_token->client()->first()->getFriendlyApplicationType()}} | -{{$refresh_token->client()->first()->app_name}} | -{{$refresh_token->scope}} | -{{ HTML::link(URL::action("UserApiController@revokeToken",array("id" => $user_id,"value" => $refresh_token->value, "hint" => 'refresh_token')),'Revoke Access',array('data-value' => $refresh_token->value,'data-hint' => 'refresh_token','class' => 'btn btn-default btn-md active btn-delete revoke-access','title' => 'Revoke Access Token')) }} | -
Your Session at OpenstackID had ended!
-