diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php index 815de9fb4ed..2d27a771bd2 100644 --- a/core/Controller/ClientFlowLoginController.php +++ b/core/Controller/ClientFlowLoginController.php @@ -173,6 +173,12 @@ class ClientFlowLoginController extends Controller { ); } + $oldStateToken = $this->session->get(self::STATE_NAME); + logger('core')->error('Fetching old state token - expected to be null', [ + 'loginFlow' => 'v1', + 'existingStateToken' => $oldStateToken, + ]); + $stateToken = $this->random->generate( 64, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS @@ -182,6 +188,21 @@ class ClientFlowLoginController extends Controller { 'token' => $stateToken, ]); + $setStateToken = $this->session->get(self::STATE_NAME); + logger('core')->error('Fetching set state token - expected to match generated one', [ + 'loginFlow' => 'v1', + 'generatedStateToken' => $stateToken, + 'setStateToken' => $setStateToken, + ]); + + if ($stateToken !== $setStateToken) { + logger('core')->error('Generate and set state token mismatch, trying to set it again one more time', [ + 'loginFlow' => 'v1', + 'stateToken' => $stateToken, + ]); + $this->session->set(self::STATE_NAME, $stateToken); + } + $csp = new Http\ContentSecurityPolicy(); if ($client) { $csp->addAllowedFormActionDomain($client->getRedirectUri()); diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php index cef2094168b..cd5c9c39b6c 100644 --- a/core/Controller/ClientFlowLoginV2Controller.php +++ b/core/Controller/ClientFlowLoginV2Controller.php @@ -125,12 +125,33 @@ class ClientFlowLoginV2Controller extends Controller { return $this->loginTokenForbiddenResponse(); } + $oldStateToken = $this->session->get(self::STATE_NAME); + logger('core')->error('Fetching old state token - expected to be null', [ + 'loginFlow' => 'v2', + 'existingStateToken' => $oldStateToken, + ]); + $stateToken = $this->random->generate( 64, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS ); $this->session->set(self::STATE_NAME, $stateToken); + $setStateToken = $this->session->get(self::STATE_NAME); + logger('core')->error('Fetching set state token - expected to match generated one', [ + 'loginFlow' => 'v2', + 'generatedStateToken' => $stateToken, + 'setStateToken' => $setStateToken, + ]); + + if ($stateToken !== $setStateToken) { + logger('core')->error('Generate and set state token mismatch, trying to set it again one more time', [ + 'loginFlow' => 'v2', + 'stateToken' => $stateToken, + ]); + $this->session->set(self::STATE_NAME, $stateToken); + } + return new StandaloneTemplateResponse( $this->appName, 'loginflowv2/authpicker', diff --git a/lib/private/Session/CryptoSessionData.php b/lib/private/Session/CryptoSessionData.php index dd6782cbff0..97d3fd78fd8 100644 --- a/lib/private/Session/CryptoSessionData.php +++ b/lib/private/Session/CryptoSessionData.php @@ -98,12 +98,27 @@ class CryptoSessionData implements \ArrayAccess, ISession { * @param mixed $value */ public function set(string $key, $value) { - if ($this->get($key) === $value) { + $existingValue = $this->get($key); + if ($existingValue === $value) { + if ($key === 'client.flow.v2.state.token' || $key === 'client.flow.state.token') { + logger('core')->error('State token value is already present!', [ + 'loginFlow' => str_contains($key, 'v2') ? 'v2' : 'v1', + 'stateToken' => $value, + 'existingStateToken' => $existingValue, + ]); + } // Do not write the session if the value hasn't changed to avoid reopening return; } $reopened = $this->reopen(); + if ($key === 'client.flow.v2.state.token' || $key === 'client.flow.state.token') { + logger('core')->error('Reporting on whether session was reopened', [ + 'loginFlow' => str_contains($key, 'v2') ? 'v2' : 'v1', + 'sessionReopened' => $reopened, + ]); + } + $this->sessionValues[$key] = $value; if ($key === 'client.flow.v2.state.token' || $key === 'client.flow.state.token') { logger('core')->error('Saving state token with session', [ diff --git a/lib/private/Session/Internal.php b/lib/private/Session/Internal.php index 87dd5ed6014..6ed1d02f821 100644 --- a/lib/private/Session/Internal.php +++ b/lib/private/Session/Internal.php @@ -36,6 +36,7 @@ namespace OC\Session; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Token\IProvider; use OCP\Session\Exceptions\SessionNotAvailableException; +use function OCP\Log\logger; /** * Class Internal @@ -221,6 +222,10 @@ class Internal extends Session { return call_user_func_array($functionName, $parameters); } } catch (\Error $e) { + logger('core')->error('trapping a session error', [ + 'loginFlow' => '?', + 'exception' => $e, + ]); $this->trapError($e->getCode(), $e->getMessage()); } }