auth_service = $auth_service; $this->user_repository = $user_repository; $this->scope_service = $scope_service; $this->client_credential_generator = $client_credential_generator; $this->client_repository = $client_repository; $this->client_factory = $client_factory; $this->tx_service = $tx_service; } /** * Clients in possession of a client password MAY use the HTTP Basic * authentication scheme as defined in [RFC2617] to authenticate with * the authorization server * Alternatively, the authorization server MAY support including the * client credentials in the request-body using the following * parameters: * implementation of http://tools.ietf.org/html/rfc6749#section-2.3.1 * implementation of http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication * @throws InvalidClientAuthMethodException * @throws MissingClientAuthorizationInfo * @return ClientAuthenticationContext */ public function getCurrentClientAuthInfo() { $auth_header = Request::header('Authorization'); if ( Input::has( OAuth2Protocol::OAuth2Protocol_ClientAssertionType) && Input::has( OAuth2Protocol::OAuth2Protocol_ClientAssertion) ) { return new ClientAssertionAuthenticationContext ( Input::get(OAuth2Protocol::OAuth2Protocol_ClientAssertionType, ''), Input::get(OAuth2Protocol::OAuth2Protocol_ClientAssertion, '') ); } if ( Input::has( OAuth2Protocol::OAuth2Protocol_ClientId) && Input::has( OAuth2Protocol::OAuth2Protocol_ClientSecret) ) { return new ClientCredentialsAuthenticationContext ( Input::get(OAuth2Protocol::OAuth2Protocol_ClientId, ''), Input::get(OAuth2Protocol::OAuth2Protocol_ClientSecret, ''), OAuth2Protocol::TokenEndpoint_AuthMethod_ClientSecretPost ); } if(!empty($auth_header)) { $auth_header = trim($auth_header); $auth_header = explode(' ', $auth_header); if (!is_array($auth_header) || count($auth_header) < 2) { throw new MissingClientAuthorizationInfo('bad auth header.'); } $auth_header_content = $auth_header[1]; $auth_header_content = base64_decode($auth_header_content); $auth_header_content = explode(':', $auth_header_content); if (!is_array($auth_header_content) || count($auth_header_content) !== 2) { throw new MissingClientAuthorizationInfo('bad auth header.'); } return new ClientCredentialsAuthenticationContext( $auth_header_content[0], $auth_header_content[1], OAuth2Protocol::TokenEndpoint_AuthMethod_ClientSecretBasic ); } throw new InvalidClientAuthMethodException; } /** * @param string $application_type * @param string $app_name * @param string $app_description * @param null|string $app_url * @param array $admin_users * @param string $app_logo * @return IClient */ public function addClient ( $application_type, $app_name, $app_description, $app_url = null, array $admin_users = array(), $app_logo = '' ) { $scope_service = $this->scope_service; $client_credential_generator = $this->client_credential_generator; $user_repository = $this->user_repository; $client_repository = $this->client_repository; $client_factory = $this->client_factory; $current_user = $this->auth_service->getCurrentUser(); return $this->tx_service->transaction(function () use ( $application_type, $current_user, $app_name, $app_url, $app_description, $app_logo, $admin_users, $scope_service, $user_repository, $client_repository, $client_factory, $client_credential_generator ) { $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) { if ( $default_scope->name === OAuth2Protocol::OfflineAccess_Scope && !( $client->application_type == IClient::ApplicationType_Native || $client->application_type == IClient::ApplicationType_Web_App ) ) { continue; } $client->addScope($default_scope); } //add admin users foreach($admin_users as $user_id) { $user = $user_repository->get(intval($user_id)); if(is_null($user)) throw new EntityNotFoundException(sprintf('user %s not found.',$user_id)); $client->addAdminUser($user); } return $client; }); } /** * @param $id * @param array $params * @throws AbsentClientException * @throws \ValidationException * @return mixed */ 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) { $client = $client_repository->get($id); if (is_null($client)) { throw new AbsentClientException(sprintf('client id %s does not exists.', $id)); } $current_app_type = $client->getApplicationType(); if($current_app_type !== $params['application_type']) { throw new \ValidationException('application type does not match.'); } // validate uris switch($current_app_type) { case IClient::ApplicationType_Native: { if (isset($params['redirect_uris'])) { $redirect_uris = explode(',', $params['redirect_uris']); //check that custom schema does not already exists for another registerd app if (!empty($params['redirect_uris'])) { foreach ($redirect_uris as $uri) { $uri = @parse_url($uri); if (!isset($uri['scheme'])) { 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.', $uri['scheme'])); } } else { if (!HttpUtils::isHttpSchema($uri['scheme'])) { throw new \ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); } } } } } } break; case IClient::ApplicationType_Web_App: case IClient::ApplicationType_JS_Client: { if (isset($params['redirect_uris'])){ if (!empty($params['redirect_uris'])) { $redirect_uris = explode(',', $params['redirect_uris']); foreach ($redirect_uris as $uri) { $uri = @parse_url($uri); if (!isset($uri['scheme'])) { throw new \ValidationException('invalid scheme on redirect uri.'); } if (!HttpUtils::isHttpsSchema($uri['scheme'])) { throw new \ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); } } } } if($current_app_type === IClient::ApplicationType_JS_Client && isset($params['allowed_origins']) &&!empty($params['allowed_origins'])){ $allowed_origins = explode(',', $params['allowed_origins']); foreach ($allowed_origins as $uri) { $uri = @parse_url($uri); if (!isset($uri['scheme'])) { throw new \ValidationException('invalid scheme on allowed origin uri.'); } if (!HttpUtils::isHttpsSchema($uri['scheme'])) { throw new \ValidationException(sprintf('scheme %s:// is invalid.', $uri['scheme'])); } } } } break; } $allowed_update_params = array( 'app_name', 'website', 'app_description', 'app_logo', 'active', 'locked', 'use_refresh_token', 'rotate_refresh_token', 'contacts', 'logo_uri', 'tos_uri', 'post_logout_redirect_uris', 'logout_uri', 'logout_session_required', 'logout_use_iframe', 'policy_uri', 'jwks_uri', 'default_max_age', 'logout_use_iframe', 'require_auth_time', 'token_endpoint_auth_method', 'token_endpoint_auth_signing_alg', 'subject_type', 'userinfo_signed_response_alg', 'userinfo_encrypted_response_alg', 'userinfo_encrypted_response_enc', 'id_token_signed_response_alg', 'id_token_encrypted_response_alg', 'id_token_encrypted_response_enc', 'redirect_uris', 'allowed_origins', 'admin_users', ); $fields_to_uri_normalize = array ( 'post_logout_redirect_uris', 'logout_uri', 'policy_uri', 'jwks_uri', 'tos_uri', 'logo_uri', 'redirect_uris', 'allowed_origins' ); foreach ($allowed_update_params as $param) { if (array_key_exists($param, $params)) { if($param === 'admin_users'){ $admin_users = trim($params['admin_users']); $admin_users = empty($admin_users) ? array():explode(',',$admin_users); $client->removeAllAdminUsers(); foreach($admin_users as $user_id) { $user = $user_repository->get(intval($user_id)); if(is_null($user)) throw new EntityNotFoundException(sprintf('user %s not found.',$user_id)); $client->addAdminUser($user); } } else { if (in_array($param, $fields_to_uri_normalize)) { $urls = $params[$param]; if (!empty($urls)) { $urls = explode(',', $urls); $normalized_uris = ''; foreach ($urls as $url) { $un = new Normalizer($url); $url = $un->normalize(); if (!empty($normalized_uris)) { $normalized_uris .= ','; } $normalized_uris .= $url; } $params[$param] = $normalized_uris; } } $client->{$param} = $params[$param]; } } } $client_repository->add($client->setEditedBy($editing_user)); return $client; }); } 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; } } 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; } 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; } 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 $res; } /** * Regenerates Client Secret * @param $id client id * @return IClient */ public function regenerateClientSecret($id) { $client_credential_generator = $this->client_credential_generator; $current_user = $this->auth_service->getCurrentUser(); return $this->tx_service->transaction(function () use ($id, $current_user, $client_credential_generator) { $client = Client::find($id); if (is_null($client)) { throw new AbsentClientException(sprintf("client id %d does not exists!.", $id)); } if ($client->client_type != IClient::ClientType_Confidential) { throw new InvalidClientType ( sprintf ( "client id %d is not confidential type!.", $id ) ); } $client = $client_credential_generator->generate($client, true); $client->setEditedBy($current_user); $client->save(); Event::fire('oauth2.client.regenerate.secret', array($client->client_id)); return $client; }); } /** * @param client $client_id * @return mixed * @throws \oauth2\exceptions\AbsentClientException */ public function lockClient($client_id) { $res = false; $this_var = $this; $this->tx_service->transaction(function () use ($client_id, &$res, &$this_var) { $client = $this_var->getClientByIdentifier($client_id); if (is_null($client)) { throw new AbsentClientException($client_id, sprintf("client id %s does not exists!", $client_id)); } $client->locked = true; $res = $client->Save(); }); return $res; } /** * @param client $client_id * @return mixed * @throws \oauth2\exceptions\AbsentClientException */ public function unlockClient($client_id) { $res = false; $this_var = $this; $this->tx_service->transaction(function () use ($client_id, &$res, &$this_var) { $client = $this_var->getClientByIdentifier($client_id); if (is_null($client)) { throw new AbsentClientException($client_id, sprintf("client id %s does not exists!", $client_id)); } $client->locked = false; $res = $client->Save(); }); return $res; } /** * @param $client_id * @return IClient */ public function getClientById($client_id) { $client = Client::where('client_id', '=', $client_id)->first(); return $client; } public function activateClient($id, $active) { $client = $this->getClientByIdentifier($id); if (is_null($client)) { throw new AbsentClientException(sprintf("client id %s does not exists!", $id)); } $client->active = $active; return $client->Save(); } public function getClientByIdentifier($id) { $client = Client::where('id', '=', $id)->first(); return $client; } public function setRefreshTokenUsage($id, $use_refresh_token) { $client = $this->getClientByIdentifier($id); if (is_null($client)) { throw new AbsentClientException(sprintf("client id %s does not exists!", $id)); } $client->use_refresh_token = $use_refresh_token; $client->setEditedBy($this->auth_service->getCurrentUser()); return $client->Save(); } public function setRotateRefreshTokenPolicy($id, $rotate_refresh_token) { $client = $this->getClientByIdentifier($id); if (is_null($client)) { throw new AbsentClientException(sprintf("client id %s does not exists!", $id)); } $client->rotate_refresh_token = $rotate_refresh_token; $client->setEditedBy($this->auth_service->getCurrentUser()); return $client->Save(); } public function existClientAppName($app_name) { return Client::where('app_name', '=', $app_name)->count() > 0; } /** * gets an api scope by id * @param $id id of api scope * @return IApiScope */ public function get($id) { return Client::find($id); } /** * @param int $page_nbr * @param int $page_size * @param array $filters * @param array $fields * @return mixed */ public function getAll($page_nbr = 1, $page_size = 10, array $filters = array(), array $fields = array('*')) { DB::getPaginator()->setCurrentPage($page_nbr); return Client::Filter($filters)->paginate($page_size, $fields); } /** * @param string $origin * @return IClient */ public function getByOrigin($origin) { return Client::where('allowed_origins', 'like', '%'.$origin.'%')->first(); } }