Skip to content

Commit d973f84

Browse files
committed
fix: corrected 401/403 behaviour
If a user's session has expired, these methods will throw a ForbiddenException (403 Forbidden) instead of an UnauthorizedHttpException (401 Unauthorized), which is semantically incorrect.
1 parent eea6d9e commit d973f84

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

phpmyfaq/src/phpMyFAQ/Controller/AbstractController.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,14 @@ protected function userIsSuperAdmin(): void
183183
}
184184

185185
/**
186-
* @throws ForbiddenException
186+
* @throws UnauthorizedHttpException|ForbiddenException
187187
*/
188188
protected function userHasGroupPermission(): void
189189
{
190+
if (!$this->currentUser->isLoggedIn()) {
191+
throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');
192+
}
193+
190194
$currentUser = $this->currentUser;
191195
if (
192196
!$currentUser->perm->hasPermission($currentUser->getUserId(), PermissionType::USER_ADD->value)
@@ -199,10 +203,14 @@ protected function userHasGroupPermission(): void
199203
}
200204

201205
/**
202-
* @throws ForbiddenException
206+
* @throws UnauthorizedHttpException|ForbiddenException
203207
*/
204208
protected function userHasUserPermission(): void
205209
{
210+
if (!$this->currentUser->isLoggedIn()) {
211+
throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');
212+
}
213+
206214
$currentUser = $this->currentUser;
207215
if (
208216
!$currentUser->perm->hasPermission($currentUser->getUserId(), PermissionType::USER_ADD->value)
@@ -214,10 +222,14 @@ protected function userHasUserPermission(): void
214222
}
215223

216224
/**
217-
* @throws ForbiddenException
225+
* @throws UnauthorizedHttpException|ForbiddenException
218226
*/
219227
protected function userHasPermission(PermissionType $permissionType): void
220228
{
229+
if (!$this->currentUser->isLoggedIn()) {
230+
throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');
231+
}
232+
221233
$currentUser = $this->currentUser;
222234
if (!$currentUser->perm->hasPermission($currentUser->getUserId(), $permissionType->value)) {
223235
throw new ForbiddenException(message: sprintf('User has no "%s" permission.', $permissionType->name));

tests/phpMyFAQ/Controller/AbstractControllerTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,12 @@ public function testUserIsSuperAdminSucceedsWhenSuperAdmin(): void
246246

247247
public function testUserHasGroupPermissionThrowsExceptionWhenMissingPermissions(): void
248248
{
249+
// Mock that user is logged in (so we get to the permission check)
250+
$this->currentUserMock
251+
->expects($this->once())
252+
->method('isLoggedIn')
253+
->willReturn(true);
254+
249255
$this->currentUserMock
250256
->expects($this->once()) // Only called once since the exception is thrown on the first check
251257
->method('getUserId')
@@ -265,6 +271,12 @@ public function testUserHasGroupPermissionThrowsExceptionWhenMissingPermissions(
265271

266272
public function testUserHasGroupPermissionSucceedsWhenAllPermissionsPresent(): void
267273
{
274+
// Mock that user is logged in
275+
$this->currentUserMock
276+
->expects($this->once())
277+
->method('isLoggedIn')
278+
->willReturn(true);
279+
268280
$this->currentUserMock
269281
->expects($this->exactly(4))
270282
->method('getUserId')
@@ -291,6 +303,12 @@ public function testUserHasGroupPermissionSucceedsWhenAllPermissionsPresent(): v
291303

292304
public function testUserHasUserPermissionThrowsExceptionWhenMissingPermissions(): void
293305
{
306+
// Mock that user is logged in (so we get to the permission check)
307+
$this->currentUserMock
308+
->expects($this->once())
309+
->method('isLoggedIn')
310+
->willReturn(true);
311+
294312
$this->currentUserMock
295313
->expects($this->once()) // Only called once since exception is thrown on first check
296314
->method('getUserId')
@@ -310,6 +328,12 @@ public function testUserHasUserPermissionThrowsExceptionWhenMissingPermissions()
310328

311329
public function testUserHasUserPermissionSucceedsWhenAllPermissionsPresent(): void
312330
{
331+
// Mock that user is logged in
332+
$this->currentUserMock
333+
->expects($this->once())
334+
->method('isLoggedIn')
335+
->willReturn(true);
336+
313337
$this->currentUserMock
314338
->expects($this->exactly(3))
315339
->method('getUserId')
@@ -335,6 +359,12 @@ public function testUserHasUserPermissionSucceedsWhenAllPermissionsPresent(): vo
335359

336360
public function testUserHasPermissionThrowsExceptionWhenMissingPermission(): void
337361
{
362+
// Mock that user is logged in (so we get to the permission check)
363+
$this->currentUserMock
364+
->expects($this->once())
365+
->method('isLoggedIn')
366+
->willReturn(true);
367+
338368
$permissionType = PermissionType::FAQ_ADD;
339369
$this->currentUserMock
340370
->expects($this->once())
@@ -354,6 +384,12 @@ public function testUserHasPermissionThrowsExceptionWhenMissingPermission(): voi
354384

355385
public function testUserHasPermissionSucceedsWhenPermissionPresent(): void
356386
{
387+
// Mock that user is logged in
388+
$this->currentUserMock
389+
->expects($this->once())
390+
->method('isLoggedIn')
391+
->willReturn(true);
392+
357393
$permissionType = PermissionType::FAQ_ADD;
358394
$this->currentUserMock
359395
->expects($this->once())
@@ -512,6 +548,12 @@ public static function permissionDataProvider(): array
512548
#[DataProvider('permissionDataProvider')]
513549
public function testUserHasPermissionWithDifferentPermissionTypes(PermissionType $permissionType): void
514550
{
551+
// Mock that user is logged in
552+
$this->currentUserMock
553+
->expects($this->once())
554+
->method('isLoggedIn')
555+
->willReturn(true);
556+
515557
$this->currentUserMock
516558
->expects($this->once())
517559
->method('getUserId')

0 commit comments

Comments
 (0)