]> BookStack Code Mirror - bookstack/blob - tests/Api/ApiAuthTest.php
Fix Crowdin name in the language_request issue template
[bookstack] / tests / Api / ApiAuthTest.php
1 <?php
2
3 namespace Tests\Api;
4
5 use BookStack\Auth\Permissions\RolePermission;
6 use BookStack\Auth\Role;
7 use BookStack\Auth\User;
8 use Carbon\Carbon;
9 use Tests\TestCase;
10
11 class ApiAuthTest extends TestCase
12 {
13     use TestsApi;
14
15     protected $endpoint = '/api/books';
16
17     public function test_requests_succeed_with_default_auth()
18     {
19         $viewer = $this->getViewer();
20         $this->giveUserPermissions($viewer, ['access-api']);
21
22         $resp = $this->get($this->endpoint);
23         $resp->assertStatus(401);
24
25         $this->actingAs($viewer, 'standard');
26
27         $resp = $this->get($this->endpoint);
28         $resp->assertStatus(200);
29     }
30
31     public function test_no_token_throws_error()
32     {
33         $resp = $this->get($this->endpoint);
34         $resp->assertStatus(401);
35         $resp->assertJson($this->errorResponse('No authorization token found on the request', 401));
36     }
37
38     public function test_bad_token_format_throws_error()
39     {
40         $resp = $this->get($this->endpoint, ['Authorization' => 'Token abc123']);
41         $resp->assertStatus(401);
42         $resp->assertJson($this->errorResponse('An authorization token was found on the request but the format appeared incorrect', 401));
43     }
44
45     public function test_token_with_non_existing_id_throws_error()
46     {
47         $resp = $this->get($this->endpoint, ['Authorization' => 'Token abc:123']);
48         $resp->assertStatus(401);
49         $resp->assertJson($this->errorResponse('No matching API token was found for the provided authorization token', 401));
50     }
51
52     public function test_token_with_bad_secret_value_throws_error()
53     {
54         $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:123"]);
55         $resp->assertStatus(401);
56         $resp->assertJson($this->errorResponse('The secret provided for the given used API token is incorrect', 401));
57     }
58
59     public function test_api_access_permission_required_to_access_api()
60     {
61         $resp = $this->get($this->endpoint, $this->apiAuthHeader());
62         $resp->assertStatus(200);
63         auth()->logout();
64
65         $accessApiPermission = RolePermission::getByName('access-api');
66         $editorRole = $this->getEditor()->roles()->first();
67         $editorRole->detachPermission($accessApiPermission);
68
69         $resp = $this->get($this->endpoint, $this->apiAuthHeader());
70         $resp->assertStatus(403);
71         $resp->assertJson($this->errorResponse('The owner of the used API token does not have permission to make API calls', 403));
72     }
73
74     public function test_api_access_permission_required_to_access_api_with_session_auth()
75     {
76         $editor = $this->getEditor();
77         $this->actingAs($editor, 'standard');
78
79         $resp = $this->get($this->endpoint);
80         $resp->assertStatus(200);
81         auth('standard')->logout();
82
83         $accessApiPermission = RolePermission::getByName('access-api');
84         $editorRole = $this->getEditor()->roles()->first();
85         $editorRole->detachPermission($accessApiPermission);
86
87         $editor = User::query()->where('id', '=', $editor->id)->first();
88
89         $this->actingAs($editor, 'standard');
90         $resp = $this->get($this->endpoint);
91         $resp->assertStatus(403);
92         $resp->assertJson($this->errorResponse('The owner of the used API token does not have permission to make API calls', 403));
93     }
94
95     public function test_access_prevented_for_guest_users_with_api_permission_while_public_access_disabled()
96     {
97         $this->disableCookieEncryption();
98         $publicRole = Role::getSystemRole('public');
99         $accessApiPermission = RolePermission::getByName('access-api');
100         $publicRole->attachPermission($accessApiPermission);
101
102         $this->withCookie('bookstack_session', 'abc123');
103
104         // Test API access when not public
105         setting()->put('app-public', false);
106         $resp = $this->get($this->endpoint);
107         $resp->assertStatus(403);
108
109         // Test API access when public
110         setting()->put('app-public', true);
111         $resp = $this->get($this->endpoint);
112         $resp->assertStatus(200);
113     }
114
115     public function test_token_expiry_checked()
116     {
117         $editor = $this->getEditor();
118         $token = $editor->apiTokens()->first();
119
120         $resp = $this->get($this->endpoint, $this->apiAuthHeader());
121         $resp->assertStatus(200);
122         auth()->logout();
123
124         $token->expires_at = Carbon::now()->subDay()->format('Y-m-d');
125         $token->save();
126
127         $resp = $this->get($this->endpoint, $this->apiAuthHeader());
128         $resp->assertJson($this->errorResponse('The authorization token used has expired', 403));
129     }
130
131     public function test_email_confirmation_checked_using_api_auth()
132     {
133         $editor = $this->getEditor();
134         $editor->email_confirmed = false;
135         $editor->save();
136
137         // Set settings and get user instance
138         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
139
140         $resp = $this->get($this->endpoint, $this->apiAuthHeader());
141         $resp->assertStatus(401);
142         $resp->assertJson($this->errorResponse('The email address for the account in use needs to be confirmed', 401));
143     }
144
145     public function test_rate_limit_headers_active_on_requests()
146     {
147         $resp = $this->actingAsApiEditor()->get($this->endpoint);
148         $resp->assertHeader('x-ratelimit-limit', 180);
149         $resp->assertHeader('x-ratelimit-remaining', 179);
150         $resp = $this->actingAsApiEditor()->get($this->endpoint);
151         $resp->assertHeader('x-ratelimit-remaining', 178);
152     }
153
154     public function test_rate_limit_hit_gives_json_error()
155     {
156         config()->set(['api.requests_per_minute' => 1]);
157         $resp = $this->actingAsApiEditor()->get($this->endpoint);
158         $resp->assertStatus(200);
159
160         $resp = $this->actingAsApiEditor()->get($this->endpoint);
161         $resp->assertStatus(429);
162         $resp->assertHeader('x-ratelimit-remaining', 0);
163         $resp->assertHeader('retry-after');
164         $resp->assertJson([
165             'error' => [
166                 'code' => 429,
167             ],
168         ]);
169     }
170 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.