1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/accounts
catborise 40287dbd2a fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA
With OTP_ENABLED the login used django-otp's OTPAuthenticationForm. Under the
pinned django-otp 1.7.3 that form could not log anyone in through the shipped
page: the page posts only a 6-digit otp_token, but the form now needs the
device named explicitly, so an enrolled user got "Please select a device.",
and a user who never enrolled got "Please enter your OTP token." with no
device to produce one. Verified in an isolated test database.

SingleDeviceOTPForm makes OTP per user: a user with a confirmed TOTP device
must enter a valid code; a user without one logs in with the password alone.
The form chooses the device itself (the user's oldest confirmed TOTP device,
locked with select_for_update inside clean_otp's transaction so replay and
throttling counters cannot race) and ignores any posted otp_device, which
django-otp does not check for confirmed status or type. The login page drops
the HTML "required" on the token field (the field is optional for an
unenrolled user) and says so.

The "Lost OTP?" page (email_otp) created a confirmed device when none existed.
With per-user OTP that let anyone who knows an address turn a password-only
account into an OTP-required one and, if the mail never arrived, lock it out.
It now resends the QR only to a user who already enrolled and never creates a
device (get_existing_totp_device); admin enrollment (admin_email_otp) still
creates one. Email QR distribution and confirmed-on-create enrollment are
unchanged by user decision.

Tests: per-user login (no device -> password only; device -> valid token
passes, wrong/empty token fails), a posted or another user's device is not
used, a token cannot be replayed, and the real login page over HTTP with
OTP_ENABLED; email_otp sends nothing and creates no device for an unenrolled
user. The new tests fail on the previous code.
2026-10-07 08:48:55 +03:00
..
migrations fix(accounts): migrate no longer overrides the change-password permission 2026-10-04 20:26:53 +03:00
templates fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
templatetags lint with black python. convert f style strings to old one. some small fixes 2020-11-05 12:34:31 +03:00
__init__.py Fixe migrations for new deployments 2020-05-28 18:19:25 +06:00
apps.py fix(accounts): migrate no longer overrides the change-password permission 2026-10-04 20:26:53 +03:00
checks.py fix(accounts): migrate no longer overrides the change-password permission 2026-10-04 20:26:53 +03:00
forms.py format python code with black 2022-11-02 08:54:35 +03:00
lockout.py feat(accounts): failed logins lock a user for the address they come from 2026-10-06 11:05:03 +03:00
middleware.py fix(accounts): first-login password change is stored, not in the session 2026-10-04 01:08:11 +03:00
models.py fix(accounts): first-login password change is stored, not in the session 2026-10-04 01:08:11 +03:00
otp.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
test_admin_email_otp.py chore: drop references to the local roadmap from code and tests 2026-10-04 11:09:25 +03:00
test_admin_password.py feat(accounts): failed logins lock a user for the address they come from 2026-10-06 11:05:03 +03:00
test_change_password_permission.py fix(accounts): migrate no longer overrides the change-password permission 2026-10-04 20:26:53 +03:00
test_checks.py feat(accounts): Django's LoginRequiredMiddleware replaces the package 2026-10-04 01:08:11 +03:00
test_email_otp.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
test_first_login_password.py feat(accounts): failed logins lock a user for the address they come from 2026-10-06 11:05:03 +03:00
test_login_lockout.py feat(accounts): failed logins lock a user for the address they come from 2026-10-06 11:05:03 +03:00
test_otp_login.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
test_security_fixes.py feat(security): enforce require_POST on power actions, prevent open redirects, and isolate instance permissions 2026-09-27 13:20:45 +03:00
test_utils.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
tests.py feat(accounts): failed logins lock a user for the address they come from 2026-10-06 11:05:03 +03:00
urls.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
utils.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00
views.py fix(accounts): OTP login works per user and "Lost OTP?" cannot impose 2FA 2026-10-07 08:48:55 +03:00