1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 11:46:49 +00:00
Commit graph

61 commits

Author SHA1 Message Date
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
catborise
da63e570e5 fix(accounts): the "Lost OTP?" page cannot be used to flood or break
/accounts/email_otp/ mails a user their OTP QR code and needs no login.
Measured with the default settings (OTP disabled):

- It was reachable although OTP was off, and created OTP devices.
- Every request sent a mail: 20 requests for one address, 20 mails, so
  anyone who knew an address could fill that mailbox.
- An address shared by two users, or a mail server that could not be
  reached, ended in an error page (500).
- Inactive users were mailed too.

The page now exists only while OTP_ENABLED is set. It mails a single
active user whose address matches (case-insensitively), at most once
every 5 minutes per user (Django's cache: with several workers the
bound is per worker), and logs a failed delivery. The answer is the
same in every case, so it does not reveal whether an address belongs
to a user.

The QR codes come from django-qr-code (segno); both the mail and the
account page render them without the qrcode package removed earlier.
The new tests fail on the previous code.
2026-10-05 20:06:02 +03:00
catborise
e94d69a524 feat(accounts): Django's LoginRequiredMiddleware replaces the package
django-login-required-middleware is dropped; Django 5.1+ ships the same
middleware. The login page is already marked login_not_required by
Django; email_otp gets the decorator, which replaces
LOGIN_REQUIRED_IGNORE_VIEW_NAMES. The datasource still requires login.

Existing settings.py files still name the old middleware. A system
check (accounts.E002) stops migrate and the server until MIDDLEWARE
uses Django's middleware, instead of an ImportError at startup; the
README has the steps.

A new matrix test walks every URL anonymously: everything outside a
short allowlist (login pages, the OpenAPI docs) sends the visitor to
the login page, and API views deny with 401/403. It passed with the old
middleware first and passes unchanged now.
2026-10-04 01:08:11 +03:00
catborise
b04f656d2b ci: replace super-linter with ruff
Super-linter ran from the unpinned :latest image and, because of
branches-ignore: [master], never on pull requests to master. Ruff now
checks syntax errors and pyflakes rules (E9, F) on every push and PR.

Fixes the existing findings: unused imports and variables, an unused
duplicate import in instances/tests.py, and the star import in
accounts/views.py. settings-dev.py keeps its star import of the base
settings.
2026-10-04 01:08:11 +03:00
catborise
6dabd69445 fix(accounts): first-login password change is stored, not in the session
The forced change of the generated admin password was a session flag
set at login when the password still matched data/admin_password. A
new session after the file was gone bypassed it.

- UserAttributes.must_change_password (migration 0007) holds it; the
  admin created with a generated password gets it, and a password
  change clears it. ForcePasswordChangeMiddleware reads it.
- A system check (accounts.E001) stops the server unless the middleware
  follows AuthenticationMiddleware; the README has the settings change.
- If the generated password cannot be stored privately, provisioning
  stops without printing it and without creating the admin (one
  transaction for the user and its attributes).
- The admin is provisioned on any real migrate run while no user
  exists, so running migrate again after a failure creates it; flush
  (plan=None) and rollbacks of accounts are skipped.
- The post_migrate receivers check the migration state for the models
  they use, so a targeted migrate on a fresh database (e.g. migrate
  appsettings) no longer fails with 'no such table'.
2026-10-04 01:08:11 +03:00
catborise
78852eb4c8 feat(accounts): force a password change at the first login with the generated password
While data/admin_password exists and a user's password still matches it,
the login sets a session flag (checked once at login, not per request).
ForcePasswordChangeMiddleware then sends that user to the password-change
page for every view except change password, login and logout. Setting a
new password clears the flag and deletes data/admin_password. No schema
change; if ADMIN_PASSWORD was set, there is no file and nothing is forced.
2026-10-02 23:55:31 +03:00
catborise
cf1cde376b fix: require POST for user block/unblock and OTP email, flag console cookie
- user_block, user_unblock and admin_email_otp changed state on GET, so an
  <img> tag could lock a user out or trigger OTP emails through an
  admin's session. They now require POST; the buttons are CSRF forms.
- The console token cookie is set with httponly, SameSite=Lax and, on
  HTTPS, secure. Only novncd reads it; the page gets the token directly.
2026-10-02 22:44:00 +03:00
catborise
b3e6fb2b7a feat(security): enforce require_POST on power actions, prevent open redirects, and isolate instance permissions 2026-09-27 13:20:45 +03:00
Emre Serdengeçti
1cbdf76df6
logger updates (#31)
* Log for failed login attempts

* Logger configuration for logging to file

* interface fixes

* login log fix, added logged in too

* bootstrap icons setup

* font-awesome icons replaced with bootstrap icons

* replaced i-tags with django_bootstrap_icons

* removed icons library from project

* bug fix

---------

Co-authored-by: catborise <catborise@gmail.com>
2023-08-09 09:20:18 +03:00
catborise
a1eab70e2d reorg imports and black format 2022-11-02 16:05:41 +03:00
catborise
217e106c8b format python code with black 2022-11-02 08:54:35 +03:00
catborise
508e3609be lint with black python. convert f style strings to old one. some small fixes 2020-11-05 12:34:31 +03:00
Real-Gecko
1f26bd0c31 Do not send email if user email is not set 2020-10-19 17:11:28 +06:00
Real-Gecko
5a19f0c949 OTP improvements 2020-10-19 14:26:08 +06:00
Real-Gecko
5172a9f619 Accounts app improvements and tests 2020-10-14 14:25:05 +03:00
Real-Gecko
0052323190 Implemented OTP #341 2020-10-08 17:57:51 +06:00
catborise
922a8e62d1 fix some linter warnings 2020-09-25 15:57:17 +03:00
catborise
aee7fa34b8 fix user not found while editing user profile 2020-09-25 09:21:37 +03:00
Real-Gecko
47009d47ca Instances overhaul 2020-07-13 15:33:09 +06:00
Real-Gecko
636b5bb1bc Reworked some account views 2020-06-16 18:35:08 +06:00
Real-Gecko
b85e246aed Moved password changing to a separate view 2020-06-16 14:36:53 +06:00
Real-Gecko
20d4aaac30 Removed UserAddForm as it is not used 2020-06-16 11:09:55 +06:00
catborise
e46bb99b3b fix typos and rearrange imports & add new lines EOF 2020-06-04 15:22:55 +03:00
catborise
7538ddab4f Add all settings to appsettings page & Convert settings choices 2020-06-04 12:32:00 +03:00
catborise
0e5840498e bootstrap 4.5 & Bootswatch Themes 2020-06-04 11:33:25 +03:00
Real-Gecko
a62daad87b Added change password permission
Replaces SHOW_PROFILE_EDIT_PASSWORD option
Can be set on per user or per group basis
2020-05-27 18:46:37 +06:00
Real-Gecko
27f62dff6c Added admin application
- Manage users
- Manage groups
- Manage logs
2020-05-27 18:24:06 +06:00
Real-Gecko
38befa4362 Added django-login-required-middleware
Thus eliminating need for login_requred decorator on every view
2020-05-27 12:43:29 +06:00
catborise
a6f7618854 convert django.core.urlresolver to django.urls. fix i18n. fix identation 2020-01-24 10:09:46 +03:00
catborise
828a271789 pep8 style code corrections 2019-09-10 09:48:31 +03:00
Ing. Jan KRCMAR
b909b9d0f1 Merge remote-tracking branch 'retspen/master' into upgrade_django 2018-07-26 12:44:22 +02:00
Ing. Jan KRCMAR
9f7ec62226 accounts: add public key check 2018-07-26 11:33:12 +02:00
catborise
ace30ca952 Libxml2 converted to lxml, django framework upgrade to 1.11.x and some bug fixes 2018-06-27 10:20:51 +03:00
Ing. Jan KRCMAR
43a8fb6dc1 add accounts view style list. configurable via settings.VIEW_ACCOUNTS_STYLE 2018-05-15 14:22:10 +02:00
Ing. Jan KRCMAR
6e5e10594c SHOW_PROFILE_EDIT_PASSWORD, SHOW_ACCESS_ROOT_PASSWORD, SHOW_ACCESS_SSH_KEYS in settings.py are not inherited in templates. they are now forwarded directly into views. 2018-05-07 10:51:23 +02:00
Ing. Jan KRCMAR
fdca3cef9c account view now displays user public keys 2017-11-15 12:55:05 +01:00
Ing. Jan KRCMAR
b095a77da5 configure_user() moved from class MyRemoteUserBackend to class UserAttributes, as static factory.
call configure_user() while adding user from form
2017-07-18 15:05:30 +02:00
Ing. Jan KRCMAR
3e709cd253 accounts/views: do not redirect to profile, if user wants to see self 2017-06-06 15:07:02 +02:00
Ing. Jan KRCMAR
fe89af9d8f using custom accounts.backends.MyRemoteUserBackend, which adds default instances and attributes for user
create_missing_userattributes removed from accounts view
2017-03-31 14:29:27 +02:00
Daniel Rieper
29b722ff41 Merge branch 'master' of https://github.com/honza801/webvirtcloud
Conflicts:
	instances/templates/instance.html
	instances/views.py
2016-07-29 13:05:54 +02:00
Ing. Jan KRCMAR
3666ff0738 settings.ALLOW_EMPTY_PASSWORD added. allows to create user withnout password. useful with SSO authentication. 2016-06-02 13:39:18 +02:00
Valentin Samir
7efbfec17f Add an option to allow an user to change VNC settings 2016-05-09 12:09:21 +02:00
Jan Krcmar
9327cf36c4 accounts view sorts users by username 2016-05-06 14:39:52 +02:00
Jan Krcmar
8de4c6b131 /accounts view creates userattributes automatically 2016-04-26 08:50:58 +02:00
Jan Krcmar
f8e681dbf4 added user disk quota limit
added quota warning in instance page
2016-03-31 13:12:52 +02:00
Jan Krcmar
317c2a85ae user can now clone instances, admin can specify user quotas (instances,cpus,memory)
user can only select predefined instance names, mac and disk names are selected automatically
2016-03-23 09:00:42 +01:00
Jan Krcmar
9832e662a8 account create_user_instance form sorts instances by name 2016-03-21 10:24:09 +01:00
Jan Krcmar
71c6161291 accounts/edit added is_staff and is_superuser checkboxes
list all users (previously staff and admins were not displayed)
2016-02-09 11:16:36 +01:00
Jan Krcmar
8deb844c35 adding new instance to user checks existing instances assigned to user 2016-01-19 15:43:56 +01:00
Jan Krcmar
6151792d9b allow multiple owners of single instance. this is controlled by settings.ALLOW_INSTANCE_MULTIPLE_OWNER 2016-01-15 10:12:03 +01:00