Commit 38278f8d authored by Jacob Priddy's avatar Jacob Priddy 👌

Fix some permissions issues and do documentation for Attempts

parent 1d8c927f
......@@ -20,11 +20,19 @@ class UnauthenticatedResponseStrategy extends Strategy
return null;
}
return [[
'content' => [
'message' => 'Unauthenticated',
return [
[
'content' => [
'message' => 'Unauthenticated',
],
'status' => 401,
],
'status' => 401,
]];
[
'content' => [
'message' => 'Unauthorized',
],
'status' => 403,
]
];
}
}
......@@ -2,14 +2,38 @@
namespace App\Http\Controllers;
use App\Guards\ApiGuard;
use Illuminate\Http\JsonResponse;
use Source\Authorization\Permissions;
use Source\Gateways\Users\UsersRepository;
use Source\Gateways\Groups\GroupsRepository;
use Source\Gateways\GroupUser\GroupUserRepository;
use Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase;
use Source\UseCases\Attempts\APIPresenter as GetAttemptsAPIPresenter;
/**
* @group Door Attempt Logs
*
* APIs for viewing attempts on doors. An attempt is a failed code entry that did not match any users.
*/
class AttemptsController extends ApiController
{
/**
* Get Attempts
*
* This route filters attempts based off of starting date, ending date, or door id.
* If only start is supplied, all attempts after the start date are given. If only end
* is supplied, all attempts before the start date are given. If both dates are supplied,
* all attempts between the given dates are returned. This route is paginated.
*
* @authenticated
* @paginated
* @queryParam start date The beginning date to filter attempts by. Example: 2020-06-02 08:11:45
* @queryParam end date The ending date to filter attempts by. Example: 2020-06-02 08:11:45
* @queryParam door_id int The door id to filter on. Example: 1
*
* @response 422 {"message":"The given data was invalid.","errors":{"start":["The start is not a valid date."],"end":["The end is not a valid date."],"door_id":["The door id must be an integer."]}}
*
* @param \Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase $attempts
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException
......
......@@ -2,12 +2,7 @@
namespace App\Http\Controllers;
use App\Guards\ApiGuard;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Contracts\Auth\Guard;
use Source\Authorization\Authorizer;
use Source\Exceptions\AuthenticationException;
use Source\UseCases\Users\GetUser\GetUserUseCase;
use Source\UseCases\Tokens\GetTokens\GetTokensUseCase;
use Source\UseCases\Users\UpdateUser\UpdateUserUseCase;
......@@ -26,34 +21,6 @@ use Source\UseCases\GroupUser\GetUserGroups\APIPresenter as GetUserGroupsAPIPres
*/
class MeController extends ApiController
{
/**
* @var \Illuminate\Contracts\Auth\Guard
*/
protected Guard $guard;
protected string $userId;
/**
* @param \Illuminate\Http\Request $request
* @param \Source\Authorization\Authorizer $authorizer
* @param \App\Guards\ApiGuard $guard
* @throws \Source\Exceptions\AuthenticationException
*/
public function __construct(Request $request, Authorizer $authorizer, ApiGuard $guard)
{
parent::__construct($request, $authorizer);
$this->guard = $guard;
$userId = $this->guard->id();
if (!$userId) {
throw new AuthenticationException();
}
$this->userId = $userId;
$this->authorizer->setCurrentUserId($this->userId);
}
/**
* Get current user
*
......@@ -69,7 +36,7 @@ class MeController extends ApiController
{
$presenter = new GetUserAPIPresenter();
$useCase->get($this->userId, $presenter);
$useCase->get($this->authorizer->getCurrentUserId(), $presenter);
return $this->respondWithData($presenter->getViewModel());
}
......@@ -90,7 +57,7 @@ class MeController extends ApiController
{
$presenter = new GetUserGroupsAPIPresenter();
$useCase->getGroupsForUser($this->userId, $presenter);
$useCase->getGroupsForUser($this->authorizer->getCurrentUserId(), $presenter);
return $this->respondWithData($presenter->getViewModel());
}
......@@ -121,7 +88,7 @@ class MeController extends ApiController
]);
$presenter = new UpdateUserAPIPresenter();
$useCase->update($this->userId, $this->request->all(), $presenter);
$useCase->update($this->authorizer->getCurrentUserId(), $this->request->all(), $presenter);
if ($presenter->hasError()) {
return $this->respondWithError($presenter->getViewModel()['message']);
......@@ -146,7 +113,7 @@ class MeController extends ApiController
{
$presenter = new GetTokensApiPresenter();
$userTokens->filter($this->userId, null, $presenter);
$userTokens->filter($this->authorizer->getCurrentUserId(), null, $presenter);
return $this->respondWithData($presenter->getViewModel());
}
......@@ -181,7 +148,7 @@ class MeController extends ApiController
{
$presenter = new DoorUserMePresenter();
$userDoorAccessUseCase->getUserDoorRelationships($this->userId, $presenter);
$userDoorAccessUseCase->getUserDoorRelationships($this->authorizer->getCurrentUserId(), $presenter);
return $this->respondWithData($presenter->getViewModel());
}
......
......@@ -25,6 +25,11 @@ use Source\UseCases\GroupUser\GetUserGroups\APIPresenter as GetUserGroupsAPIPres
use Source\UseCases\GroupUser\AddUserToGroup\APIPresenter as AddUserToGroupAPIPresenter;
use Source\UseCases\GroupUser\RemoveUserFromGroup\APIPresenter as RemoveUserFromGroupAPIPresenter;
/**
* @group User Management
*
* Set of APIs to manage users on the doorcode system
*/
class UsersController extends ApiController
{
/**
......@@ -138,6 +143,14 @@ class UsersController extends ApiController
}
/**
* User Delete
*
* Deletes a user from the database.
*
* @authenticated
* @urlParam userId required The userId to delete. Example: 2
*
*
* @param \Source\UseCases\Users\DeleteUser\DeleteUserUseCase $deleteUser
* @param string $userId
* @return \Illuminate\Http\JsonResponse
......@@ -180,6 +193,10 @@ class UsersController extends ApiController
}
/**
* Remove User From Group
*
* This route removes a user from a group.
*
* @param \Source\UseCases\GroupUser\RemoveUserFromGroup\RemoveUserFromGroupUseCase $useCase
* @param string $userId
* @param string $groupId
......
......@@ -60,6 +60,14 @@ class ApiAuthorizer implements Authorizer
}
}
/**
* @inheritDoc
*/
public function getCurrentUserId(): ?string
{
return $this->currentUserId;
}
/**
* @inheritDoc
*/
......@@ -220,6 +228,9 @@ class ApiAuthorizer implements Authorizer
// Only admins can create or remove other admins
if ($group->hasTitleOf(Permissions::ADMIN)) {
$this->protect(Permissions::ADMIN);
if ($this->getCurrentUserId() === $userId) {
throw new AuthorizationException('You cannot modify your own admin privileges');
}
}
}
......
......@@ -10,6 +10,11 @@ interface Authorizer
*/
public function setCurrentUserId(?string $id): void;
/**
* @return string|null
*/
public function getCurrentUserId(): ?string;
/**
* Returns list of permission from \Source\Authorization\Permissions that the user has
*
......
......@@ -23,7 +23,7 @@ class AuthorizerServiceProvider extends ServiceProvider implements DeferrablePro
*/
public function register()
{
$this->app->singleton(Authorizer::class, static function (Application $app) {
$this->app->bind(Authorizer::class, static function (Application $app) {
return new ApiAuthorizer(
$app->make(ApiGuard::class)->id(),
$app->make(UsersRepository::class),
......
......@@ -9,6 +9,7 @@ use Source\Entities\Password;
use Source\Entities\HashedSearchable;
use Source\Gateways\Users\UsersRepository;
use Source\Exceptions\EntityExistsException;
use Source\Exceptions\AuthorizationException;
class CreateUser implements CreateUserUseCase
{
......@@ -54,6 +55,10 @@ class CreateUser implements CreateUserUseCase
$expires
);
if ($user->hasFirstNameOf('admin')) {
throw new AuthorizationException('You cannot create a user with the first name of admin');
}
if (!($user = $this->usersRepository->create($user))) {
throw new EntityExistsException();
......
......@@ -9,6 +9,7 @@ use Source\Entities\Password;
use Source\Authorization\Authorizer;
use Source\Entities\HashedSearchable;
use Source\Gateways\Users\UsersRepository;
use Source\Exceptions\AuthorizationException;
use Source\Exceptions\EntityNotFoundException;
class UpdateUser implements UpdateUserUseCase
......@@ -70,6 +71,10 @@ class UpdateUser implements UpdateUserUseCase
$user->getUpdatedAt()
);
if ($newUser->hasFirstNameOf('admin')) {
throw new AuthorizationException('You cannot create a user with the first name of admin');
}
$response = new ResponseModel();
$returnedUser = $this->usersRepository->update($user->getId(), $newUser);
......
......@@ -12,12 +12,22 @@ class AuthorizerStub implements Authorizer
protected bool $adminRightsProtected = false;
protected ?string $id = null;
/**
* @param string|null $id
*/
public function setCurrentUserId(?string $id): void
{
// nothing for now
$this->id = $id;
}
/**
* @inheritDoc
*/
public function getCurrentUserId(): ?string
{
return $this->id;
}
public function setNext(bool $next = true): void
......
......@@ -19,7 +19,7 @@ class UpdateCurrentUserApiTest extends AuthenticatesWithApplicationTestCase
{
/**
* @var \Illuminate\Foundation\Testing\TestResponse
* @var \Illuminate\Testing\TestResponse
*/
protected TestResponse $response;
......
......@@ -56,11 +56,13 @@ class AuthenticatesWithApplicationTestCase extends TestCase
/**
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Source\Exceptions\EntityExistsException
*/
protected function authenticate(): void
{
$this->authUser = new User(1, '', '', '', '', '');
$this->usersRepository->create($this->authUser);
$this->authorizer->setCurrentUserId($this->authUser->getId());
$this->tokens->create(new Token(1, 1, 'token', 'name'));
$this->authToken = 'token';
......@@ -80,6 +82,7 @@ class AuthenticatesWithApplicationTestCase extends TestCase
/**
* @param bool $succeed
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Source\Exceptions\EntityExistsException
*/
protected function authorize(bool $succeed = true): void
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment