Skip to content

Commit 9ccb363

Browse files
fix(AppFramework): apply legacy PasswordConfirmation exemptions in both strict and non-strict modes
Previously the legacy exemption list was only consulted in the non-strict branch. Signed-off-by: Josh <josh.t.richards@gmail.com>
1 parent 9947e38 commit 9ccb363

1 file changed

Lines changed: 21 additions & 15 deletions

File tree

lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use OCP\Authentication\Token\IToken;
2121
use OCP\IRequest;
2222
use OCP\ISession;
23+
use OCP\IUser;
2324
use OCP\IUserSession;
2425
use OCP\Session\Exceptions\SessionNotAvailableException;
2526
use OCP\User\Backend\IPasswordConfirmationBackend;
@@ -32,9 +33,9 @@ class PasswordConfirmationMiddleware extends Middleware {
3233
private const PASSWORD_CONFIRMATION_GRACE_SECONDS = 15;
3334

3435
/**
35-
* Legacy compatibility allowlist for backends that do not participate in the
36-
* non-strict recent-confirmation flow. New backends should prefer implementing
37-
* IPasswordConfirmationBackend instead of being added here.
36+
* Backends that cannot participate in password confirmation are exempt from both
37+
* strict and non-strict password confirmation checks. New backends should prefer
38+
* implementing IPasswordConfirmationBackend instead of being added here.
3839
*
3940
* @var array<string, true>
4041
*/
@@ -74,13 +75,14 @@ public function beforeController(Controller $controller, string $methodName) {
7475
$sessionId = $this->session->getId();
7576
$token = $this->tokenProvider->getToken($sessionId);
7677
} catch (SessionNotAvailableException|InvalidTokenException|WipeTokenException|ExpiredTokenException) {
77-
// Only valid interactive session tokens participate in password confirmation. Requests without such a
78-
// token are left to be rejected or otherwise handled by the normal authentication/session handling.
78+
// Password confirmation is only enforced for requests backed by a valid interactive session token.
79+
// Requests without such a token are left to be rejected or otherwise handled by the normal
80+
// authentication/session middleware stack.
7981
return;
8082
}
8183

8284
if ($this->isTokenExemptFromPasswordConfirmation($token)) {
83-
// Users logging in from SSO backends cannot confirm their password by design
85+
// Some session tokens are marked to skip password validation entirely.
8486
return;
8587
}
8688

@@ -96,11 +98,7 @@ public function beforeController(Controller $controller, string $methodName) {
9698
$minimumRequiredConfirmTime = $now
9799
- (self::PASSWORD_CONFIRMATION_TIMEOUT + self::PASSWORD_CONFIRMATION_GRACE_SECONDS);
98100

99-
// TODO: confirm excludedUserBackEnds can go away and remove it
100-
if (
101-
!$this->isLegacyBackendExcludedFromRecentConfirmation($user)
102-
&& $lastConfirm < $minimumRequiredConfirmTime
103-
) {
101+
if ($lastConfirm < $minimumRequiredConfirmTime) {
104102
throw new NotConfirmedException();
105103
}
106104
}
@@ -124,12 +122,20 @@ private function isBackendExemptFromPasswordConfirmation(?IUser $user): bool {
124122
}
125123

126124
$backend = $user->getBackend();
127-
return $backend instanceof IPasswordConfirmationBackend
128-
&& !$backend->canConfirmPassword($user->getUID());
125+
126+
if (
127+
$backend instanceof IPasswordConfirmationBackend
128+
&& !$backend->canConfirmPassword($user->getUID())
129+
) {
130+
return true;
131+
}
132+
133+
return $this->isLegacyBackendExcludedFromRecentConfirmation($user);
129134
}
130135

131136
private function isLegacyBackendExcludedFromRecentConfirmation(?IUser $user): bool {
132137
$backendClassName = $user?->getBackendClassName() ?? '';
138+
// TODO: confirm excludedUserBackEnds can go away and remove it
133139
return isset($this->excludedUserBackEnds[$backendClassName]);
134140
}
135141

@@ -143,9 +149,9 @@ private function isTokenExemptFromPasswordConfirmation(IToken $token): bool {
143149
* @throws NotConfirmedException
144150
*/
145151
private function confirmPasswordFromAuthorizationHeader(): void {
146-
$authHeader = strtolower($this->request->getHeader('Authorization'));
152+
$authHeader = $this->request->getHeader('Authorization');
147153

148-
if (!str_starts_with($authHeader, 'basic ')) {
154+
if (!str_starts_with(strtolower($authHeader), 'basic ')) {
149155
throw new NotConfirmedException('Required authorization header missing');
150156
}
151157

0 commit comments

Comments
 (0)