From 9c8f8c2d989d3fe489e073a7a5b3bb76ad6db467 Mon Sep 17 00:00:00 2001 From: konradoboza Date: Fri, 7 Jun 2024 12:35:17 +0200 Subject: [PATCH] improved UnauthorizedException throwing, introduced dedicated exception --- src/bundle/EventListener/CsrfListener.php | 9 +++----- .../Exceptions/UnauthorizedException.php | 23 +++++++++++++++++++ .../Authenticator/RestAuthenticator.php | 6 ++++- src/lib/Server/Controller/JWT.php | 4 ++-- .../Server/Controller/SessionController.php | 15 +++++------- .../UnauthorizedException.php | 10 +++----- .../bundle/EventListener/CsrfListenerTest.php | 2 +- 7 files changed, 43 insertions(+), 26 deletions(-) create mode 100644 src/contracts/Exceptions/UnauthorizedException.php diff --git a/src/bundle/EventListener/CsrfListener.php b/src/bundle/EventListener/CsrfListener.php index 81df858b..057ca5ac 100644 --- a/src/bundle/EventListener/CsrfListener.php +++ b/src/bundle/EventListener/CsrfListener.php @@ -9,7 +9,7 @@ namespace Ibexa\Bundle\Rest\EventListener; use Ibexa\Bundle\Rest\RestEvents; -use Ibexa\Core\Base\Exceptions\UnauthorizedException; +use Ibexa\Contracts\Rest\Exceptions\UnauthorizedException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; @@ -59,7 +59,7 @@ public static function getSubscribedEvents(): array /** * This method validates CSRF token if CSRF protection is enabled. * - * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException */ public function onKernelRequest(RequestEvent $event): void { @@ -86,10 +86,7 @@ public function onKernelRequest(RequestEvent $event): void } if (!$this->checkCsrfToken($request)) { - throw new UnauthorizedException( - 'Missing or invalid CSRF token', - $request->getMethod() . ' ' . $request->getPathInfo() - ); + throw new UnauthorizedException('Missing or invalid CSRF token'); } // Dispatching event so that CSRF token intention can be injected into Legacy Stack diff --git a/src/contracts/Exceptions/UnauthorizedException.php b/src/contracts/Exceptions/UnauthorizedException.php new file mode 100644 index 00000000..4a0f6d85 --- /dev/null +++ b/src/contracts/Exceptions/UnauthorizedException.php @@ -0,0 +1,23 @@ +getMessage()); } public function isInteractive(): bool diff --git a/src/lib/Server/Controller/JWT.php b/src/lib/Server/Controller/JWT.php index 8faf40e4..e0b08723 100644 --- a/src/lib/Server/Controller/JWT.php +++ b/src/lib/Server/Controller/JWT.php @@ -8,7 +8,7 @@ namespace Ibexa\Rest\Server\Controller; -use Ibexa\Core\Base\Exceptions\UnauthorizedException; +use Ibexa\Contracts\Rest\Exceptions\UnauthorizedException; use Ibexa\Core\MVC\Symfony\Security\Authentication\AuthenticatorInterface; use Ibexa\Rest\Message; use Ibexa\Rest\Server\Controller as RestController; @@ -57,7 +57,7 @@ public function createToken(Request $request): Values\JWT return new Values\JWT($jwtToken); } catch (AuthenticationException $e) { $this->getAuthenticator()->logout($request); - throw new UnauthorizedException('Invalid login or password', $request->getPathInfo()); + throw new UnauthorizedException('Invalid login or password'); } } diff --git a/src/lib/Server/Controller/SessionController.php b/src/lib/Server/Controller/SessionController.php index a6a0c19a..588ff22c 100644 --- a/src/lib/Server/Controller/SessionController.php +++ b/src/lib/Server/Controller/SessionController.php @@ -11,7 +11,7 @@ use Ibexa\Contracts\Core\Repository\PermissionResolver; use Ibexa\Contracts\Core\Repository\UserService; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; -use Ibexa\Core\Base\Exceptions\UnauthorizedException; +use Ibexa\Contracts\Rest\Exceptions\UnauthorizedException; use Ibexa\Rest\Server\Controller; use Ibexa\Rest\Server\Exceptions; use Ibexa\Rest\Server\Security\CsrfTokenManager; @@ -47,7 +47,7 @@ public function createSessionAction(Request $request): RestValue $token = $this->securityTokenStorage->getToken(); if ($token === null) { - throw new UnauthorizedException('authorization', 'The current user is not authenticated.'); + throw new UnauthorizedException('The current user is not authenticated.'); } /** @var \Ibexa\Core\MVC\Symfony\Security\User $user */ @@ -64,9 +64,9 @@ public function createSessionAction(Request $request): RestValue // Already logged in with another user, this will be converted to HTTP status 409 return new Values\Conflict(); } catch (AuthenticationException $e) { - throw new UnauthorizedException('Invalid login or password', $request->getPathInfo()); + throw new UnauthorizedException('Invalid login or password'); } catch (AccessDeniedException $e) { - throw new UnauthorizedException($e->getMessage(), $request->getPathInfo()); + throw new UnauthorizedException($e->getMessage()); } } @@ -159,7 +159,7 @@ private function hasStoredCsrfToken(): bool /** * Checks the presence / validity of the CSRF token. * - * @throws \Ibexa\Core\Base\Exceptions\UnauthorizedException if the token is missing or invalid + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException if the token is missing or invalid */ private function checkCsrfToken(Request $request): void { @@ -184,10 +184,7 @@ private function getCsrfToken(): string private function createInvalidCsrfTokenException(Request $request): UnauthorizedException { - return new UnauthorizedException( - 'Missing or invalid CSRF token', - $request->getMethod() . ' ' . $request->getPathInfo() - ); + return new UnauthorizedException('Missing or invalid CSRF token'); } private function logout(Request $request): Response diff --git a/src/lib/Server/Output/ValueObjectVisitor/UnauthorizedException.php b/src/lib/Server/Output/ValueObjectVisitor/UnauthorizedException.php index 0e679b89..6bddc8c4 100644 --- a/src/lib/Server/Output/ValueObjectVisitor/UnauthorizedException.php +++ b/src/lib/Server/Output/ValueObjectVisitor/UnauthorizedException.php @@ -4,20 +4,16 @@ * @copyright Copyright (C) Ibexa AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ +declare(strict_types=1); namespace Ibexa\Rest\Server\Output\ValueObjectVisitor; /** * UnauthorizedException value object visitor. */ -class UnauthorizedException extends Exception +final class UnauthorizedException extends Exception { - /** - * Returns HTTP status code. - * - * @return int - */ - protected function getStatus() + protected function getStatus(): int { return 401; } diff --git a/tests/bundle/EventListener/CsrfListenerTest.php b/tests/bundle/EventListener/CsrfListenerTest.php index 50b8df83..e7d5d6d2 100644 --- a/tests/bundle/EventListener/CsrfListenerTest.php +++ b/tests/bundle/EventListener/CsrfListenerTest.php @@ -9,7 +9,7 @@ namespace Ibexa\Tests\Bundle\Rest\EventListener; use Ibexa\Bundle\Rest\EventListener\CsrfListener; -use Ibexa\Core\Base\Exceptions\UnauthorizedException; +use Ibexa\Contracts\Rest\Exceptions\UnauthorizedException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\HeaderBag; use Symfony\Component\HttpFoundation\ParameterBag;