From 00509888309ade885a313dc47a95498b7cad3464 Mon Sep 17 00:00:00 2001 From: Sebastian Marcet Date: Sat, 1 Sep 2018 14:27:41 -0300 Subject: [PATCH] Silent token renewal issue Fixed identiy check issue Change-Id: Icf30f27df424dd3a9b7b3477febecdf297e10b37 --- app/Services/OAuth2/ResourceServerService.php | 7 +-- app/Services/OAuth2/TokenService.php | 5 +- app/libs/Auth/AuthService.php | 46 +++++++++++++++++-- .../Exceptions/ReloadSessionException.php | 30 ++++++++++++ .../GrantTypes/InteractiveGrantType.php | 25 ++++++---- app/libs/OAuth2/OAuth2Protocol.php | 4 +- app/libs/Utils/Services/IAuthService.php | 9 ++++ 7 files changed, 102 insertions(+), 24 deletions(-) create mode 100644 app/libs/OAuth2/Exceptions/ReloadSessionException.php diff --git a/app/Services/OAuth2/ResourceServerService.php b/app/Services/OAuth2/ResourceServerService.php index f8aef983..7f9e1269 100644 --- a/app/Services/OAuth2/ResourceServerService.php +++ b/app/Services/OAuth2/ResourceServerService.php @@ -103,12 +103,7 @@ final class ResourceServerService implements IResourceServerService ); } - 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 diff --git a/app/Services/OAuth2/TokenService.php b/app/Services/OAuth2/TokenService.php index 9f3975da..235fffec 100644 --- a/app/Services/OAuth2/TokenService.php +++ b/app/Services/OAuth2/TokenService.php @@ -1447,11 +1447,8 @@ final class TokenService implements ITokenService // build claim set $epoch_now = time(); - $session_id = Crypt::encrypt(Session::getId()); - $encoder = new Base64UrlRepresentation(); - $jti = $encoder->encode(hash('sha512', $session_id.$client_id, true)); - $this->cache_service->addSingleValue($jti, $session_id, $id_token_lifetime); + $jti = $this->auth_service->generateJTI($client_id, $id_token_lifetime); $claim_set = new JWTClaimSet ( diff --git a/app/libs/Auth/AuthService.php b/app/libs/Auth/AuthService.php index a551913d..e9463c1f 100644 --- a/app/libs/Auth/AuthService.php +++ b/app/libs/Auth/AuthService.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\libs\OAuth2\Exceptions\ReloadSessionException; use Auth\Repositories\IMemberRepository; use Auth\Repositories\IUserRepository; use Illuminate\Support\Facades\Auth; @@ -21,6 +22,7 @@ use OAuth2\Models\IClient; use OAuth2\Services\IPrincipalService; use OpenId\Models\IOpenIdUser; use OpenId\Services\IUserService; +use utils\Base64UrlRepresentation; use Utils\Services\IAuthService; use Utils\Services\ICacheService; use jwe\compression_algorithms\CompressionAlgorithms_Registry; @@ -104,10 +106,12 @@ final class AuthService implements IAuthService */ public function login($username, $password, $remember_me) { + Log::debug("AuthService::login"); $res = Auth::attempt(array('username' => $username, 'password' => $password), $remember_me); if ($res) { + Log::debug("AuthService::login: clearing principal"); $this->principal_service->clear(); $this->principal_service->register ( @@ -121,6 +125,7 @@ final class AuthService implements IAuthService public function logout() { + $this->invalidateSession(); Auth::logout(); $this->principal_service->clear(); Cookie::queue(IAuthService::LOGGED_RELAYING_PARTIES_COOKIE_NAME, null, $minutes = -2628000, $path = '/', $domain = null, $secure = false, $httpOnly = false); @@ -348,7 +353,7 @@ final class AuthService implements IAuthService $rps = $zlib->uncompress($rps); return explode('|', $rps); } - return null; + return []; } /** @@ -357,16 +362,51 @@ final class AuthService implements IAuthService */ public function reloadSession($jti) { + Log::debug(sprintf("AuthService::reloadSession jti %s", $jti )); $session_id = $this->cache_service->getSingleValue($jti); - if(empty($session_id)) throw new Exception('session not found!'); + + Log::debug(sprintf("AuthService::reloadSession session_id %s", $session_id )); + if(empty($session_id)) + throw new ReloadSessionException('session not found!'); + + if($this->cache_service->exists($session_id."invalid")){ + // session was marked as void, check if we are authenticated + if(!Auth::check()) + throw new ReloadSessionException('user not found!'); + } + Session::setId(Crypt::decrypt($session_id)); Session::start(); if(!Auth::check()) { + $user_id = $this->principal_service->get()->getUserId(); + Log::debug(sprintf("AuthService::reloadSession user_id %s", $user_id )); $user = $this->getUserById($user_id); - if(is_null($user)) throw new Exception('user not found!'); + if(is_null($user)) + throw new ReloadSessionException('user not found!'); Auth::login($user); } } + + /** + * @param string $client_id + * @param int $id_token_lifetime + * @return string + */ + public function generateJTI($client_id, $id_token_lifetime){ + $session_id = Crypt::encrypt(Session::getId()); + $encoder = new Base64UrlRepresentation(); + $jti = $encoder->encode(hash('sha512', $session_id.$client_id, true)); + + $this->cache_service->addSingleValue($jti, $session_id, $id_token_lifetime); + + return $jti; + } + + + public function invalidateSession(){ + $session_id = Crypt::encrypt(Session::getId()); + $this->cache_service->addSingleValue($session_id."invalid", $session_id); + } } \ No newline at end of file diff --git a/app/libs/OAuth2/Exceptions/ReloadSessionException.php b/app/libs/OAuth2/Exceptions/ReloadSessionException.php new file mode 100644 index 00000000..8dcdc676 --- /dev/null +++ b/app/libs/OAuth2/Exceptions/ReloadSessionException.php @@ -0,0 +1,30 @@ +getLoginHint(); $token_hint = $request->getIdTokenHint(); - + $this->log_service->debug_msg("InteractiveGrantType::processUserHint"); // process login hint $user = null; @@ -418,6 +419,7 @@ abstract class InteractiveGrantType extends AbstractGrantType } else if(!empty($token_hint)) { + $this->log_service->debug_msg("InteractiveGrantType::processUserHint has token hint"); $client_id = $request->getClientId(); $client = $this->client_repository->getClientById($client_id); @@ -437,6 +439,7 @@ abstract class InteractiveGrantType extends AbstractGrantType if($jwt instanceof IJWE) { + $this->log_service->debug_msg("InteractiveGrantType::processUserHint token hint is IJWE"); // decrypt using server key $heuristic = new ServerEncryptionKeyFinder($this->server_private_key_repository); $server_enc_private_key = $heuristic->find @@ -452,6 +455,7 @@ abstract class InteractiveGrantType extends AbstractGrantType } if($jwt instanceof IJWS) { + $this->log_service->debug_msg("InteractiveGrantType::processUserHint token hint is IJWS"); // signed by client ? try { @@ -467,7 +471,7 @@ abstract class InteractiveGrantType extends AbstractGrantType catch(RecipientKeyNotFoundException $ex) { // try to find the server signing key used ... - + $this->log_service->debug_msg("InteractiveGrantType::processUserHint token hint is IJWS -> RecipientKeyNotFoundException"); $heuristic = new ServerSigningKeyFinder($this->server_private_key_repository); $server_private_sig_key = $heuristic->find ( @@ -497,19 +501,20 @@ abstract class InteractiveGrantType extends AbstractGrantType if($user) { - $principal = $this->principal_service->get(); - + $this->log_service->debug_msg("InteractiveGrantType::processUserHint: checking principal"); + $logged_user = $this->auth_service->getCurrentUser(); if ( - !is_null($principal) && - !is_null($principal->getUserId()) && - $principal->getUserId() !== $user->getId() + !is_null($logged_user) && + $logged_user->getId() !== $user->getId() ) { - if(!$this->canInteractWithEndUser($request)) - throw new InteractionRequiredException; - $this->auth_service->logout(); + + if(!$this->canInteractWithEndUser($request)) { + $this->log_service->debug_msg("InteractiveGrantType::processUserHint: cant interact with user"); + throw new InteractionRequiredException; + } } $this->security_context_service->save diff --git a/app/libs/OAuth2/OAuth2Protocol.php b/app/libs/OAuth2/OAuth2Protocol.php index 89c83ae2..85eb5634 100644 --- a/app/libs/OAuth2/OAuth2Protocol.php +++ b/app/libs/OAuth2/OAuth2Protocol.php @@ -563,6 +563,7 @@ final class OAuth2Protocol implements IOAuth2Protocol //http://tools.ietf.org/html/rfc6750#section-3-1 const OAuth2Protocol_Error_InvalidToken = 'invalid_token'; const OAuth2Protocol_Error_InsufficientScope = 'insufficient_scope'; + const OAuth2Protocol_Error_Session_Cant_Reload = 'session_cant_reload'; // http://openid.net/specs/openid-connect-core-1_0.html#AuthError @@ -1427,8 +1428,9 @@ final class OAuth2Protocol implements IOAuth2Protocol $this->log_service->debug_msg("OAuth2Protocol::endSession user not found!"); throw new InvalidOAuth2Request('user not found!'); } + $logged_user = $this->auth_service->getCurrentUser(); - if($this->principal_service->get()->getUserId() !== $user->getId()) { + if(is_null($logged_user) || $logged_user->getId() !== $user->getId()) { $this->log_service->debug_msg("OAuth2Protocol::endSession user does not match with current session!"); throw new InvalidOAuth2Request('user does not match with current session!'); } diff --git a/app/libs/Utils/Services/IAuthService.php b/app/libs/Utils/Services/IAuthService.php index 58d32a30..5d659267 100644 --- a/app/libs/Utils/Services/IAuthService.php +++ b/app/libs/Utils/Services/IAuthService.php @@ -127,4 +127,13 @@ interface IAuthService const LOGGED_RELAYING_PARTIES_COOKIE_NAME = 'rps'; + /** + * @param string $client_id + * @param int $id_token_lifetime + * @return string + */ + public function generateJTI($client_id, $id_token_lifetime); + + public function invalidateSession(); + } \ No newline at end of file