X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/263384cf99864ebdb0408fd4e478f783aa487c1a..refs/pull/3593/head:/tests/Auth/OidcTest.php diff --git a/tests/Auth/OidcTest.php b/tests/Auth/OidcTest.php index cf04080fc..aa2c99a36 100644 --- a/tests/Auth/OidcTest.php +++ b/tests/Auth/OidcTest.php @@ -1,21 +1,21 @@ -keyFilePath, OidcJwtHelper::publicPemKey()); config()->set([ - 'auth.method' => 'oidc', - 'auth.defaults.guard' => 'oidc', - 'oidc.name' => 'SingleSignOn-Testing', - 'oidc.display_name_claims' => ['name'], - 'oidc.client_id' => OidcJwtHelper::defaultClientId(), - 'oidc.client_secret' => 'testpass', - 'oidc.jwt_public_key' => $this->keyFilePath, - 'oidc.issuer' => OidcJwtHelper::defaultIssuer(), + 'auth.method' => 'oidc', + 'auth.defaults.guard' => 'oidc', + 'oidc.name' => 'SingleSignOn-Testing', + 'oidc.display_name_claims' => ['name'], + 'oidc.client_id' => OidcJwtHelper::defaultClientId(), + 'oidc.client_secret' => 'testpass', + 'oidc.jwt_public_key' => $this->keyFilePath, + 'oidc.issuer' => OidcJwtHelper::defaultIssuer(), 'oidc.authorization_endpoint' => 'https://oidc.local/auth', - 'oidc.token_endpoint' => 'https://oidc.local/token', - 'oidc.discover' => false, - 'oidc.dump_user_details' => false, + 'oidc.token_endpoint' => 'https://oidc.local/token', + 'oidc.discover' => false, + 'oidc.dump_user_details' => false, ]); } - public function tearDown(): void + protected function tearDown(): void { parent::tearDown(); if (file_exists($this->keyFilePath)) { @@ -52,7 +52,7 @@ class OidcTest extends TestCase { $req = $this->get('/login'); $req->assertSeeText('SingleSignOn-Testing'); - $req->assertElementExists('form[action$="/oidc/login"][method=POST] button'); + $this->withHtml($req)->assertElementExists('form[action$="/oidc/login"][method=POST] button'); } public function test_oidc_routes_are_only_active_if_oidc_enabled() @@ -89,7 +89,7 @@ class OidcTest extends TestCase public function test_logout_route_functions() { $this->actingAs($this->getEditor()); - $this->get('/logout'); + $this->post('/logout'); $this->assertFalse(auth()->check()); } @@ -131,7 +131,7 @@ class OidcTest extends TestCase $transactions = &$this->mockHttpClient([$this->getMockAuthorizationResponse([ 'email' => 'benny@example.com', - 'sub' => 'benny1010101' + 'sub' => 'benny1010101', ])]); // Callback from auth provider @@ -148,12 +148,11 @@ class OidcTest extends TestCase $this->assertStringContainsString('code=SplxlOBeZQQYbYS6WxSbIA', $tokenRequest->getBody()); $this->assertStringContainsString('redirect_uri=' . urlencode(url('/oidc/callback')), $tokenRequest->getBody()); - $this->assertTrue(auth()->check()); $this->assertDatabaseHas('users', [ - 'email' => 'benny@example.com', + 'email' => 'benny@example.com', 'external_auth_id' => 'benny1010101', - 'email_confirmed' => false, + 'email_confirmed' => false, ]); $user = User::query()->where('email', '=', 'benny@example.com')->first(); @@ -176,15 +175,15 @@ class OidcTest extends TestCase $resp = $this->runLogin([ 'email' => 'benny@example.com', - 'sub' => 'benny505' + 'sub' => 'benny505', ]); $resp->assertStatus(200); $resp->assertJson([ 'email' => 'benny@example.com', - 'sub' => 'benny505', - "iss" => OidcJwtHelper::defaultIssuer(), - "aud" => OidcJwtHelper::defaultClientId(), + 'sub' => 'benny505', + 'iss' => OidcJwtHelper::defaultIssuer(), + 'aud' => OidcJwtHelper::defaultClientId(), ]); $this->assertFalse(auth()->check()); } @@ -193,7 +192,7 @@ class OidcTest extends TestCase { $this->runLogin([ 'email' => '', - 'sub' => 'benny505' + 'sub' => 'benny505', ]); $this->assertSessionError('Could not find an email address, for this user, in the data provided by the external authentication system'); @@ -205,7 +204,7 @@ class OidcTest extends TestCase $this->runLogin([ 'email' => 'benny@example.com', - 'sub' => 'benny505' + 'sub' => 'benny505', ]); $this->assertSessionError('Already logged in'); @@ -221,7 +220,7 @@ class OidcTest extends TestCase $this->runLogin([ 'email' => 'benny@example.com', - 'sub' => 'benny505' + 'sub' => 'benny505', ]); $this->assertTrue(auth()->check()); @@ -236,22 +235,24 @@ class OidcTest extends TestCase $this->assertFalse(auth()->check()); - $this->runLogin([ + $resp = $this->runLogin([ 'email' => $editor->email, - 'sub' => 'benny505' + 'sub' => 'benny505', ]); + $resp = $this->followRedirects($resp); - $this->assertSessionError('A user with the email ' . $editor->email . ' already exists but with different credentials.'); + $resp->assertSeeText('A user with the email ' . $editor->email . ' already exists but with different credentials.'); $this->assertFalse(auth()->check()); } public function test_auth_login_with_invalid_token_fails() { - $this->runLogin([ + $resp = $this->runLogin([ 'sub' => null, ]); + $resp = $this->followRedirects($resp); - $this->assertSessionError('ID token validate failed with error: Missing token subject value'); + $resp->assertSeeText('ID token validate failed with error: Missing token subject value'); $this->assertFalse(auth()->check()); } @@ -287,9 +288,9 @@ class OidcTest extends TestCase new Response(404, [], 'Not found'), ]); - $this->runLogin(); + $resp = $this->followRedirects($this->runLogin()); $this->assertFalse(auth()->check()); - $this->assertSessionError('Login using SingleSignOn-Testing failed, system did not provide successful authorization'); + $resp->assertSeeText('Login using SingleSignOn-Testing failed, system did not provide successful authorization'); } public function test_autodiscovery_calls_are_cached() @@ -300,7 +301,7 @@ class OidcTest extends TestCase $this->getAutoDiscoveryResponse(), $this->getJwksResponse(), $this->getAutoDiscoveryResponse([ - 'issuer' => 'https://auto.example.com' + 'issuer' => 'https://auto.example.com', ]), $this->getJwksResponse(), ]); @@ -318,14 +319,39 @@ class OidcTest extends TestCase $this->assertCount(4, $transactions); } + public function test_auth_login_with_autodiscovery_with_keys_that_do_not_have_alg_property() + { + $this->withAutodiscovery(); + + $keyArray = OidcJwtHelper::publicJwkKeyArray(); + unset($keyArray['alg']); + + $this->mockHttpClient([ + $this->getAutoDiscoveryResponse(), + new Response(200, [ + 'Content-Type' => 'application/json', + 'Cache-Control' => 'no-cache, no-store', + 'Pragma' => 'no-cache', + ], json_encode([ + 'keys' => [ + $keyArray, + ], + ])), + ]); + + $this->assertFalse(auth()->check()); + $this->runLogin(); + $this->assertTrue(auth()->check()); + } + protected function withAutodiscovery() { config()->set([ - 'oidc.issuer' => OidcJwtHelper::defaultIssuer(), - 'oidc.discover' => true, + 'oidc.issuer' => OidcJwtHelper::defaultIssuer(), + 'oidc.discover' => true, 'oidc.authorization_endpoint' => null, - 'oidc.token_endpoint' => null, - 'oidc.jwt_public_key' => null, + 'oidc.token_endpoint' => null, + 'oidc.jwt_public_key' => null, ]); } @@ -341,41 +367,41 @@ class OidcTest extends TestCase protected function getAutoDiscoveryResponse($responseOverrides = []): Response { return new Response(200, [ - 'Content-Type' => 'application/json', + 'Content-Type' => 'application/json', 'Cache-Control' => 'no-cache, no-store', - 'Pragma' => 'no-cache' + 'Pragma' => 'no-cache', ], json_encode(array_merge([ - 'token_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/token', + 'token_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/token', 'authorization_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/authorize', - 'jwks_uri' => OidcJwtHelper::defaultIssuer() . '/oidc/keys', - 'issuer' => OidcJwtHelper::defaultIssuer() + 'jwks_uri' => OidcJwtHelper::defaultIssuer() . '/oidc/keys', + 'issuer' => OidcJwtHelper::defaultIssuer(), ], $responseOverrides))); } protected function getJwksResponse(): Response { return new Response(200, [ - 'Content-Type' => 'application/json', + 'Content-Type' => 'application/json', 'Cache-Control' => 'no-cache, no-store', - 'Pragma' => 'no-cache' + 'Pragma' => 'no-cache', ], json_encode([ 'keys' => [ - OidcJwtHelper::publicJwkKeyArray() - ] + OidcJwtHelper::publicJwkKeyArray(), + ], ])); } protected function getMockAuthorizationResponse($claimOverrides = []): Response { return new Response(200, [ - 'Content-Type' => 'application/json', + 'Content-Type' => 'application/json', 'Cache-Control' => 'no-cache, no-store', - 'Pragma' => 'no-cache' + 'Pragma' => 'no-cache', ], json_encode([ 'access_token' => 'abc123', - 'token_type' => 'Bearer', - 'expires_in' => 3600, - 'id_token' => OidcJwtHelper::idToken($claimOverrides) + 'token_type' => 'Bearer', + 'expires_in' => 3600, + 'id_token' => OidcJwtHelper::idToken($claimOverrides), ])); } }