X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/3de55ee6454667e2d4b3cb866625a165ccb9aee3..refs/pull/1881/head:/app/Http/Middleware/ApiAuthenticate.php diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php index 3e68cb3ae..15962b3b0 100644 --- a/app/Http/Middleware/ApiAuthenticate.php +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -2,77 +2,65 @@ namespace BookStack\Http\Middleware; -use BookStack\Api\ApiToken; -use BookStack\Http\Request; +use BookStack\Exceptions\ApiAuthException; +use BookStack\Exceptions\UnauthorizedException; use Closure; -use Hash; +use Illuminate\Http\Request; class ApiAuthenticate { + use ChecksForEmailConfirmation; /** * Handle an incoming request. */ public function handle(Request $request, Closure $next) { - // TODO - Look to extract a lot of the logic here into a 'Guard' - // Ideally would like to be able to request API via browser without having to boot - // the session middleware (in Kernel). + // Validate the token and it's users API access + try { + $this->ensureAuthorizedBySessionOrToken(); + } catch (UnauthorizedException $exception) { + return $this->unauthorisedResponse($exception->getMessage(), $exception->getCode()); + } -// $sessionCookieName = config('session.cookie'); -// if ($request->cookies->has($sessionCookieName)) { -// $sessionCookie = $request->cookies->get($sessionCookieName); -// $sessionCookie = decrypt($sessionCookie, false); -// dd($sessionCookie); -// } + return $next($request); + } + /** + * Ensure the current user can access authenticated API routes, either via existing session + * authentication or via API Token authentication. + * @throws UnauthorizedException + */ + protected function ensureAuthorizedBySessionOrToken(): void + { // Return if the user is already found to be signed in via session-based auth. // This is to make it easy to browser the API via browser after just logging into the system. if (signedInUser()) { - return $next($request); - } - - $authToken = trim($request->header('Authorization', '')); - if (empty($authToken)) { - return $this->unauthorisedResponse(trans('errors.api_no_authorization_found')); - } - - if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { - return $this->unauthorisedResponse(trans('errors.api_bad_authorization_format')); + $this->ensureEmailConfirmedIfRequested(); + if (!auth()->user()->can('access-api')) { + throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); + } + return; } - [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); - $token = ApiToken::query() - ->where('token_id', '=', $id) - ->with(['user'])->first(); - - if ($token === null) { - return $this->unauthorisedResponse(trans('errors.api_user_token_not_found')); - } - - if (!Hash::check($secret, $token->secret)) { - return $this->unauthorisedResponse(trans('errors.api_incorrect_token_secret')); - } + // Set our api guard to be the default for this request lifecycle. + auth()->shouldUse('api'); - if (!$token->user->can('access-api')) { - return $this->unauthorisedResponse(trans('errors.api_user_no_api_permission'), 403); - } - - auth()->login($token->user); - - return $next($request); + // Validate the token and it's users API access + auth()->authenticate(); + $this->ensureEmailConfirmedIfRequested(); } /** * Provide a standard API unauthorised response. */ - protected function unauthorisedResponse(string $message, int $code = 401) + protected function unauthorisedResponse(string $message, int $code) { return response()->json([ 'error' => [ 'code' => $code, 'message' => $message, ] - ], 401); + ], $code); } }