]> BookStack Code Mirror - bookstack/commitdiff
Added expiry checking to API token auth
authorDan Brown <redacted>
Mon, 30 Dec 2019 19:51:41 +0000 (19:51 +0000)
committerDan Brown <redacted>
Mon, 30 Dec 2019 19:51:41 +0000 (19:51 +0000)
- Added test to cover to ensure its checked going forward

app/Api/ApiTokenGuard.php
resources/lang/en/errors.php
tests/Api/ApiAuthTest.php
tests/TestsApi.php

index ba0b4b5dd5160581a3e1b975445c643c60c5c46b..e0a50ebe3d2a03f7e90a8b4362ff15283bb73849 100644 (file)
@@ -6,6 +6,7 @@ use BookStack\Exceptions\ApiAuthException;
 use Illuminate\Auth\GuardHelpers;
 use Illuminate\Contracts\Auth\Authenticatable;
 use Illuminate\Contracts\Auth\Guard;
 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;
 
 use Illuminate\Support\Facades\Hash;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -125,6 +126,11 @@ class ApiTokenGuard implements Guard
             throw new ApiAuthException(trans('errors.api_incorrect_token_secret'));
         }
 
             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);
         }
         if (!$token->user->can('access-api')) {
             throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403);
         }
index 85c498f4831242e10afdab2720f76cefbdadae60..bb7b6148c9e5c14eb6ba42862e175c58bd512047 100644 (file)
@@ -95,5 +95,6 @@ return [
     'api_user_token_not_found' => 'No matching API token was found for the provided authorization token',
     'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect',
     'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls',
     'api_user_token_not_found' => 'No matching API token was found for the provided authorization token',
     'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect',
     'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls',
+    'api_user_token_expired' => 'The authorization token used has expired',
 
 ];
 
 ];
index ef975d556b654faa3e59929d9a5353e4860edab5..30d7f4ead4e855478ba2209b443d919d5070b53c 100644 (file)
@@ -3,6 +3,7 @@
 namespace Tests;
 
 use BookStack\Auth\Permissions\RolePermission;
 namespace Tests;
 
 use BookStack\Auth\Permissions\RolePermission;
+use Carbon\Carbon;
 
 class ApiAuthTest extends TestCase
 {
 
 class ApiAuthTest extends TestCase
 {
@@ -52,7 +53,7 @@ class ApiAuthTest extends TestCase
 
     public function test_api_access_permission_required_to_access_api()
     {
 
     public function test_api_access_permission_required_to_access_api()
     {
-        $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]);
+        $resp = $this->get($this->endpoint, $this->apiAuthHeader());
         $resp->assertStatus(200);
         auth()->logout();
 
         $resp->assertStatus(200);
         auth()->logout();
 
@@ -60,12 +61,27 @@ class ApiAuthTest extends TestCase
         $editorRole = $this->getEditor()->roles()->first();
         $editorRole->detachPermission($accessApiPermission);
 
         $editorRole = $this->getEditor()->roles()->first();
         $editorRole->detachPermission($accessApiPermission);
 
-        $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]);
+        $resp = $this->get($this->endpoint, $this->apiAuthHeader());
         $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403));
     }
 
         $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403));
     }
 
+    public function test_token_expiry_checked()
+    {
+        $editor = $this->getEditor();
+        $token = $editor->apiTokens()->first();
+
+        $resp = $this->get($this->endpoint, $this->apiAuthHeader());
+        $resp->assertStatus(200);
+        auth()->logout();
+
+        $token->expires_at = Carbon::now()->subDay()->format('Y-m-d');
+        $token->save();
+
+        $resp = $this->get($this->endpoint, $this->apiAuthHeader());
+        $resp->assertJson($this->errorResponse("The authorization token used has expired", 403));
+    }
 
 
-    public function test_email_confirmation_checked_on_auth_requets()
+    public function test_email_confirmation_checked_using_api_auth()
     {
         $editor = $this->getEditor();
         $editor->email_confirmed = false;
     {
         $editor = $this->getEditor();
         $editor->email_confirmed = false;
@@ -74,7 +90,7 @@ class ApiAuthTest extends TestCase
         // Set settings and get user instance
         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
 
         // Set settings and get user instance
         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
 
-        $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]);
+        $resp = $this->get($this->endpoint, $this->apiAuthHeader());
         $resp->assertStatus(401);
         $resp->assertJson($this->errorResponse("The email address for the account in use needs to be confirmed", 401));
     }
         $resp->assertStatus(401);
         $resp->assertJson($this->errorResponse("The email address for the account in use needs to be confirmed", 401));
     }
index 2bc751f543f537e6d86605d5bf2b29b44bfecb4f..4afcbdf220a5a78c6a2dce92b465554dcceef421 100644 (file)
@@ -13,4 +13,11 @@ trait TestsApi
         return ["error" => ["code" => $code, "message" => $messge]];
     }
 
         return ["error" => ["code" => $code, "message" => $messge]];
     }
 
+    protected function apiAuthHeader()
+    {
+        return [
+            "Authorization" => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"
+        ];
+    }
+
 }
\ No newline at end of file
 }
\ No newline at end of file