auth: reject inactive users at login + invalidate existing sessions
Two-pronged enforcement so deactivation has effect both for fresh
logins and already-issued sessions:
- load_current_user(): treat User with active=False as logged-out
(sets g.user=None). Existing sessions stop working immediately.
- login(): include `not user.active` in the existing 401 condition,
so deactivated accounts get the same "invalid credentials"
response as wrong-password / unknown-user — no timing oracle for
deactivation status.
Tests still green (12/12 in test_auth.py).
This commit is contained in:
parent
726acfa4ff
commit
3490be5fb7
2 changed files with 7 additions and 2 deletions
|
|
@ -27,7 +27,10 @@ def load_current_user() -> None:
|
|||
g.user = None
|
||||
return
|
||||
with session_scope() as db:
|
||||
g.user = db.scalar(select(User).where(User.id == int(user_id)))
|
||||
user = db.scalar(select(User).where(User.id == int(user_id)))
|
||||
# Treat deactivated users as logged-out so existing sessions stop
|
||||
# working as soon as an admin flips active=False.
|
||||
g.user = user if user is not None and user.active else None
|
||||
|
||||
|
||||
def current_user() -> User | None:
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ def login() -> Response:
|
|||
user = db.scalar(select(User).where(User.username == username))
|
||||
digest = user.password_digest if user is not None else _TIMING_DUMMY_DIGEST
|
||||
password_ok = verify_password(password, digest)
|
||||
if user is None or not password_ok:
|
||||
if user is None or not password_ok or not user.active:
|
||||
# Same generic response for missing user, wrong password, or
|
||||
# deactivated account — no timing oracle for deactivation status.
|
||||
return Response("invalid credentials", status=401)
|
||||
login_user(user.id)
|
||||
LOGIN_ATTEMPTS_BY_IP.pop(remote_addr, None)
|
||||
|
|
|
|||
Loading…
Reference in a new issue