Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error handling: Fix status codes #1854

Merged
merged 5 commits into from
Sep 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/Api/Controller/ListNotificationsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
use Flarum\Discussion\Discussion;
use Flarum\Http\UrlGenerator;
use Flarum\Notification\NotificationRepository;
use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\AssertPermissionTrait;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;

class ListNotificationsController extends AbstractListController
{
use AssertPermissionTrait;

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -67,9 +69,7 @@ protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');

if ($actor->isGuest()) {
throw new PermissionDeniedException;
}
$this->assertRegistered($actor);

$actor->markNotificationsAsRead()->save();

Expand Down
8 changes: 4 additions & 4 deletions src/Api/Controller/ListUsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@
use Flarum\Api\Serializer\UserSerializer;
use Flarum\Http\UrlGenerator;
use Flarum\Search\SearchCriteria;
use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\AssertPermissionTrait;
use Flarum\User\Search\UserSearcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;

class ListUsersController extends AbstractListController
{
use AssertPermissionTrait;

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -70,9 +72,7 @@ protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');

if ($actor->cannot('viewUserList')) {
throw new PermissionDeniedException;
}
$this->assertCan($actor, 'viewUserList');

$query = Arr::get($this->extractFilter($request), 'q');
$sort = $this->extractSort($request);
Expand Down
1 change: 1 addition & 0 deletions src/Foundation/ErrorServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public function register()

// 401 Unauthorized
'invalid_access_token' => 401,
'not_authenticated' => 401,

// 403 Forbidden
'forbidden' => 403,
Expand Down
49 changes: 32 additions & 17 deletions src/User/AssertPermissionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@

namespace Flarum\User;

use Flarum\User\Exception\NotAuthenticatedException;
use Flarum\User\Exception\PermissionDeniedException;

trait AssertPermissionTrait
{
/**
* @param $condition
* Ensure the current user is allowed to do something.
*
* If the condition is not met, an exception will be thrown that signals the
* lack of permissions. This is about *authorization*, i.e. retrying such a
* request / operation without a change in permissions (or using another
* user account) is pointless.
*
* @param bool $condition
* @throws PermissionDeniedException
*/
protected function assertPermission($condition)
Expand All @@ -27,36 +35,43 @@ protected function assertPermission($condition)
}

/**
* Ensure the given actor is authenticated.
*
* This will throw an exception for guest users, signaling that
* *authorization* failed. Thus, they could retry the operation after
* logging in (or using other means of authentication).
*
* @param User $actor
* @param string $ability
* @param mixed $arguments
* @throws PermissionDeniedException
* @throws NotAuthenticatedException
*/
protected function assertCan(User $actor, $ability, $arguments = [])
{
$this->assertPermission($actor->can($ability, $arguments));
}

/**
* @param User $actor
* @throws \Flarum\User\Exception\PermissionDeniedException
*/
protected function assertGuest(User $actor)
protected function assertRegistered(User $actor)
{
$this->assertPermission($actor->isGuest());
if ($actor->isGuest()) {
throw new NotAuthenticatedException;
}
}

/**
* @param User $actor
* @param string $ability
* @param mixed $arguments
* @throws NotAuthenticatedException
* @throws PermissionDeniedException
*/
protected function assertRegistered(User $actor)
protected function assertCan(User $actor, $ability, $arguments = [])
{
$this->assertPermission(! $actor->isGuest());
// For non-authenticated users, we throw a different exception to signal
// that logging in may help.
$this->assertRegistered($actor);

// If we're logged in, then we need to communicate that the current
// account simply does not have enough permissions.
$this->assertPermission($actor->can($ability, $arguments));
}

/**
* @param User $actor
* @throws NotAuthenticatedException
* @throws PermissionDeniedException
*/
protected function assertAdmin(User $actor)
Expand Down
2 changes: 1 addition & 1 deletion src/User/Command/RegisterUserHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function handle(RegisterUser $command)
$data = $command->data;

if (! $this->settings->get('allow_sign_up')) {
$this->assertAdmin($actor);
$this->assertPermission($actor->can('administrate'));
}

$password = Arr::get($data, 'attributes.password');
Expand Down
23 changes: 23 additions & 0 deletions src/User/Exception/NotAuthenticatedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Flarum\User\Exception;

use Exception;
use Flarum\Foundation\KnownError;

class NotAuthenticatedException extends Exception implements KnownError
{
public function getType(): string
{
return 'not_authenticated';
}
}
2 changes: 1 addition & 1 deletion tests/integration/api/Auth/AuthenticateWithApiKeyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function cannot_authorize_without_key()

$response = $api->send(CreateGroupController::class, new Guest);

$this->assertEquals(403, $response->getStatusCode());
$this->assertEquals(401, $response->getStatusCode());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function admin_can_create_group()
/**
* @test
*/
public function unauthorized_user_cannot_create_group()
public function normal_user_cannot_create_group()
{
$this->actor = User::find(2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function disallows_index_for_guest()
{
$response = $this->callWith();

$this->assertEquals(403, $response->getStatusCode());
$this->assertEquals(401, $response->getStatusCode());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function disallows_index_for_guest()
{
$response = $this->callWith();

$this->assertEquals(403, $response->getStatusCode());
$this->assertEquals(401, $response->getStatusCode());
}

/**
Expand Down