aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2025-02-10 16:42:48 +0100
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>2025-02-27 07:59:49 +0000
commite840ee72b233471830892ac6fecc91387d17a93d (patch)
tree0815427b98bea3af1b159903683ce5425491a29c
parent6e52b55555d08f61b21e2b2fdfbe9d394daabdd1 (diff)
downloadnextcloud-server-e840ee72b233471830892ac6fecc91387d17a93d.tar.gz
nextcloud-server-e840ee72b233471830892ac6fecc91387d17a93d.zip
feat: Close sessions created for login flow v2
Sessions created during the login flow v2 should be short lived to not leave an unexpected opened session in the browser. This commit add a property to the session object to track its origin, and will close it as soon as possible, i.e., on the first non public page request. Signed-off-by: Louis Chemineau <louis@chmn.me>
-rw-r--r--core/Controller/ClientFlowLoginV2Controller.php2
-rw-r--r--lib/composer/composer/autoload_classmap.php2
-rw-r--r--lib/composer/composer/autoload_static.php2
-rw-r--r--lib/private/AppFramework/DependencyInjection/DIContainer.php8
-rw-r--r--lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php46
-rw-r--r--lib/private/Authentication/Login/Chain.php75
-rw-r--r--lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php27
7 files changed, 101 insertions, 61 deletions
diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php
index 4bd2cddd12b..1ce43c19932 100644
--- a/core/Controller/ClientFlowLoginV2Controller.php
+++ b/core/Controller/ClientFlowLoginV2Controller.php
@@ -41,6 +41,8 @@ use OCP\Security\ISecureRandom;
class ClientFlowLoginV2Controller extends Controller {
public const TOKEN_NAME = 'client.flow.v2.login.token';
public const STATE_NAME = 'client.flow.v2.state.token';
+ // Denotes that the session was created for the login flow and should therefore be ephemeral.
+ public const EPHEMERAL_NAME = 'client.flow.v2.state.ephemeral';
public function __construct(
string $appName,
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index b6095032c4c..26389031e2a 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -982,6 +982,7 @@ return array(
'OC\\AppFramework\\Http\\RequestId' => $baseDir . '/lib/private/AppFramework/Http/RequestId.php',
'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php',
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
+ 'OC\\AppFramework\\Middleware\\FlowV2EphemeralSessionsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php',
'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => $baseDir . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php',
'OC\\AppFramework\\Middleware\\NotModifiedMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php',
'OC\\AppFramework\\Middleware\\OCSMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/OCSMiddleware.php',
@@ -1079,6 +1080,7 @@ return array(
'OC\\Authentication\\Login\\CreateSessionTokenCommand' => $baseDir . '/lib/private/Authentication/Login/CreateSessionTokenCommand.php',
'OC\\Authentication\\Login\\EmailLoginCommand' => $baseDir . '/lib/private/Authentication/Login/EmailLoginCommand.php',
'OC\\Authentication\\Login\\FinishRememberedLoginCommand' => $baseDir . '/lib/private/Authentication/Login/FinishRememberedLoginCommand.php',
+ 'OC\\Authentication\\Login\\FlowV2EphemeralSessionsCommand' => $baseDir . '/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php',
'OC\\Authentication\\Login\\LoggedInCheckCommand' => $baseDir . '/lib/private/Authentication/Login/LoggedInCheckCommand.php',
'OC\\Authentication\\Login\\LoginData' => $baseDir . '/lib/private/Authentication/Login/LoginData.php',
'OC\\Authentication\\Login\\LoginResult' => $baseDir . '/lib/private/Authentication/Login/LoginResult.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 66df44dfb06..d76c97ecc07 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1031,6 +1031,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\AppFramework\\Http\\RequestId' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/RequestId.php',
'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php',
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
+ 'OC\\AppFramework\\Middleware\\FlowV2EphemeralSessionsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php',
'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php',
'OC\\AppFramework\\Middleware\\NotModifiedMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php',
'OC\\AppFramework\\Middleware\\OCSMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/OCSMiddleware.php',
@@ -1128,6 +1129,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Authentication\\Login\\CreateSessionTokenCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/CreateSessionTokenCommand.php',
'OC\\Authentication\\Login\\EmailLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/EmailLoginCommand.php',
'OC\\Authentication\\Login\\FinishRememberedLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/FinishRememberedLoginCommand.php',
+ 'OC\\Authentication\\Login\\FlowV2EphemeralSessionsCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php',
'OC\\Authentication\\Login\\LoggedInCheckCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoggedInCheckCommand.php',
'OC\\Authentication\\Login\\LoginData' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoginData.php',
'OC\\Authentication\\Login\\LoginResult' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoginResult.php',
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index be4f6897da8..e1a2fefc55a 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -10,6 +10,7 @@ use OC;
use OC\AppFramework\Http;
use OC\AppFramework\Http\Dispatcher;
use OC\AppFramework\Http\Output;
+use OC\AppFramework\Middleware\FlowV2EphemeralSessionsMiddleware;
use OC\AppFramework\Middleware\MiddlewareDispatcher;
use OC\AppFramework\Middleware\OCSMiddleware;
use OC\AppFramework\Middleware\Security\CORSMiddleware;
@@ -216,7 +217,12 @@ class DIContainer extends SimpleContainer implements IAppContainer {
)
);
-
+ $dispatcher->registerMiddleware(
+ new FlowV2EphemeralSessionsMiddleware(
+ $c->get(ISession::class),
+ $c->get(IUserSession::class),
+ )
+ );
$securityMiddleware = new SecurityMiddleware(
$c->get(IRequest::class),
diff --git a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
new file mode 100644
index 00000000000..b3e406adf22
--- /dev/null
+++ b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
@@ -0,0 +1,46 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OC\AppFramework\Middleware;
+
+use OC\Core\Controller\ClientFlowLoginV2Controller;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Middleware;
+use OCP\ISession;
+use OCP\IUserSession;
+use ReflectionMethod;
+
+// Will close the session if the user session is ephemeral.
+// Happens when the user logs in via the login flow v2.
+class FlowV2EphemeralSessionsMiddleware extends Middleware {
+ public function __construct(
+ private ISession $session,
+ private IUserSession $userSession,
+ ) {
+ }
+
+ public function beforeController(Controller $controller, string $methodName) {
+ if (!$this->session->get(ClientFlowLoginV2Controller::EPHEMERAL_NAME)) {
+ return;
+ }
+
+ if (
+ $controller instanceof ClientFlowLoginV2Controller &&
+ ($methodName === 'grantPage' || $methodName === 'generateAppPassword')
+ ) {
+ return;
+ }
+
+ $reflectionMethod = new ReflectionMethod($controller, $methodName);
+ if (!empty($reflectionMethod->getAttributes('PublicPage'))) {
+ return;
+ }
+
+ $this->userSession->logout();
+ $this->session->close();
+ }
+}
diff --git a/lib/private/Authentication/Login/Chain.php b/lib/private/Authentication/Login/Chain.php
index 3cba396afdd..09030a154a6 100644
--- a/lib/private/Authentication/Login/Chain.php
+++ b/lib/private/Authentication/Login/Chain.php
@@ -9,67 +9,21 @@ declare(strict_types=1);
namespace OC\Authentication\Login;
class Chain {
- /** @var PreLoginHookCommand */
- private $preLoginHookCommand;
-
- /** @var UserDisabledCheckCommand */
- private $userDisabledCheckCommand;
-
- /** @var UidLoginCommand */
- private $uidLoginCommand;
-
- /** @var EmailLoginCommand */
- private $emailLoginCommand;
-
- /** @var LoggedInCheckCommand */
- private $loggedInCheckCommand;
-
- /** @var CompleteLoginCommand */
- private $completeLoginCommand;
-
- /** @var CreateSessionTokenCommand */
- private $createSessionTokenCommand;
-
- /** @var ClearLostPasswordTokensCommand */
- private $clearLostPasswordTokensCommand;
-
- /** @var UpdateLastPasswordConfirmCommand */
- private $updateLastPasswordConfirmCommand;
-
- /** @var SetUserTimezoneCommand */
- private $setUserTimezoneCommand;
-
- /** @var TwoFactorCommand */
- private $twoFactorCommand;
-
- /** @var FinishRememberedLoginCommand */
- private $finishRememberedLoginCommand;
-
- public function __construct(PreLoginHookCommand $preLoginHookCommand,
- UserDisabledCheckCommand $userDisabledCheckCommand,
- UidLoginCommand $uidLoginCommand,
- EmailLoginCommand $emailLoginCommand,
- LoggedInCheckCommand $loggedInCheckCommand,
- CompleteLoginCommand $completeLoginCommand,
- CreateSessionTokenCommand $createSessionTokenCommand,
- ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand,
- UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand,
- SetUserTimezoneCommand $setUserTimezoneCommand,
- TwoFactorCommand $twoFactorCommand,
- FinishRememberedLoginCommand $finishRememberedLoginCommand,
+ public function __construct(
+ private PreLoginHookCommand $preLoginHookCommand,
+ private UserDisabledCheckCommand $userDisabledCheckCommand,
+ private UidLoginCommand $uidLoginCommand,
+ private EmailLoginCommand $emailLoginCommand,
+ private LoggedInCheckCommand $loggedInCheckCommand,
+ private CompleteLoginCommand $completeLoginCommand,
+ private CreateSessionTokenCommand $createSessionTokenCommand,
+ private ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand,
+ private UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand,
+ private SetUserTimezoneCommand $setUserTimezoneCommand,
+ private TwoFactorCommand $twoFactorCommand,
+ private FinishRememberedLoginCommand $finishRememberedLoginCommand,
+ private FlowV2EphemeralSessionsCommand $flowV2EphemeralSessionsCommand,
) {
- $this->preLoginHookCommand = $preLoginHookCommand;
- $this->userDisabledCheckCommand = $userDisabledCheckCommand;
- $this->uidLoginCommand = $uidLoginCommand;
- $this->emailLoginCommand = $emailLoginCommand;
- $this->loggedInCheckCommand = $loggedInCheckCommand;
- $this->completeLoginCommand = $completeLoginCommand;
- $this->createSessionTokenCommand = $createSessionTokenCommand;
- $this->clearLostPasswordTokensCommand = $clearLostPasswordTokensCommand;
- $this->updateLastPasswordConfirmCommand = $updateLastPasswordConfirmCommand;
- $this->setUserTimezoneCommand = $setUserTimezoneCommand;
- $this->twoFactorCommand = $twoFactorCommand;
- $this->finishRememberedLoginCommand = $finishRememberedLoginCommand;
}
public function process(LoginData $loginData): LoginResult {
@@ -80,6 +34,7 @@ class Chain {
->setNext($this->emailLoginCommand)
->setNext($this->loggedInCheckCommand)
->setNext($this->completeLoginCommand)
+ ->setNext($this->flowV2EphemeralSessionsCommand)
->setNext($this->createSessionTokenCommand)
->setNext($this->clearLostPasswordTokensCommand)
->setNext($this->updateLastPasswordConfirmCommand)
diff --git a/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php b/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php
new file mode 100644
index 00000000000..b215df1523f
--- /dev/null
+++ b/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Authentication\Login;
+
+use OC\Core\Controller\ClientFlowLoginV2Controller;
+use OCP\ISession;
+
+class FlowV2EphemeralSessionsCommand extends ALoginCommand {
+ public function __construct(
+ private ISession $session,
+ ) {
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if (str_starts_with($loginData->getRedirectUrl() ?? '', '/login/v2/grant')) {
+ $this->session->set(ClientFlowLoginV2Controller::EPHEMERAL_NAME, true);
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+}