From 657dccdade755c47f250848454f6573b13bcba07 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Thu, 7 Dec 2023 14:44:18 +0100 Subject: [PATCH 1/2] fix(loginflow): Log state token mismatch errors Signed-off-by: Christoph Wurst [skip ci] --- core/Controller/ClientFlowLoginController.php | 18 ++++++++++++- .../ClientFlowLoginV2Controller.php | 25 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php index 99074e6ff597f..deaf26b348d04 100644 --- a/core/Controller/ClientFlowLoginController.php +++ b/core/Controller/ClientFlowLoginController.php @@ -36,6 +36,8 @@ use OCP\Security\ICrypto; use OCP\Security\ISecureRandom; use OCP\Session\Exceptions\SessionNotAvailableException; +use function hash_equals; +use function OCP\Log\logger; #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] class ClientFlowLoginController extends Controller { @@ -69,9 +71,20 @@ private function getClientName(): string { private function isValidToken(string $stateToken): bool { $currentToken = $this->session->get(self::STATE_NAME); if (!is_string($currentToken)) { + logger('core')->error('Client login flow state token is not set', [ + 'sessionToken' => $currentToken, + 'requestToken' => $stateToken, + ]); return false; } - return hash_equals($currentToken, $stateToken); + $hashEquals = hash_equals($currentToken, $stateToken); + if (!$hashEquals) { + logger('core')->error('Client login flow state token does not match', [ + 'sessionToken' => $currentToken, + 'requestToken' => $stateToken, + ]); + } + return $hashEquals; } private function stateTokenForbiddenResponse(): StandaloneTemplateResponse { @@ -123,6 +136,9 @@ public function showAuthPickerPage(string $clientIdentifier = '', string $user = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS ); $this->session->set(self::STATE_NAME, $stateToken); + logger('core')->error('Client login flow state token set', [ + 'token' => $stateToken, + ]); $csp = new Http\ContentSecurityPolicy(); if ($client) { diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php index 1ce43c1993222..fce60d443ee3e 100644 --- a/core/Controller/ClientFlowLoginV2Controller.php +++ b/core/Controller/ClientFlowLoginV2Controller.php @@ -93,6 +93,11 @@ public function landing(string $token, $user = '', int $direct = 0): Response { } $this->session->set(self::TOKEN_NAME, $token); + logger('core')->debug('Client login flow state token set on landing page', [ + 'sessionId' => $this->session->getId(), + 'sessionToken' => $token, + 'user' => $user, + ]); return new RedirectResponse( $this->urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.showAuthPickerPage', ['user' => $user, 'direct' => $direct]) @@ -116,6 +121,11 @@ public function showAuthPickerPage(string $user = '', int $direct = 0): Standalo ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS ); $this->session->set(self::STATE_NAME, $stateToken); + logger('core')->debug('Client login flow state token set on auth picker page', [ + 'sessionId' => $this->session->getId(), + 'sessionToken' => $stateToken, + 'user' => $user, + ]); return new StandaloneTemplateResponse( $this->appName, @@ -299,9 +309,22 @@ public function init(): JSONResponse { private function isValidStateToken(string $stateToken): bool { $currentToken = $this->session->get(self::STATE_NAME); if (!is_string($stateToken) || !is_string($currentToken)) { + logger('core')->error('Client login flow state token is not set', [ + 'sessionId' => $this->session->getId(), + 'sessionToken' => $currentToken, + 'requestToken' => $stateToken, + ]); return false; } - return hash_equals($currentToken, $stateToken); + $hashEquals = hash_equals($currentToken, $stateToken); + if (!$hashEquals) { + logger('core')->error('Client login flow state token does not match', [ + 'sessionId' => $this->session->getId(), + 'sessionToken' => $currentToken, + 'requestToken' => $stateToken, + ]); + } + return $hashEquals; } private function stateTokenMissingResponse(): StandaloneTemplateResponse { From 1c806ac4344331703660a8753777a3ac26d604ab Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 3 Jun 2025 10:36:04 +0200 Subject: [PATCH 2/2] add import --- core/Controller/ClientFlowLoginV2Controller.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php index fce60d443ee3e..8e07a2cb1d055 100644 --- a/core/Controller/ClientFlowLoginV2Controller.php +++ b/core/Controller/ClientFlowLoginV2Controller.php @@ -33,6 +33,8 @@ use OCP\IUser; use OCP\IUserSession; use OCP\Security\ISecureRandom; +use function hash_equals; +use function OCP\Log\logger; /** * @psalm-import-type CoreLoginFlowV2Credentials from ResponseDefinitions