From 0eaaf79ad80b27d8f7fa88f287b25087e3652cd9 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Wed, 25 Feb 2026 20:10:09 +0000 Subject: [PATCH] - WIP on v2.x authentication --- src/Authorize/Bearer/JsonWebTokenDecoder.php | 8 ++-- src/Authorize/Header/BearerMethod.php | 10 ++++- src/Authorize/HeaderAuthentication.php | 2 +- src/Entity/User.php | 6 +-- src/Exception/InvalidUserException.php | 5 +++ src/Middleware/AuthenticationMiddleware.php | 43 ++++++++++++-------- 6 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 src/Exception/InvalidUserException.php diff --git a/src/Authorize/Bearer/JsonWebTokenDecoder.php b/src/Authorize/Bearer/JsonWebTokenDecoder.php index 039896b..404804d 100644 --- a/src/Authorize/Bearer/JsonWebTokenDecoder.php +++ b/src/Authorize/Bearer/JsonWebTokenDecoder.php @@ -70,11 +70,11 @@ class JsonWebTokenDecoder public function isJWT() : bool { try { - return $this->parse(); + return count(explode('.', $this->encoded)) === 3; + } + catch(\Throwable $t) { + return false; } - catch(\Throwable $t) {} - - return false; } public function getPayload() : array diff --git a/src/Authorize/Header/BearerMethod.php b/src/Authorize/Header/BearerMethod.php index f2b5f20..98a890e 100644 --- a/src/Authorize/Header/BearerMethod.php +++ b/src/Authorize/Header/BearerMethod.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ServerRequestInterface; use Ulmus\User\Authorize\Bearer\JsonWebTokenDecoder; use Ulmus\User\Entity\UserInterface; use Ulmus\User\Lib\Authenticate; +use Ulmus\User\Lib\AuthenticationMethodEnum; class BearerMethod implements MethodInterface { @@ -23,10 +24,15 @@ class BearerMethod implements MethodInterface switch($this->autodetectTokenType()) { case BearerTokenTypeEnum::JsonWebToken: + $this->jwt->decode(); + $payload = $this->jwt->getPayload(); if ( $payload['sub'] ?? false) { - $request = $request->withAttribute('authentication_middleware:user_id', $payload['sub']); + $request = $request + ->withAttribute('authentication_middleware:method', AuthenticationMethodEnum::ForceLogin) + ->withAttribute('authentication_middleware:jwt', $payload) + ->withAttribute('authentication_middleware:user_id', $payload['sub']); } else { throw new \InvalidArgumentException("Given JsonWebToken is missing a 'sub' key (which concords to user id)"); @@ -37,6 +43,8 @@ class BearerMethod implements MethodInterface case BearerTokenTypeEnum::UniqueKey: # @TODO break; + + default: } return $request; diff --git a/src/Authorize/HeaderAuthentication.php b/src/Authorize/HeaderAuthentication.php index 81f161a..74a14dd 100644 --- a/src/Authorize/HeaderAuthentication.php +++ b/src/Authorize/HeaderAuthentication.php @@ -62,7 +62,7 @@ class HeaderAuthentication implements AuthorizeMethodInterface } } }*/ - + return $request->hasHeader('authorization'); } } \ No newline at end of file diff --git a/src/Entity/User.php b/src/Entity/User.php index e5c87c1..469e3dc 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -48,12 +48,12 @@ abstract class User implements UserInterface { #[Field] public string $password; - #[Field\UpdatedAt(name: "updated_at", readonly: true)] - public ? Datetime $updatedAt; - #[Field\CreatedAt(name: "created_at", readonly: true)] public Datetime $createdAt; + #[Field\UpdatedAt(name: "updated_at", readonly: true)] + public ? Datetime $updatedAt; + public bool $logged = false; public function __toString() : string diff --git a/src/Exception/InvalidUserException.php b/src/Exception/InvalidUserException.php new file mode 100644 index 0000000..8472f59 --- /dev/null +++ b/src/Exception/InvalidUserException.php @@ -0,0 +1,5 @@ +getAttribute('authentication_middleware:user_id')) { - $this->authenticator->loadUser($id); - - if ( ! $this->authenticator->user->isLoaded() ) { - throw new \Exception("Given user id do not match with an existing/active user"); - } - } - - switch($request->getAttribute('authentication_middleware:method')) { - case AuthenticationMethodEnum::ForceLogin: - $this->authenticator->login(); - break; - - case AuthenticationMethodEnum::UsernamePassword: - $this->authenticator->authenticate($request->getAttribute('authentication_middleware:username'), $request->getAttribute('authentication_middleware:password')); - break; - } + $this->launchAuthentication($request); } - catch(\Exception $e) { + catch(InvalidUserException $e) { return call_user_func($this->loginFailedResponse, [ 'api.error_message' => $e->getMessage() ]); } return $handler->handle($request); } + + protected function launchAuthentication(ServerRequestInterface $request) : void + { + if (null !== $id = $request->getAttribute('authentication_middleware:user_id')) { + + $this->authenticator->loadUser($id); + + if ( ! $this->authenticator->user->isLoaded() ) { + throw new InvalidUserException("Given user id do not match with an existing/active user"); + } + } + + switch($request->getAttribute('authentication_middleware:method')) { + case AuthenticationMethodEnum::ForceLogin: + $this->authenticator->login(); + break; + + case AuthenticationMethodEnum::UsernamePassword: + $this->authenticator->authenticate($request->getAttribute('authentication_middleware:username'), $request->getAttribute('authentication_middleware:password')); + break; + } + } }