2020use OCP \Authentication \Token \IToken ;
2121use OCP \IRequest ;
2222use OCP \ISession ;
23+ use OCP \IUser ;
2324use OCP \IUserSession ;
2425use OCP \Session \Exceptions \SessionNotAvailableException ;
2526use 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