From b501e1fddb4c75a3df3a596d384b9ef9c14a8f5b Mon Sep 17 00:00:00 2001 From: turegjorup Date: Thu, 11 Jun 2026 13:10:55 +0200 Subject: [PATCH] fix: preserve authentication failure cause in onAuthenticationFailure onAuthenticationFailure() now chains the original exception via previous and includes its message, so logs and error reporters retain the actual cause (timeout vs. signature mismatch vs. wrong nonce). Symfony's security component still renders only the safe message key to the user. Ported from feature/exception-flow (222bf32); the rest of that branch was superseded by the 5.0 exception-contract work. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 5 +++++ src/Security/OpenIdLoginAuthenticator.php | 5 ++++- tests/Security/OpenIdLoginAuthenticatorTest.php | 14 +++++++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fa67df..24c08e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- `OpenIdLoginAuthenticator::onAuthenticationFailure()` now chains the + original exception via `previous` and includes its message, so logs and + error reporters retain the cause (timeout vs. signature mismatch vs. + wrong nonce). Symfony's security component still renders only the safe + message key to the user. - Strengthened tests guided by mutation testing; mutation score raised to 100% with a CI threshold of 95 (`minCoveredMsi` in `infection.json5`) - Test fixtures use RFC 2606 reserved domains (`provider.example.org`, diff --git a/src/Security/OpenIdLoginAuthenticator.php b/src/Security/OpenIdLoginAuthenticator.php index 440e38e..e207408 100644 --- a/src/Security/OpenIdLoginAuthenticator.php +++ b/src/Security/OpenIdLoginAuthenticator.php @@ -78,6 +78,9 @@ protected function validateClaims(Request $request): array public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response { - throw new AuthenticationException('Error occurred validating openid login'); + // Preserve the cause so logs and error reporters can see what actually + // failed (timeout, signature mismatch, wrong nonce, etc.). Symfony's + // security component renders only the safe message key to the user. + throw new AuthenticationException(sprintf('Error occurred validating openid login: %s', $exception->getMessage()), $exception->getCode(), $exception); } } diff --git a/tests/Security/OpenIdLoginAuthenticatorTest.php b/tests/Security/OpenIdLoginAuthenticatorTest.php index e2704cf..96f371c 100644 --- a/tests/Security/OpenIdLoginAuthenticatorTest.php +++ b/tests/Security/OpenIdLoginAuthenticatorTest.php @@ -40,13 +40,17 @@ public function testSupports(): void $this->assertTrue($this->authenticator->supports($request)); } - public function testOnAuthenticationFailure(): void + public function testOnAuthenticationFailurePreservesCause(): void { - $this->expectException(AuthenticationException::class); + $cause = new AuthenticationException('Original cause message'); - $exception = new AuthenticationException(); - - $this->authenticator->onAuthenticationFailure(new Request(), $exception); + try { + $this->authenticator->onAuthenticationFailure(new Request(), $cause); + $this->fail('Expected AuthenticationException'); + } catch (AuthenticationException $thrown) { + $this->assertSame($cause, $thrown->getPrevious(), 'Original exception must be chained as previous'); + $this->assertStringContainsString('Original cause message', $thrown->getMessage(), 'Cause message must be preserved for logs'); + } } public function testValidateClaimsWrongState(): void