Skip to content

Commit c68656a

Browse files
committed
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>
1 parent bfaa1ae commit c68656a

7 files changed

Lines changed: 101 additions & 61 deletions

File tree

core/Controller/ClientFlowLoginV2Controller.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
class ClientFlowLoginV2Controller extends Controller {
5858
public const TOKEN_NAME = 'client.flow.v2.login.token';
5959
public const STATE_NAME = 'client.flow.v2.state.token';
60+
// Denotes that the session was created for the login flow and should therefore be ephemeral.
61+
public const EPHEMERAL_NAME = 'client.flow.v2.state.ephemeral';
6062

6163
public function __construct(
6264
string $appName,

lib/composer/composer/autoload_classmap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@
853853
'OC\\AppFramework\\Logger' => $baseDir . '/lib/private/AppFramework/Logger.php',
854854
'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php',
855855
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
856+
'OC\\AppFramework\\Middleware\\FlowV2EphemeralSessionsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php',
856857
'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => $baseDir . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php',
857858
'OC\\AppFramework\\Middleware\\NotModifiedMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php',
858859
'OC\\AppFramework\\Middleware\\OCSMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/OCSMiddleware.php',
@@ -948,6 +949,7 @@
948949
'OC\\Authentication\\Login\\CreateSessionTokenCommand' => $baseDir . '/lib/private/Authentication/Login/CreateSessionTokenCommand.php',
949950
'OC\\Authentication\\Login\\EmailLoginCommand' => $baseDir . '/lib/private/Authentication/Login/EmailLoginCommand.php',
950951
'OC\\Authentication\\Login\\FinishRememberedLoginCommand' => $baseDir . '/lib/private/Authentication/Login/FinishRememberedLoginCommand.php',
952+
'OC\\Authentication\\Login\\FlowV2EphemeralSessionsCommand' => $baseDir . '/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php',
951953
'OC\\Authentication\\Login\\LoggedInCheckCommand' => $baseDir . '/lib/private/Authentication/Login/LoggedInCheckCommand.php',
952954
'OC\\Authentication\\Login\\LoginData' => $baseDir . '/lib/private/Authentication/Login/LoginData.php',
953955
'OC\\Authentication\\Login\\LoginResult' => $baseDir . '/lib/private/Authentication/Login/LoginResult.php',

lib/composer/composer/autoload_static.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
886886
'OC\\AppFramework\\Logger' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Logger.php',
887887
'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php',
888888
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
889+
'OC\\AppFramework\\Middleware\\FlowV2EphemeralSessionsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php',
889890
'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php',
890891
'OC\\AppFramework\\Middleware\\NotModifiedMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php',
891892
'OC\\AppFramework\\Middleware\\OCSMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/OCSMiddleware.php',
@@ -981,6 +982,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
981982
'OC\\Authentication\\Login\\CreateSessionTokenCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/CreateSessionTokenCommand.php',
982983
'OC\\Authentication\\Login\\EmailLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/EmailLoginCommand.php',
983984
'OC\\Authentication\\Login\\FinishRememberedLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/FinishRememberedLoginCommand.php',
985+
'OC\\Authentication\\Login\\FlowV2EphemeralSessionsCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/FlowV2EphemeralSessionsCommand.php',
984986
'OC\\Authentication\\Login\\LoggedInCheckCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoggedInCheckCommand.php',
985987
'OC\\Authentication\\Login\\LoginData' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoginData.php',
986988
'OC\\Authentication\\Login\\LoginResult' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoginResult.php',

lib/private/AppFramework/DependencyInjection/DIContainer.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use OC\AppFramework\Http;
3838
use OC\AppFramework\Http\Dispatcher;
3939
use OC\AppFramework\Http\Output;
40+
use OC\AppFramework\Middleware\FlowV2EphemeralSessionsMiddleware;
4041
use OC\AppFramework\Middleware\MiddlewareDispatcher;
4142
use OC\AppFramework\Middleware\OCSMiddleware;
4243
use OC\AppFramework\Middleware\Security\CORSMiddleware;
@@ -244,7 +245,12 @@ public function __construct(string $appName, array $urlParams = [], ?ServerConta
244245
)
245246
);
246247

247-
248+
$dispatcher->registerMiddleware(
249+
new FlowV2EphemeralSessionsMiddleware(
250+
$c->get(ISession::class),
251+
$c->get(IUserSession::class),
252+
)
253+
);
248254

249255
$securityMiddleware = new SecurityMiddleware(
250256
$c->get(IRequest::class),
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-only
7+
*/
8+
namespace OC\AppFramework\Middleware;
9+
10+
use OC\Core\Controller\ClientFlowLoginV2Controller;
11+
use OCP\AppFramework\Controller;
12+
use OCP\AppFramework\Middleware;
13+
use OCP\ISession;
14+
use OCP\IUserSession;
15+
use ReflectionMethod;
16+
17+
// Will close the session if the user session is ephemeral.
18+
// Happens when the user logs in via the login flow v2.
19+
class FlowV2EphemeralSessionsMiddleware extends Middleware {
20+
public function __construct(
21+
private ISession $session,
22+
private IUserSession $userSession,
23+
) {
24+
}
25+
26+
public function beforeController(Controller $controller, string $methodName) {
27+
if (!$this->session->get(ClientFlowLoginV2Controller::EPHEMERAL_NAME)) {
28+
return;
29+
}
30+
31+
if (
32+
$controller instanceof ClientFlowLoginV2Controller &&
33+
($methodName === 'grantPage' || $methodName === 'generateAppPassword')
34+
) {
35+
return;
36+
}
37+
38+
$reflectionMethod = new ReflectionMethod($controller, $methodName);
39+
if (!empty($reflectionMethod->getAttributes('PublicPage'))) {
40+
return;
41+
}
42+
43+
$this->userSession->logout();
44+
$this->session->close();
45+
}
46+
}

lib/private/Authentication/Login/Chain.php

Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -26,67 +26,21 @@
2626
namespace OC\Authentication\Login;
2727

2828
class Chain {
29-
/** @var PreLoginHookCommand */
30-
private $preLoginHookCommand;
31-
32-
/** @var UserDisabledCheckCommand */
33-
private $userDisabledCheckCommand;
34-
35-
/** @var UidLoginCommand */
36-
private $uidLoginCommand;
37-
38-
/** @var EmailLoginCommand */
39-
private $emailLoginCommand;
40-
41-
/** @var LoggedInCheckCommand */
42-
private $loggedInCheckCommand;
43-
44-
/** @var CompleteLoginCommand */
45-
private $completeLoginCommand;
46-
47-
/** @var CreateSessionTokenCommand */
48-
private $createSessionTokenCommand;
49-
50-
/** @var ClearLostPasswordTokensCommand */
51-
private $clearLostPasswordTokensCommand;
52-
53-
/** @var UpdateLastPasswordConfirmCommand */
54-
private $updateLastPasswordConfirmCommand;
55-
56-
/** @var SetUserTimezoneCommand */
57-
private $setUserTimezoneCommand;
58-
59-
/** @var TwoFactorCommand */
60-
private $twoFactorCommand;
61-
62-
/** @var FinishRememberedLoginCommand */
63-
private $finishRememberedLoginCommand;
64-
65-
public function __construct(PreLoginHookCommand $preLoginHookCommand,
66-
UserDisabledCheckCommand $userDisabledCheckCommand,
67-
UidLoginCommand $uidLoginCommand,
68-
EmailLoginCommand $emailLoginCommand,
69-
LoggedInCheckCommand $loggedInCheckCommand,
70-
CompleteLoginCommand $completeLoginCommand,
71-
CreateSessionTokenCommand $createSessionTokenCommand,
72-
ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand,
73-
UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand,
74-
SetUserTimezoneCommand $setUserTimezoneCommand,
75-
TwoFactorCommand $twoFactorCommand,
76-
FinishRememberedLoginCommand $finishRememberedLoginCommand
29+
public function __construct(
30+
private PreLoginHookCommand $preLoginHookCommand,
31+
private UserDisabledCheckCommand $userDisabledCheckCommand,
32+
private UidLoginCommand $uidLoginCommand,
33+
private EmailLoginCommand $emailLoginCommand,
34+
private LoggedInCheckCommand $loggedInCheckCommand,
35+
private CompleteLoginCommand $completeLoginCommand,
36+
private CreateSessionTokenCommand $createSessionTokenCommand,
37+
private ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand,
38+
private UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand,
39+
private SetUserTimezoneCommand $setUserTimezoneCommand,
40+
private TwoFactorCommand $twoFactorCommand,
41+
private FinishRememberedLoginCommand $finishRememberedLoginCommand,
42+
private FlowV2EphemeralSessionsCommand $flowV2EphemeralSessionsCommand,
7743
) {
78-
$this->preLoginHookCommand = $preLoginHookCommand;
79-
$this->userDisabledCheckCommand = $userDisabledCheckCommand;
80-
$this->uidLoginCommand = $uidLoginCommand;
81-
$this->emailLoginCommand = $emailLoginCommand;
82-
$this->loggedInCheckCommand = $loggedInCheckCommand;
83-
$this->completeLoginCommand = $completeLoginCommand;
84-
$this->createSessionTokenCommand = $createSessionTokenCommand;
85-
$this->clearLostPasswordTokensCommand = $clearLostPasswordTokensCommand;
86-
$this->updateLastPasswordConfirmCommand = $updateLastPasswordConfirmCommand;
87-
$this->setUserTimezoneCommand = $setUserTimezoneCommand;
88-
$this->twoFactorCommand = $twoFactorCommand;
89-
$this->finishRememberedLoginCommand = $finishRememberedLoginCommand;
9044
}
9145

9246
public function process(LoginData $loginData): LoginResult {
@@ -97,6 +51,7 @@ public function process(LoginData $loginData): LoginResult {
9751
->setNext($this->emailLoginCommand)
9852
->setNext($this->loggedInCheckCommand)
9953
->setNext($this->completeLoginCommand)
54+
->setNext($this->flowV2EphemeralSessionsCommand)
10055
->setNext($this->createSessionTokenCommand)
10156
->setNext($this->clearLostPasswordTokensCommand)
10257
->setNext($this->updateLastPasswordConfirmCommand)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OC\Authentication\Login;
10+
11+
use OC\Core\Controller\ClientFlowLoginV2Controller;
12+
use OCP\ISession;
13+
14+
class FlowV2EphemeralSessionsCommand extends ALoginCommand {
15+
public function __construct(
16+
private ISession $session,
17+
) {
18+
}
19+
20+
public function process(LoginData $loginData): LoginResult {
21+
if (str_contains($loginData->getRedirectUrl() ?? '', '/login/v2/grant')) {
22+
$this->session->set(ClientFlowLoginV2Controller::EPHEMERAL_NAME, true);
23+
}
24+
25+
return $this->processNextOrFinishSuccessfully($loginData);
26+
}
27+
}

0 commit comments

Comments
 (0)