X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/3cacda6762bca67ae2beeb44cdcff39ad6d7ec60..refs/pull/5280/head:/tests/Api/ApiAuthTest.php diff --git a/tests/Api/ApiAuthTest.php b/tests/Api/ApiAuthTest.php index 30d7f4ead..93e4b02e4 100644 --- a/tests/Api/ApiAuthTest.php +++ b/tests/Api/ApiAuthTest.php @@ -1,9 +1,12 @@ getViewer(); + $viewer = $this->users->viewer(); + $this->permissions->grantUserRolePermissions($viewer, ['access-api']); + $resp = $this->get($this->endpoint); $resp->assertStatus(401); - $this->actingAs($viewer, 'web'); + $this->actingAs($viewer, 'standard'); $resp = $this->get($this->endpoint); $resp->assertStatus(200); @@ -27,28 +32,28 @@ class ApiAuthTest extends TestCase { $resp = $this->get($this->endpoint); $resp->assertStatus(401); - $resp->assertJson($this->errorResponse("No authorization token found on the request", 401)); + $resp->assertJson($this->errorResponse('No authorization token found on the request', 401)); } public function test_bad_token_format_throws_error() { - $resp = $this->get($this->endpoint, ['Authorization' => "Token abc123"]); + $resp = $this->get($this->endpoint, ['Authorization' => 'Token abc123']); $resp->assertStatus(401); - $resp->assertJson($this->errorResponse("An authorization token was found on the request but the format appeared incorrect", 401)); + $resp->assertJson($this->errorResponse('An authorization token was found on the request but the format appeared incorrect', 401)); } public function test_token_with_non_existing_id_throws_error() { - $resp = $this->get($this->endpoint, ['Authorization' => "Token abc:123"]); + $resp = $this->get($this->endpoint, ['Authorization' => 'Token abc:123']); $resp->assertStatus(401); - $resp->assertJson($this->errorResponse("No matching API token was found for the provided authorization token", 401)); + $resp->assertJson($this->errorResponse('No matching API token was found for the provided authorization token', 401)); } public function test_token_with_bad_secret_value_throws_error() { $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:123"]); $resp->assertStatus(401); - $resp->assertJson($this->errorResponse("The secret provided for the given used API token is incorrect", 401)); + $resp->assertJson($this->errorResponse('The secret provided for the given used API token is incorrect', 401)); } public function test_api_access_permission_required_to_access_api() @@ -58,16 +63,58 @@ class ApiAuthTest extends TestCase auth()->logout(); $accessApiPermission = RolePermission::getByName('access-api'); - $editorRole = $this->getEditor()->roles()->first(); + $editorRole = $this->users->editor()->roles()->first(); $editorRole->detachPermission($accessApiPermission); $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->assertStatus(403); + $resp->assertJson($this->errorResponse('The owner of the used API token does not have permission to make API calls', 403)); + } + + public function test_api_access_permission_required_to_access_api_with_session_auth() + { + $editor = $this->users->editor(); + $this->actingAs($editor, 'standard'); + + $resp = $this->get($this->endpoint); + $resp->assertStatus(200); + auth('standard')->logout(); + + $accessApiPermission = RolePermission::getByName('access-api'); + $editorRole = $this->users->editor()->roles()->first(); + $editorRole->detachPermission($accessApiPermission); + + $editor = User::query()->where('id', '=', $editor->id)->first(); + + $this->actingAs($editor, 'standard'); + $resp = $this->get($this->endpoint); + $resp->assertStatus(403); + $resp->assertJson($this->errorResponse('The owner of the used API token does not have permission to make API calls', 403)); + } + + public function test_access_prevented_for_guest_users_with_api_permission_while_public_access_disabled() + { + $this->disableCookieEncryption(); + $publicRole = Role::getSystemRole('public'); + $accessApiPermission = RolePermission::getByName('access-api'); + $publicRole->attachPermission($accessApiPermission); + + $this->withCookie('bookstack_session', 'abc123'); + + // Test API access when not public + setting()->put('app-public', false); + $resp = $this->get($this->endpoint); + $resp->assertStatus(403); + + // Test API access when public + setting()->put('app-public', true); + $resp = $this->get($this->endpoint); + $resp->assertStatus(200); } public function test_token_expiry_checked() { - $editor = $this->getEditor(); + $editor = $this->users->editor(); $token = $editor->apiTokens()->first(); $resp = $this->get($this->endpoint, $this->apiAuthHeader()); @@ -78,12 +125,12 @@ class ApiAuthTest extends TestCase $token->save(); $resp = $this->get($this->endpoint, $this->apiAuthHeader()); - $resp->assertJson($this->errorResponse("The authorization token used has expired", 403)); + $resp->assertJson($this->errorResponse('The authorization token used has expired', 403)); } public function test_email_confirmation_checked_using_api_auth() { - $editor = $this->getEditor(); + $editor = $this->users->editor(); $editor->email_confirmed = false; $editor->save(); @@ -92,7 +139,32 @@ class ApiAuthTest extends TestCase $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->assertJson($this->errorResponse('The email address for the account in use needs to be confirmed', 401)); } -} \ No newline at end of file + public function test_rate_limit_headers_active_on_requests() + { + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertHeader('x-ratelimit-limit', 180); + $resp->assertHeader('x-ratelimit-remaining', 179); + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertHeader('x-ratelimit-remaining', 178); + } + + public function test_rate_limit_hit_gives_json_error() + { + config()->set(['api.requests_per_minute' => 1]); + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertStatus(200); + + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertStatus(429); + $resp->assertHeader('x-ratelimit-remaining', 0); + $resp->assertHeader('retry-after'); + $resp->assertJson([ + 'error' => [ + 'code' => 429, + ], + ]); + } +}