fix(auth): check reset link expiry against interactive login timestamp - #64126
silverkszlo wants to merge 1 commit into
Conversation
this step is on the normal browser, or the private browser window? i understand the latter.
Hm, there might be an edge case hidden? 🤔 |
|
Auth is a tough area to look into, and full of mines 🙃 Great that you looked into it! On first sight it looks fine, but there are actually a things to improve, also to avoid frequent writes to DB. Findings from a claude review:
|
8ba768f to
8d5af33
Compare
this step is on the normal browser, so after clicking the reset link in the email
might have been, but the error is gone... |
So to mitigate that, Claude came up with wiring
Yes, the link would survive the 7 days for an account that is only used via app passwords. But using a stale link requires reading the account's mailbox and a person with that kind of access can also just request a fresh link? Recording app-password logins would reintroduce the bug this PR fixes, if I understand that correctly. But ofc I am not sure if that is the best way to mitigate that.
done |
Signed-off-by: silver <s.szmajduch@posteo.de> Assisted-by: ClaudeCode:claude-opus-5
8d5af33 to
00e8cbc
Compare
Summary
The bug
When the password of a user expires and they want to reset it while they have an open session somewhere, the "Forgot password" flow sends them into a loop and never allows them to reset their password: logging in is being refused because the password expired, and the emailed reset link is being refused as expired as well.
How to reproduce
occ app:enable password_policyocc config:app:set password_policy expiration --value=1occ user:setting blume password_policy pwd_last_updated $(( $(date +%s) - 10*86400 ))This solution
VerificationTokencompared the reset link's creation time againstIUser::getLastLogin(). Despite its name that value is a "last seen" timestamp.Session::validateSession()refreshes it on every request of an already authenticated session, so it kept moving past the reset link's creation time while the user did nothing but leave a session open.This PR records the time a person authenticated in a browser (
lastInteractiveLogin) and compares against that instead. That is wired into a newRecordInteractiveLoginCommandinside the web loginChain, to filter by where the login came from (browser authentication). Remember-me logins are covered by an additionalUserLoggedInWithCookieListener.Checklist
3. to review, feature component)stable32)AI (if applicable)