X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/349b4629bef25e4631c1024749726415507b2cd5..refs/pull/2227/head:/app/Api/ApiTokenGuard.php diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php index b347e536a..e0a50ebe3 100644 --- a/app/Api/ApiTokenGuard.php +++ b/app/Api/ApiTokenGuard.php @@ -6,6 +6,7 @@ use BookStack\Exceptions\ApiAuthException; use Illuminate\Auth\GuardHelpers; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Guard; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Hash; use Symfony\Component\HttpFoundation\Request; @@ -33,8 +34,7 @@ class ApiTokenGuard implements Guard { $this->request = $request; } - - + /** * @inheritDoc */ @@ -84,6 +84,24 @@ class ApiTokenGuard implements Guard protected function getAuthorisedUserFromRequest(): Authenticatable { $authToken = trim($this->request->headers->get('Authorization', '')); + $this->validateTokenHeaderValue($authToken); + + [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); + $token = ApiToken::query() + ->where('token_id', '=', $id) + ->with(['user'])->first(); + + $this->validateToken($token, $secret); + + return $token->user; + } + + /** + * Validate the format of the token header value string. + * @throws ApiAuthException + */ + protected function validateTokenHeaderValue(string $authToken): void + { if (empty($authToken)) { throw new ApiAuthException(trans('errors.api_no_authorization_found')); } @@ -91,12 +109,15 @@ class ApiTokenGuard implements Guard if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { throw new ApiAuthException(trans('errors.api_bad_authorization_format')); } + } - [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); - $token = ApiToken::query() - ->where('token_id', '=', $id) - ->with(['user'])->first(); - + /** + * Validate the given secret against the given token and ensure the token + * currently has access to the instance API. + * @throws ApiAuthException + */ + protected function validateToken(?ApiToken $token, string $secret): void + { if ($token === null) { throw new ApiAuthException(trans('errors.api_user_token_not_found')); } @@ -105,11 +126,14 @@ class ApiTokenGuard implements Guard throw new ApiAuthException(trans('errors.api_incorrect_token_secret')); } + $now = Carbon::now(); + if ($token->expires_at <= $now) { + throw new ApiAuthException(trans('errors.api_user_token_expired'), 403); + } + if (!$token->user->can('access-api')) { throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); } - - return $token->user; } /** @@ -132,4 +156,11 @@ class ApiTokenGuard implements Guard return Hash::check($credentials['secret'], $token->secret); } + /** + * "Log out" the currently authenticated user. + */ + public function logout() + { + $this->user = null; + } } \ No newline at end of file