Enforce account-active status across the auth lifecycle
active? was only checked at the password step of sign-in. A user disabled afterwards could (a) still complete the 2FA step and mint a valid session, and (b) keep using any existing session until natural expiry, because per-request auth only checked session expiry, not user status. Three enforcement points: - Mid-flow guard: verify_totp and webauthn_verify re-check active? before start_new_session_for, clearing the pending session and rejecting if disabled. - Request-time guard: find_session_by_cookie now uses Session.for_active_user, so a session whose user is disabled no longer authenticates (authoritative, catches any disable path including direct DB changes). - Immediate cleanup: User#revoke_sessions_when_deactivated destroys a user's sessions when status changes away from active, so access is revoked everywhere at once rather than on the next request. Tests cover the mid-flow TOTP rejection, request-time rejection of an existing session after disable, session destruction on disable, and that unrelated updates leave sessions intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,16 @@ class SessionsController < ApplicationController
|
||||
return
|
||||
end
|
||||
|
||||
# Re-check account status: active? was verified at the password step, but an
|
||||
# admin may have disabled the account while the user sat on this 2FA screen.
|
||||
# Without this, a disabled account could still mint a valid session here.
|
||||
unless user.active?
|
||||
session.delete(:pending_totp_user_id)
|
||||
session.delete(:pending_remember_me)
|
||||
redirect_to signin_path, alert: "Your account is not active. Please contact an administrator."
|
||||
return
|
||||
end
|
||||
|
||||
remember_me = session.delete(:pending_remember_me) || false
|
||||
|
||||
# Try TOTP verification first (password + TOTP = 2FA)
|
||||
@@ -241,6 +251,14 @@ class SessionsController < ApplicationController
|
||||
return
|
||||
end
|
||||
|
||||
# Re-check account status: an admin may have disabled the account between the
|
||||
# password step and this passkey verification. Reject before creating a session.
|
||||
unless user.active?
|
||||
session.delete(:pending_webauthn_user_id)
|
||||
render json: {error: "Your account is not active."}, status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
# Get the credential and assertion from params
|
||||
credential_data = params[:credential]
|
||||
if credential_data.blank?
|
||||
|
||||
Reference in New Issue
Block a user