]> BookStack Code Mirror - bookstack/blob - tests/Auth/LdapTest.php
Merge branch 'new_bookshelf_cover_fix' of git://github.com/TBK/BookStack into TBK...
[bookstack] / tests / Auth / LdapTest.php
1 <?php namespace Tests;
2
3 use BookStack\Auth\Role;
4 use BookStack\Auth\Access\Ldap;
5 use BookStack\Auth\User;
6 use Mockery\MockInterface;
7
8 class LdapTest extends BrowserKitTest
9 {
10
11     /**
12      * @var MockInterface
13      */
14     protected $mockLdap;
15
16     protected $mockUser;
17     protected $resourceId = 'resource-test';
18
19     public function setUp(): void
20     {
21         parent::setUp();
22         if (!defined('LDAP_OPT_REFERRALS')) define('LDAP_OPT_REFERRALS', 1);
23         app('config')->set([
24             'auth.method' => 'ldap',
25             'auth.defaults.guard' => 'ldap',
26             'services.ldap.base_dn' => 'dc=ldap,dc=local',
27             'services.ldap.email_attribute' => 'mail',
28             'services.ldap.display_name_attribute' => 'cn',
29             'services.ldap.id_attribute' => 'uid',
30             'services.ldap.user_to_groups' => false,
31             'services.ldap.version' => '3',
32             'services.ldap.user_filter' => '(&(uid=${user}))',
33             'services.ldap.follow_referrals' => false,
34             'services.ldap.tls_insecure' => false,
35         ]);
36         $this->mockLdap = \Mockery::mock(Ldap::class);
37         $this->app[Ldap::class] = $this->mockLdap;
38         $this->mockUser = factory(User::class)->make();
39     }
40
41     protected function mockEscapes($times = 1)
42     {
43         $this->mockLdap->shouldReceive('escape')->times($times)->andReturnUsing(function($val) {
44             return ldap_escape($val);
45         });
46     }
47
48     protected function mockExplodes($times = 1)
49     {
50         $this->mockLdap->shouldReceive('explodeDn')->times($times)->andReturnUsing(function($dn, $withAttrib) {
51             return ldap_explode_dn($dn, $withAttrib);
52         });
53     }
54
55     protected function mockUserLogin()
56     {
57         return $this->visit('/login')
58             ->see('Username')
59             ->type($this->mockUser->name, '#username')
60             ->type($this->mockUser->password, '#password')
61             ->press('Log In');
62     }
63
64     public function test_login()
65     {
66         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
67         $this->mockLdap->shouldReceive('setVersion')->once();
68         $this->mockLdap->shouldReceive('setOption')->times(2);
69         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
70             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
71             ->andReturn(['count' => 1, 0 => [
72                 'uid' => [$this->mockUser->name],
73                 'cn' => [$this->mockUser->name],
74                 'dn' => ['dc=test' . config('services.ldap.base_dn')]
75             ]]);
76         $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true);
77         $this->mockEscapes(2);
78
79         $this->mockUserLogin()
80             ->seePageIs('/login')->see('Please enter an email to use for this account.');
81
82         $this->type($this->mockUser->email, '#email')
83             ->press('Log In')
84             ->seePageIs('/')
85             ->see($this->mockUser->name)
86             ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $this->mockUser->name]);
87     }
88
89     public function test_email_domain_restriction_active_on_new_ldap_login()
90     {
91         $this->setSettings([
92             'registration-restrict' => 'testing.com'
93         ]);
94
95         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
96         $this->mockLdap->shouldReceive('setVersion')->once();
97         $this->mockLdap->shouldReceive('setOption')->times(2);
98         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
99             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
100             ->andReturn(['count' => 1, 0 => [
101                 'uid' => [$this->mockUser->name],
102                 'cn' => [$this->mockUser->name],
103                 'dn' => ['dc=test' . config('services.ldap.base_dn')]
104             ]]);
105         $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true);
106         $this->mockEscapes(2);
107
108         $this->mockUserLogin()
109             ->seePageIs('/login')
110             ->see('Please enter an email to use for this account.');
111
112         $email = '[email protected]';
113
114         $this->type($email, '#email')
115             ->press('Log In')
116             ->seePageIs('/login')
117             ->see('That email domain does not have access to this application')
118             ->dontSeeInDatabase('users', ['email' => $email]);
119     }
120
121     public function test_login_works_when_no_uid_provided_by_ldap_server()
122     {
123         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
124         $this->mockLdap->shouldReceive('setVersion')->once();
125         $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn');
126         $this->mockLdap->shouldReceive('setOption')->times(1);
127         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
128             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
129             ->andReturn(['count' => 1, 0 => [
130                 'cn' => [$this->mockUser->name],
131                 'dn' => $ldapDn,
132                 'mail' => [$this->mockUser->email]
133             ]]);
134         $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true);
135         $this->mockEscapes(1);
136
137         $this->mockUserLogin()
138             ->seePageIs('/')
139             ->see($this->mockUser->name)
140             ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $ldapDn]);
141     }
142
143     public function test_a_custom_uid_attribute_can_be_specified_and_is_used_properly()
144     {
145         config()->set(['services.ldap.id_attribute' => 'my_custom_id']);
146         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
147         $this->mockLdap->shouldReceive('setVersion')->once();
148         $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn');
149         $this->mockLdap->shouldReceive('setOption')->times(1);
150         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
151             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
152             ->andReturn(['count' => 1, 0 => [
153                 'cn' => [$this->mockUser->name],
154                 'dn' => $ldapDn,
155                 'my_custom_id' => ['cooluser456'],
156                 'mail' => [$this->mockUser->email]
157             ]]);
158
159
160         $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true);
161         $this->mockEscapes(1);
162
163         $this->mockUserLogin()
164             ->seePageIs('/')
165             ->see($this->mockUser->name)
166             ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => 'cooluser456']);
167     }
168
169     public function test_initial_incorrect_credentials()
170     {
171         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
172         $this->mockLdap->shouldReceive('setVersion')->once();
173         $this->mockLdap->shouldReceive('setOption')->times(1);
174         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
175             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
176             ->andReturn(['count' => 1, 0 => [
177                 'uid' => [$this->mockUser->name],
178                 'cn' => [$this->mockUser->name],
179                 'dn' => ['dc=test' . config('services.ldap.base_dn')]
180             ]]);
181         $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true, false);
182         $this->mockEscapes(1);
183
184         $this->mockUserLogin()
185             ->seePageIs('/login')->see('These credentials do not match our records.')
186             ->dontSeeInDatabase('users', ['external_auth_id' => $this->mockUser->name]);
187     }
188
189     public function test_login_not_found_username()
190     {
191         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
192         $this->mockLdap->shouldReceive('setVersion')->once();
193         $this->mockLdap->shouldReceive('setOption')->times(1);
194         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
195             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
196             ->andReturn(['count' => 0]);
197         $this->mockLdap->shouldReceive('bind')->times(1)->andReturn(true, false);
198         $this->mockEscapes(1);
199
200         $this->mockUserLogin()
201             ->seePageIs('/login')->see('These credentials do not match our records.')
202             ->dontSeeInDatabase('users', ['external_auth_id' => $this->mockUser->name]);
203     }
204
205
206     public function test_create_user_form()
207     {
208         $this->asAdmin()->visit('/settings/users/create')
209             ->dontSee('Password')
210             ->type($this->mockUser->name, '#name')
211             ->type($this->mockUser->email, '#email')
212             ->press('Save')
213             ->see('The external auth id field is required.')
214             ->type($this->mockUser->name, '#external_auth_id')
215             ->press('Save')
216             ->seePageIs('/settings/users')
217             ->seeInDatabase('users', ['email' => $this->mockUser->email, 'external_auth_id' => $this->mockUser->name, 'email_confirmed' => true]);
218     }
219
220     public function test_user_edit_form()
221     {
222         $editUser = $this->getNormalUser();
223         $this->asAdmin()->visit('/settings/users/' . $editUser->id)
224             ->see('Edit User')
225             ->dontSee('Password')
226             ->type('test_auth_id', '#external_auth_id')
227             ->press('Save')
228             ->seePageIs('/settings/users')
229             ->seeInDatabase('users', ['email' => $editUser->email, 'external_auth_id' => 'test_auth_id']);
230     }
231
232     public function test_registration_disabled()
233     {
234         $this->visit('/register')
235             ->seePageIs('/login');
236     }
237
238     public function test_non_admins_cannot_change_auth_id()
239     {
240         $testUser = $this->getNormalUser();
241         $this->actingAs($testUser)->visit('/settings/users/' . $testUser->id)
242             ->dontSee('External Authentication');
243     }
244
245     public function test_login_maps_roles_and_retains_existing_roles()
246     {
247         $roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'display_name' => 'LdapTester']);
248         $roleToReceive2 = factory(Role::class)->create(['name' => 'ldaptester-second', 'display_name' => 'LdapTester Second']);
249         $existingRole = factory(Role::class)->create(['name' => 'ldaptester-existing']);
250         $this->mockUser->forceFill(['external_auth_id' => $this->mockUser->name])->save();
251         $this->mockUser->attachRole($existingRole);
252
253         app('config')->set([
254             'services.ldap.user_to_groups' => true,
255             'services.ldap.group_attribute' => 'memberOf',
256             'services.ldap.remove_from_groups' => false,
257         ]);
258         $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId);
259         $this->mockLdap->shouldReceive('setVersion')->times(1);
260         $this->mockLdap->shouldReceive('setOption')->times(4);
261         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4)
262             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
263             ->andReturn(['count' => 1, 0 => [
264                 'uid' => [$this->mockUser->name],
265                 'cn' => [$this->mockUser->name],
266                 'dn' => ['dc=test' . config('services.ldap.base_dn')],
267                 'mail' => [$this->mockUser->email],
268                 'memberof' => [
269                     'count' => 2,
270                     0 => "cn=ldaptester,ou=groups,dc=example,dc=com",
271                     1 => "cn=ldaptester-second,ou=groups,dc=example,dc=com",
272                 ]
273             ]]);
274         $this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true);
275         $this->mockEscapes(4);
276         $this->mockExplodes(6);
277
278         $this->mockUserLogin()->seePageIs('/');
279
280         $user = User::where('email', $this->mockUser->email)->first();
281         $this->seeInDatabase('role_user', [
282             'user_id' => $user->id,
283             'role_id' => $roleToReceive->id
284         ]);
285         $this->seeInDatabase('role_user', [
286             'user_id' => $user->id,
287             'role_id' => $roleToReceive2->id
288         ]);
289         $this->seeInDatabase('role_user', [
290             'user_id' => $user->id,
291             'role_id' => $existingRole->id
292         ]);
293     }
294
295     public function test_login_maps_roles_and_removes_old_roles_if_set()
296     {
297         $roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'display_name' => 'LdapTester']);
298         $existingRole = factory(Role::class)->create(['name' => 'ldaptester-existing']);
299         $this->mockUser->forceFill(['external_auth_id' => $this->mockUser->name])->save();
300         $this->mockUser->attachRole($existingRole);
301
302         app('config')->set([
303             'services.ldap.user_to_groups' => true,
304             'services.ldap.group_attribute' => 'memberOf',
305             'services.ldap.remove_from_groups' => true,
306         ]);
307         $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId);
308         $this->mockLdap->shouldReceive('setVersion')->times(1);
309         $this->mockLdap->shouldReceive('setOption')->times(3);
310         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(3)
311             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
312             ->andReturn(['count' => 1, 0 => [
313                 'uid' => [$this->mockUser->name],
314                 'cn' => [$this->mockUser->name],
315                 'dn' => ['dc=test' . config('services.ldap.base_dn')],
316                 'mail' => [$this->mockUser->email],
317                 'memberof' => [
318                     'count' => 1,
319                     0 => "cn=ldaptester,ou=groups,dc=example,dc=com",
320                 ]
321             ]]);
322         $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true);
323         $this->mockEscapes(3);
324         $this->mockExplodes(2);
325
326         $this->mockUserLogin()->seePageIs('/');
327
328         $user = User::where('email', $this->mockUser->email)->first();
329         $this->seeInDatabase('role_user', [
330             'user_id' => $user->id,
331             'role_id' => $roleToReceive->id
332         ]);
333         $this->dontSeeInDatabase('role_user', [
334             'user_id' => $user->id,
335             'role_id' => $existingRole->id
336         ]);
337     }
338
339     public function test_external_auth_id_visible_in_roles_page_when_ldap_active()
340     {
341         $role = factory(Role::class)->create(['name' => 'ldaptester', 'external_auth_id' => 'ex-auth-a, test-second-param']);
342         $this->asAdmin()->visit('/settings/roles/' . $role->id)
343             ->see('ex-auth-a');
344     }
345
346     public function test_login_maps_roles_using_external_auth_ids_if_set()
347     {
348         $roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'external_auth_id' => 'test-second-param, ex-auth-a']);
349         $roleToNotReceive = factory(Role::class)->create(['name' => 'ldaptester-not-receive', 'display_name' => 'ex-auth-a', 'external_auth_id' => 'test-second-param']);
350
351         app('config')->set([
352             'services.ldap.user_to_groups' => true,
353             'services.ldap.group_attribute' => 'memberOf',
354             'services.ldap.remove_from_groups' => true,
355         ]);
356         $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId);
357         $this->mockLdap->shouldReceive('setVersion')->times(1);
358         $this->mockLdap->shouldReceive('setOption')->times(3);
359         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(3)
360             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
361             ->andReturn(['count' => 1, 0 => [
362                 'uid' => [$this->mockUser->name],
363                 'cn' => [$this->mockUser->name],
364                 'dn' => ['dc=test' . config('services.ldap.base_dn')],
365                 'mail' => [$this->mockUser->email],
366                 'memberof' => [
367                     'count' => 1,
368                     0 => "cn=ex-auth-a,ou=groups,dc=example,dc=com",
369                 ]
370             ]]);
371         $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true);
372         $this->mockEscapes(3);
373         $this->mockExplodes(2);
374
375         $this->mockUserLogin()->seePageIs('/');
376
377         $user = User::where('email', $this->mockUser->email)->first();
378         $this->seeInDatabase('role_user', [
379             'user_id' => $user->id,
380             'role_id' => $roleToReceive->id
381         ]);
382         $this->dontSeeInDatabase('role_user', [
383             'user_id' => $user->id,
384             'role_id' => $roleToNotReceive->id
385         ]);
386     }
387
388     public function test_login_group_mapping_does_not_conflict_with_default_role()
389     {
390         $roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'display_name' => 'LdapTester']);
391         $roleToReceive2 = factory(Role::class)->create(['name' => 'ldaptester-second', 'display_name' => 'LdapTester Second']);
392         $this->mockUser->forceFill(['external_auth_id' => $this->mockUser->name])->save();
393
394         setting()->put('registration-role', $roleToReceive->id);
395
396         app('config')->set([
397             'services.ldap.user_to_groups' => true,
398             'services.ldap.group_attribute' => 'memberOf',
399             'services.ldap.remove_from_groups' => true,
400         ]);
401         $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId);
402         $this->mockLdap->shouldReceive('setVersion')->times(1);
403         $this->mockLdap->shouldReceive('setOption')->times(4);
404         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4)
405             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
406             ->andReturn(['count' => 1, 0 => [
407                 'uid' => [$this->mockUser->name],
408                 'cn' => [$this->mockUser->name],
409                 'dn' => ['dc=test' . config('services.ldap.base_dn')],
410                 'mail' => [$this->mockUser->email],
411                 'memberof' => [
412                     'count' => 2,
413                     0 => "cn=ldaptester,ou=groups,dc=example,dc=com",
414                     1 => "cn=ldaptester-second,ou=groups,dc=example,dc=com",
415                 ]
416             ]]);
417         $this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true);
418         $this->mockEscapes(4);
419         $this->mockExplodes(6);
420
421         $this->mockUserLogin()->seePageIs('/');
422
423         $user = User::where('email', $this->mockUser->email)->first();
424         $this->seeInDatabase('role_user', [
425             'user_id' => $user->id,
426             'role_id' => $roleToReceive->id
427         ]);
428         $this->seeInDatabase('role_user', [
429             'user_id' => $user->id,
430             'role_id' => $roleToReceive2->id
431         ]);
432     }
433
434     public function test_login_uses_specified_display_name_attribute()
435     {
436         app('config')->set([
437             'services.ldap.display_name_attribute' => 'displayName'
438         ]);
439
440         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
441         $this->mockLdap->shouldReceive('setVersion')->once();
442         $this->mockLdap->shouldReceive('setOption')->times(2);
443         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
444             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
445             ->andReturn(['count' => 1, 0 => [
446                 'uid' => [$this->mockUser->name],
447                 'cn' => [$this->mockUser->name],
448                 'dn' => ['dc=test' . config('services.ldap.base_dn')],
449                 'displayname' => 'displayNameAttribute'
450             ]]);
451         $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true);
452         $this->mockEscapes(2);
453
454         $this->mockUserLogin()
455             ->seePageIs('/login')->see('Please enter an email to use for this account.');
456
457         $this->type($this->mockUser->email, '#email')
458             ->press('Log In')
459             ->seePageIs('/')
460             ->see('displayNameAttribute')
461             ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $this->mockUser->name, 'name' => 'displayNameAttribute']);
462     }
463
464     public function test_login_uses_default_display_name_attribute_if_specified_not_present()
465     {
466         app('config')->set([
467             'services.ldap.display_name_attribute' => 'displayName'
468         ]);
469
470         $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId);
471         $this->mockLdap->shouldReceive('setVersion')->once();
472         $this->mockLdap->shouldReceive('setOption')->times(2);
473         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
474             ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
475             ->andReturn(['count' => 1, 0 => [
476                 'uid' => [$this->mockUser->name],
477                 'cn' => [$this->mockUser->name],
478                 'dn' => ['dc=test' . config('services.ldap.base_dn')]
479             ]]);
480         $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true);
481         $this->mockEscapes(2);
482
483         $this->mockUserLogin()
484             ->seePageIs('/login')->see('Please enter an email to use for this account.');
485
486         $this->type($this->mockUser->email, '#email')
487             ->press('Log In')
488             ->seePageIs('/')
489             ->see($this->mockUser->name)
490             ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $this->mockUser->name, 'name' => $this->mockUser->name]);
491     }
492
493     protected function checkLdapReceivesCorrectDetails($serverString, $expectedHost, $expectedPort)
494     {
495         app('config')->set([
496             'services.ldap.server' => $serverString
497         ]);
498
499         // Standard mocks
500         $this->mockLdap->shouldReceive('setVersion')->once();
501         $this->mockLdap->shouldReceive('setOption')->times(1);
502         $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)->andReturn(['count' => 1, 0 => [
503             'uid' => [$this->mockUser->name],
504             'cn' => [$this->mockUser->name],
505             'dn' => ['dc=test' . config('services.ldap.base_dn')]
506         ]]);
507         $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true);
508         $this->mockEscapes(1);
509
510         $this->mockLdap->shouldReceive('connect')->once()
511             ->with($expectedHost, $expectedPort)->andReturn($this->resourceId);
512         $this->mockUserLogin();
513     }
514
515     public function test_ldap_port_provided_on_host_if_host_is_full_uri()
516     {
517         $hostName = 'ldaps://bookstack:8080';
518         $this->checkLdapReceivesCorrectDetails($hostName, $hostName, 389);
519     }
520
521     public function test_ldap_port_parsed_from_server_if_host_is_not_full_uri()
522     {
523         $this->checkLdapReceivesCorrectDetails('ldap.bookstack.com:8080', 'ldap.bookstack.com', 8080);
524     }
525
526     public function test_default_ldap_port_used_if_not_in_server_string_and_not_uri()
527     {
528         $this->checkLdapReceivesCorrectDetails('ldap.bookstack.com', 'ldap.bookstack.com', 389);
529     }
530
531     public function test_forgot_password_routes_inaccessible()
532     {
533         $resp = $this->get('/password/email');
534         $this->assertPermissionError($resp);
535
536         $resp = $this->post('/password/email');
537         $this->assertPermissionError($resp);
538
539         $resp = $this->get('/password/reset/abc123');
540         $this->assertPermissionError($resp);
541
542         $resp = $this->post('/password/reset');
543         $this->assertPermissionError($resp);
544     }
545
546     public function test_user_invite_routes_inaccessible()
547     {
548         $resp = $this->get('/register/invite/abc123');
549         $this->assertPermissionError($resp);
550
551         $resp = $this->post('/register/invite/abc123');
552         $this->assertPermissionError($resp);
553     }
554
555     public function test_user_register_routes_inaccessible()
556     {
557         $resp = $this->get('/register');
558         $this->assertPermissionError($resp);
559
560         $resp = $this->post('/register');
561         $this->assertPermissionError($resp);
562     }
563 }