X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a274406038e13cf678e14d65dfa70d04ead67206..refs/pull/3593/head:/tests/Auth/Saml2Test.php
diff --git a/tests/Auth/Saml2Test.php b/tests/Auth/Saml2Test.php
index 8ace3e2ee..885adf9e0 100644
--- a/tests/Auth/Saml2Test.php
+++ b/tests/Auth/Saml2Test.php
@@ -8,7 +8,7 @@ use Tests\TestCase;
class Saml2Test extends TestCase
{
- public function setUp(): void
+ protected function setUp(): void
{
parent::setUp();
// Set default config for SAML2
@@ -49,14 +49,14 @@ class Saml2Test extends TestCase
$req = $this->get('/saml2/metadata');
$req->assertSee('https://example.com/super-cats');
$req->assertSee('md:ContactPerson');
- $req->assertSee('Barry Scott');
+ $req->assertSee('Barry Scott', false);
}
public function test_login_option_shows_on_login_page()
{
$req = $this->get('/login');
$req->assertSeeText('SingleSignOn-Testing');
- $req->assertElementExists('form[action$="/saml2/login"][method=POST] button');
+ $this->withHtml($req)->assertElementExists('form[action$="/saml2/login"][method=POST] button');
}
public function test_login()
@@ -68,17 +68,47 @@ class Saml2Test extends TestCase
config()->set(['saml2.onelogin.strict' => false]);
$this->assertFalse($this->isAuthenticated());
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () {
- $acsPost = $this->post('/saml2/acs');
- $acsPost->assertRedirect('/');
- $this->assertTrue($this->isAuthenticated());
- $this->assertDatabaseHas('users', [
- 'email' => 'user@example.com',
- 'external_auth_id' => 'user',
- 'email_confirmed' => false,
- 'name' => 'Barry Scott',
- ]);
- });
+ $acsPost = $this->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $redirect = $acsPost->headers->get('Location');
+ $acsId = explode('?id=', $redirect)[1];
+ $this->assertTrue(strlen($acsId) > 12);
+
+ $this->assertStringContainsString('/saml2/acs?id=', $redirect);
+ $this->assertTrue(cache()->has('saml2_acs:' . $acsId));
+
+ $acsGet = $this->get($redirect);
+ $acsGet->assertRedirect('/');
+ $this->assertFalse(cache()->has('saml2_acs:' . $acsId));
+
+ $this->assertTrue($this->isAuthenticated());
+ $this->assertDatabaseHas('users', [
+ 'email' => 'user@example.com',
+ 'external_auth_id' => 'user',
+ 'email_confirmed' => false,
+ 'name' => 'Barry Scott',
+ ]);
+ }
+
+ public function test_acs_process_id_randomly_generated()
+ {
+ $acsPost = $this->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $redirectA = $acsPost->headers->get('Location');
+
+ $acsPost = $this->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $redirectB = $acsPost->headers->get('Location');
+
+ $this->assertFalse($redirectA === $redirectB);
+ }
+
+ public function test_process_acs_endpoint_cant_be_called_with_invalid_id()
+ {
+ $resp = $this->get('/saml2/acs');
+ $resp->assertRedirect('/login');
+ $this->followRedirects($resp)->assertSeeText('Login using SingleSignOn-Testing failed, system did not provide successful authorization');
+
+ $resp = $this->get('/saml2/acs?id=abc123');
+ $resp->assertRedirect('/login');
+ $this->followRedirects($resp)->assertSeeText('Login using SingleSignOn-Testing failed, system did not provide successful authorization');
}
public function test_group_role_sync_on_login()
@@ -89,17 +119,15 @@ class Saml2Test extends TestCase
'saml2.remove_from_groups' => false,
]);
- $memberRole = factory(Role::class)->create(['external_auth_id' => 'member']);
+ $memberRole = Role::factory()->create(['external_auth_id' => 'member']);
$adminRole = Role::getSystemRole('admin');
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () use ($memberRole, $adminRole) {
- $acsPost = $this->post('/saml2/acs');
- $user = User::query()->where('external_auth_id', '=', 'user')->first();
+ $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $user = User::query()->where('external_auth_id', '=', 'user')->first();
- $userRoleIds = $user->roles()->pluck('id');
- $this->assertContains($memberRole->id, $userRoleIds, 'User was assigned to member role');
- $this->assertContains($adminRole->id, $userRoleIds, 'User was assigned to admin role');
- });
+ $userRoleIds = $user->roles()->pluck('id');
+ $this->assertContains($memberRole->id, $userRoleIds, 'User was assigned to member role');
+ $this->assertContains($adminRole->id, $userRoleIds, 'User was assigned to admin role');
}
public function test_group_role_sync_removal_option_works_as_expected()
@@ -110,18 +138,16 @@ class Saml2Test extends TestCase
'saml2.remove_from_groups' => true,
]);
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () {
- $acsPost = $this->post('/saml2/acs');
- $user = User::query()->where('external_auth_id', '=', 'user')->first();
+ $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $user = User::query()->where('external_auth_id', '=', 'user')->first();
- $randomRole = factory(Role::class)->create(['external_auth_id' => 'random']);
- $user->attachRole($randomRole);
- $this->assertContains($randomRole->id, $user->roles()->pluck('id'));
+ $randomRole = Role::factory()->create(['external_auth_id' => 'random']);
+ $user->attachRole($randomRole);
+ $this->assertContains($randomRole->id, $user->roles()->pluck('id'));
- auth()->logout();
- $acsPost = $this->post('/saml2/acs');
- $this->assertNotContains($randomRole->id, $user->roles()->pluck('id'));
- });
+ auth()->logout();
+ $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $this->assertNotContains($randomRole->id, $user->roles()->pluck('id'));
}
public function test_logout_link_directs_to_saml_path()
@@ -131,8 +157,7 @@ class Saml2Test extends TestCase
]);
$resp = $this->actingAs($this->getEditor())->get('/');
- $resp->assertElementExists('a[href$="/saml2/logout"]');
- $resp->assertElementContains('a[href$="/saml2/logout"]', 'Logout');
+ $this->withHtml($resp)->assertElementContains('form[action$="/saml2/logout"] button', 'Logout');
}
public function test_logout_sls_flow()
@@ -149,16 +174,12 @@ class Saml2Test extends TestCase
$this->assertFalse($this->isAuthenticated());
};
- $loginAndStartLogout = function () use ($handleLogoutResponse) {
- $this->post('/saml2/acs');
+ $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
- $req = $this->get('/saml2/logout');
- $redirect = $req->headers->get('location');
- $this->assertStringStartsWith('http://saml.local/saml2/idp/SingleLogoutService.php', $redirect);
- $this->withGet(['SAMLResponse' => $this->sloResponseData], $handleLogoutResponse);
- };
-
- $this->withPost(['SAMLResponse' => $this->acsPostData], $loginAndStartLogout);
+ $req = $this->post('/saml2/logout');
+ $redirect = $req->headers->get('location');
+ $this->assertStringStartsWith('http://saml.local/saml2/idp/SingleLogoutService.php', $redirect);
+ $this->withGet(['SAMLResponse' => $this->sloResponseData], $handleLogoutResponse);
}
public function test_logout_sls_flow_when_sls_not_configured()
@@ -168,15 +189,12 @@ class Saml2Test extends TestCase
'saml2.onelogin.idp.singleLogoutService.url' => null,
]);
- $loginAndStartLogout = function () {
- $this->post('/saml2/acs');
+ $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $this->assertTrue($this->isAuthenticated());
- $req = $this->get('/saml2/logout');
- $req->assertRedirect('/');
- $this->assertFalse($this->isAuthenticated());
- };
-
- $this->withPost(['SAMLResponse' => $this->acsPostData], $loginAndStartLogout);
+ $req = $this->post('/saml2/logout');
+ $req->assertRedirect('/');
+ $this->assertFalse($this->isAuthenticated());
}
public function test_dump_user_details_option_works()
@@ -186,26 +204,24 @@ class Saml2Test extends TestCase
'saml2.dump_user_details' => true,
]);
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () {
- $acsPost = $this->post('/saml2/acs');
- $acsPost->assertJsonStructure([
- 'id_from_idp',
- 'attrs_from_idp' => [],
- 'attrs_after_parsing' => [],
- ]);
- });
+ $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $acsPost->assertJsonStructure([
+ 'id_from_idp',
+ 'attrs_from_idp' => [],
+ 'attrs_after_parsing' => [],
+ ]);
}
public function test_saml_routes_are_only_active_if_saml_enabled()
{
config()->set(['auth.method' => 'standard']);
- $getRoutes = ['/logout', '/metadata', '/sls'];
+ $getRoutes = ['/metadata', '/sls'];
foreach ($getRoutes as $route) {
$req = $this->get('/saml2' . $route);
$this->assertPermissionError($req);
}
- $postRoutes = ['/login', '/acs'];
+ $postRoutes = ['/login', '/acs', '/logout'];
foreach ($postRoutes as $route) {
$req = $this->post('/saml2' . $route);
$this->assertPermissionError($req);
@@ -232,7 +248,7 @@ class Saml2Test extends TestCase
$resp = $this->post('/login');
$this->assertPermissionError($resp);
- $resp = $this->get('/logout');
+ $resp = $this->post('/logout');
$this->assertPermissionError($resp);
}
@@ -263,13 +279,10 @@ class Saml2Test extends TestCase
'saml2.onelogin.strict' => false,
]);
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () {
- $acsPost = $this->post('/saml2/acs');
- $acsPost->assertRedirect('/login');
- $errorMessage = session()->get('error');
- $this->assertStringContainsString('That email domain does not have access to this application', $errorMessage);
- $this->assertDatabaseMissing('users', ['email' => 'user@example.com']);
- });
+ $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $acsPost->assertSeeText('That email domain does not have access to this application');
+ $this->assertFalse(auth()->check());
+ $this->assertDatabaseMissing('users', ['email' => 'user@example.com']);
}
public function test_group_sync_functions_when_email_confirmation_required()
@@ -281,22 +294,20 @@ class Saml2Test extends TestCase
'saml2.remove_from_groups' => false,
]);
- $memberRole = factory(Role::class)->create(['external_auth_id' => 'member']);
+ $memberRole = Role::factory()->create(['external_auth_id' => 'member']);
$adminRole = Role::getSystemRole('admin');
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () use ($memberRole, $adminRole) {
- $acsPost = $this->followingRedirects()->post('/saml2/acs');
+ $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
- $this->assertEquals('http://localhost/register/confirm', url()->current());
- $acsPost->assertSee('Please check your email and click the confirmation button to access BookStack.');
- /** @var User $user */
- $user = User::query()->where('external_auth_id', '=', 'user')->first();
+ $this->assertEquals('http://localhost/register/confirm', url()->current());
+ $acsPost->assertSee('Please check your email and click the confirmation button to access BookStack.');
+ /** @var User $user */
+ $user = User::query()->where('external_auth_id', '=', 'user')->first();
- $userRoleIds = $user->roles()->pluck('id');
- $this->assertContains($memberRole->id, $userRoleIds, 'User was assigned to member role');
- $this->assertContains($adminRole->id, $userRoleIds, 'User was assigned to admin role');
- $this->assertFalse(boolval($user->email_confirmed), 'User email remains unconfirmed');
- });
+ $userRoleIds = $user->roles()->pluck('id');
+ $this->assertContains($memberRole->id, $userRoleIds, 'User was assigned to member role');
+ $this->assertContains($adminRole->id, $userRoleIds, 'User was assigned to admin role');
+ $this->assertFalse(boolval($user->email_confirmed), 'User email remains unconfirmed');
$this->assertNull(auth()->user());
$homeGet = $this->get('/');
@@ -316,18 +327,14 @@ class Saml2Test extends TestCase
'name' => 'Barry Scott',
]);
- $this->withPost(['SAMLResponse' => $this->acsPostData], function () {
- $acsPost = $this->post('/saml2/acs');
- $acsPost->assertRedirect('/login');
- $this->assertFalse($this->isAuthenticated());
- $this->assertDatabaseHas('users', [
- 'email' => 'user@example.com',
- 'external_auth_id' => 'old_system_user_id',
- ]);
-
- $loginGet = $this->get('/login');
- $loginGet->assertSee('A user with the email user@example.com already exists but with different credentials');
- });
+ $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]);
+ $this->assertFalse($this->isAuthenticated());
+ $this->assertDatabaseHas('users', [
+ 'email' => 'user@example.com',
+ 'external_auth_id' => 'old_system_user_id',
+ ]);
+
+ $acsPost->assertSee('A user with the email user@example.com already exists but with different credentials');
}
public function test_login_request_contains_expected_default_authncontext()
@@ -370,11 +377,6 @@ class Saml2Test extends TestCase
return $this->withGlobal($_GET, $options, $callback);
}
- protected function withPost(array $options, callable $callback)
- {
- return $this->withGlobal($_POST, $options, $callback);
- }
-
protected function withGlobal(array &$global, array $options, callable $callback)
{
$original = [];