- Mostly because administrators won't discover the email address field for the
user later on.
- This field is important to be able to run 'reset password' operation.
Tests:
- In stable and testing containers, run first boot wizard. Enter the email
address during the first boot and see that it was saved as part of user account.
Leave the email address blank and it is possible to proceed. User account show
blank email address.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Veiko Aasa <veiko17@disroot.org>
Fixes: #2409.
When creating a user if one or more groups is selected, creation fails. This
is because the fields contains group choices as (name, label) tuples instead
of (group_id, label) tuples as expected by the many-to-many field mapping
mechanism in ModelField class. Fix this by using the same mechanism used in
UserUpdateForm, which is to reuse the base class form field (but adjust some
properties).
Tests:
- During first boot
- Django groups are fully created when form is accessed with blank database
- In user creation/modify form:
- Label appears are 'Permissions'
- Choices appear fully and as 'Description (Group name)'
- Help text is correct.
- Choices are sorted on group name.
- Django groups are fully created when form is accessed when a new group is
added to code.
- User can have no groups
- Widget is multiple checkbox widget. Multiple groups can be selected.
- User is added to proper ldap groups after submission
- In user modify form:
- If the user is last admin user, admin checkbox is checked and disabled.
- Current list of groups is accurate shown when form is displayed.
- Add remove of groups works as expected
- Functional tests for gitweb and users apps pass
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Veiko Aasa <veiko17@disroot.org>
- Add explicit dependency on django-ipware >=3. django-axes >= 6 adds
only and optional dependency on django-ipware. Adding explicit dependency make
the behavior safer.
- Depend on django-axes >= 5 where the authentication backend and other features
are available. The new code won't work with older versions. The new approach
uses and authentication backend to deny access to the login form on lockout and
a middleware to redirect user to locked out form when limit of attempts have
been reached.
- Drop old code used for compatibility with django-axes 3.x.
- Suppress verbose and debug messages as django-axes is too chatty.
- Re-implment the CAPTCHA form entirely. In the old style, we have a login form
with CAPTCHA field. That would not work with the new django-axes authentication
middle. On submission of the form, auth.authenticate() will be called. This
call invokes various authentication backends include django-axes authentication
backend. This backend's behavior is to reject all authentication attempts when
the IP is listed in locked table. The new approach is to provide a simple
CAPTCHA form with just the CAPTCHA field. If the form is successfully
validated (correct CAPTCHA is provided), then the lock on the IP address is
reset. The user is then free to perform 3 more attempts to login.
- Update firstboot form to send the request parameter when using
auth.authenticate() method. This needed by Django axes' authentication method
which will be triggered.
Tests:
- Run tests on Debian Bookworm and Debian testing.
- Axes verbose messages and debug messages are not printed on the console when
running FreedomBox in debug mode.
- Only three invalid attempts are allowed at the login page. After the final
incorrect attempt, user is redirected to CAPTCHA page. Visiting the login page
using the URL works but entering the correct credentials still takes the user to
CAPTCHA page.
- CAPTCHA form appears as expected. Clicking the CAPTCHA images downloads the
audio file corresponding to the image. Incorrect CAPTCHA shows an error. Correct
CAPTCHA takes the user to login form where they are able to login with correct
credentials. Entering incorrect credentials 3 times will take the user again to
CAPTCHA page.
- Creating user account during firstboot works.
- Blocked IP address the IP of the client such as 10.42.0.1 and not the local IP
address 127.0.0.1 according the django-axes log messages. While one client IP
address is blocked, another IP is able to login to the same user account that
was attempted by the blocked client.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
Using autofocus too much hurts accessibility[1] as screen readers jump to the
autofocused field. Specifically, it should used only when it increases UX
significantly, when the form is the only thing on the page and there is nothing
to read before the field is filled.
- Networks: There is not much improvement to UX by focusing on a radio select.
- Update User Form: there is a statement to be read before the first element is
filled up. Username is changed rarely but it being focused on.
- First boot user account: There is content to be read before filling the form
and this will be skipped by the screen reader.
Links:
1) https://www.boia.org/blog/accessibility-tips-be-cautious-when-using-autofocus
Tests:
- networks: Add new connection form works. The connection type is not
autofocused.
- users: Update user form works. Username is not autofocused.
- users: First boot form works. Username is not autofocused.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
Closes: #2276.
Functionality all over the system keeps failing due this approach. The latest is
changing hostname in ejabberd Mnesia database fails (#2276). Further, users
connecting FreedomBox to a monitor can't use a GUI.
Tests:
- Without patches, enable restricted access. Apply patches and setup.py install.
Security app is updated. Restricted access is disabled and
/etc/security/access.d/{50freedombox.conf, 10freedombox-security.conf,
10freedombox-performance.conf} are removed. It is possible to login into
non-admin account via SSH.
- On a fresh install, the configuration files are not found.
- Security page does not show 'restrict console logins' option.
- Updating security app setting works. Message 'Configuration updated.' is
shown.
- First boot succeeds. Restrict console login is not enabled.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
Tests:
- Functional tests work (failing already)
- DONE: Showing front page shortcuts according to user groups works
- DONE: Only user who is party of syncthing group is shown syncthing
- DONE: Admin users are always shown all the apps
- DONE: Syncthing:
- Not tested: When upgrading from version 2 or below, renaming group works
- DONE: Syncthing is added to freedombox-share group
- DONE: Initial setup of users app works
- DONE: freedombox-share group is created
- DONE: Retriving last admin user works
- DONE: Last admin is not allowed to delete account
- DONE: Creating a new user works
- DONE: Password is set properly (user can login with 'su - user' after)
- DONE: Incorrect confirmation password leads to error
- DONE: Adding the user to groups works (edit page shows correct list of groups)
- DONE: Editing a user works
- DONE: User is renamed properly
- DONE: Removing user from groups works
- DONE: Adding user to new groups works
- DONE: Providing incorrect auth password results in error message
- DONE: Enabling/disabling account work (confirm with 'su - user'). See #2277.
- DONE: Updating user password works
- DONE: New password is set (confirm with 'su - user')
- DONE: Providing incorrect auth password results in error message
- DONE: Initial user account creation works
- DONE: User account can be used (confirm with 'su - user')
- DONE: User is added to admin group
- DONE: Exception while getting SSH keys results in showing empty field
- DONE: Removing a user works
- DONE: Command provided in a message in users_firstboot.html works for
deleting users.
- DONE: If an admin users exists when running first wizard, list of admin users
is shown.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
Closes: #2081.
Tests:
- In the create user form, edit user form and change password form, the message
is shown as expected.
- The create user form, edit user form and change password form work as expected.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This patch only ensures that response object is send along with set_language()
call. In later changes, response object can be used by set_language() to set the
language cookie.
Tests:
- Relevant functional tests pass.
- Edit current user's language. The language is immediately set.
- Edit another user's language. The language of the current session is not changed.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- Before Django 3.1, iterating the .choices for a field would yield (id, label)
tuples directly suitable for use with ChoiceFields. From Django 3.1, id is an
instance of ModelChoiceIteratorValue which helps to easily find the model
instance. In most cases, using the proxy works, but in our case, the value is
being hashed. Access the actual value of the field from the object to avoid this
issue.
- Cleanup widget for disabling individual checkboxes in a group
- When a form is submitted, 'disabled' input field is omitted by the browser
irrespective of its value. So, the last admin user, automatically add the
'admin' group to form values.
Tests:
- On Django 2.2 and Django 3.2 access the user edit page. The form should render
as before the change without errors.
- Test with the current user as the last admin user. The 'admin' checkbox should
be read-only.
- Test with the current user not as the last admin user. The 'admin' checkbox
should not be read-only.
- Add/remove non-admin groups and save the current/different user.
- Access the user edit page as non-admin user, the groups should be disabled.
- Give/take admin permission to/from a user other than current user.
- Take admin permission from current user.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- ugettext functions will be removed in Django 4.0. Each use emits a warning
when running with Django 3.2. Since we have warnings enabled in developer mode,
we see quite a few messages because of this.
- ugettext is already a simple alias of gettext. So, no regressions are
expected.
Tests:
- Accessing an affected app in UI with Django 3.2 and Django 2.2 works fine.
- Using Django 3.2 there are no warnings related to removal of ugettext
functions.
- Ran regular unit tests.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This is the first functional test which tests the permissions of a
non-administrator user in a group.
Some changes had to be made in the form shown in users module for this
to work. The id of each checkbox in the "Permissions" section is now
predictable based on the name of the group. For example, the id of the
checkbox for the group "vpn" is `id_group_vpn`. Changes are also made in
`CheckboxSelectMultipleReadOnly` form class for consistency, though it
is not being used by this functional test.
Some utility functions for functional tests have been moved out of users
module to be usable by other app modules for testing group permissions.
One additional utility function to skip creating user if it already
exists has been added. Not using this function wouldn't break the test
but using it saves some time.
Changed password format string to use `S` instead of `w` to support
special characters in password.
Signed-off-by: Joseph Nuthalapati <njoseph@riseup.net>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This change prevents the plinth user to become a superuser without
knowing an admin password.
Users module and action script:
- User credentials are now required for the subcommands: create-user,
set-user-password, add-user-to-group (if the group is admin),
remove-user-from-group (if the group is admin), set-user-status,
remove-user (if the removed user is the last admin user.
Note: the web UI doesn't allow to delete last admin user).
- subcommand remove-users requires authentication if the user is last
admin user. Password must be provided through standard input.
- subcommand remove-group: do not allow to remove group 'admin'
- User credentials must be provided using the argument
--auth-user and a passsword must be provided through standard input.
- If there are no users in the admin group, no admin password is
required and if the --auth-user argument is required, it can be an
empty string.
Users web UI:
- An admin needs to enter current password to create and edit a user
and to change user's password.
- Show more detailed error text on exceptions when submitting forms.
- Show page title on the edit and create user pages.
Users unit and functional tests:
- Added a configuration parameters to the pytest configuration file
to set current admin user/password.
- Added a configuration parameter 'ssh_port' to the functional tests.
You can overwrite this with the FREEDOMBOX_SSH_PORT environment
variable. Modified HACKING.md accordingly.
- Added an unit test:
- test changing the password as a non-admin user.
- test invalid admin password input.
- test that removing the admin group fails.
- Capture stdout and stderr in the unit tests when calling an action
script to be able to see more info on exceptions.
- Added functional tests for setting ssh keys and changing passwords
for admin and non-admin users.
- Added a functional test for setting a user as active/inactive.
Changes during review [sunil]:
- Move uncommon functional step definitions to users module from global. This is
keep the common functional step definitions to minimal level and promote when
needed.
- Minor styling changes, flake8 fixes.
- Don't require pampy module when running non-admin tests. This allows tests to
be run from outside the container on the host machine without python3-pam
installed.
- Call the confirm password field 'Authorization Password'. This avoid confusion
with a very common field 'Confirm Password' which essentially means retype
your password to ensure you didn't get it wrong. Add label explaining why the
field exists.
- Don't hard-code /tmp path in test_actions.py. Use tmp_path_factory fixture
provided by pytest.
- Remove unused _get_password_hash() from actions/users.
- Undo splitting ldapgid output before parsing. It does not seem correct and
could introduce problems when field values contain spaces.
Tests performed:
- No failed unit tests (run with and without sudo).
- All 'users' functional tests pass.
- Creating an admin user during the first boot wizard succeeds.
- Creating a user using the web UI with an empty or wrong admin
password fails and with the correct admin password succeeds.
- Editing a user using the web UI with an empty or wrong admin
password fails and with the correct admin password succeeds.
- Changing user's password using the web UI with an empty or wrong
admin password fails and with the correct admin password succeeds.
- Above mentioned user action script commands can't be run without
correct credentials.
- Adding the daemon user to the freedombox-share group succeeds when
installing certain apps (deluge, mldonkey, syncthing, transmission).
Signed-off-by: Veiko Aasa <veiko17@disroot.org>
[sunil: Move uncommon functional step definitions to users module from global]
[sunil: Minor styling changes, flake8 fixes]
[sunil: Don't require pampy module when running non-admin tests]
[sunil: Call the confirm password field 'Authorization Password']
[sunil: Don't hard-code /tmp path in test_actions.py]
[sunil: Remove unused _get_password_hash() from actions/users]
[sunil: Undo splitting ldapgid output before parsing]
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
Helps: #1938.
backups/forms.py:
- ChoiceField labeled to allow translation.
- Translation applied to hard coded literals.
config/forms.py:
Lazy translation applied to literals that were translated but still
displayed in english to non-english users.
diagnostics_results.html:
Apply translation to results. Use gettext_noop to mark for translation.
dynamicdns/forms.py:
Apply translation to choice literals.
i2p/views.py:
Lazy translation applied to literals that were translated but still
displayed in english to non-english users.
names.html:
Apply translation to table headers.
performance/__init__.py:
Apply translation to description literals.
radicale/forms.py:
ChoiceField labeled to allow translation.
users/forms.py:
CharField labeled to allow translation.
QA:
- Literals visually verified.
- No errors in py.test-3.
- Yapf applied (only) to changed files.
- No remarks by flake8 to changed file.
Signed-off-by: Fioddor Superconcentrado <fioddor@gmail.com>
[sunil: Separate out the translations]
[sunil: Fix i18n for diagnostics]
[sunil: dynamicdns: Also do i18n for string GnuDIP]
[sunil: searx: Revert an incorrect removal of import]
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
- Handle groups needed by an app.
- Handle reserved usernames for an app.
- Updated documentation
- Updated unit tests
Tests performed:
- Reserved usernames: ez-ipupd, ejabberd, Debian-minetest, mldonkey,
monkeysphere, mumble-server, privoxy, quasselcore, radicale, debian-tor,
debian-transmission
- Reserved usernames checks should work in the following forms:
- Create user
- Update user
- First boot user creation
- Full list of available groups should appear in following cases:
- Create user form
- Update user form
- Full list of groups should get created in Django DB during:
- Update user form display
- First boot form save
- When updating the last admin user, the 'admin' group choice is checked
and disabled.
- Following groups show up (sorted by group name):
- bit-torrent: Download files using BitTorrent applications
- git-access: Read-write access to Git repositories
- i2p: Manage I2P application
- wiki: View and edit wiki applications
- minidlna: Media streaming server
- ed2k: Download files using eDonkey applications
- freedombox-share: Access to the private shares
- web-search: Search the web
- syncthing: Administer Syncthing application
- feed-reader: Read and subscribe to news feeds
- admin: Access to all services and system settings
- Directory validation form checks for write permissions for following apps:
- deluge with debian-deluged user
- transmission with debian-transmission user
- Sharing app should show all the groups in add/edit share forms
- The following apps should get added to share group during setup:
debian-transmission
debian-deluged
- Unit tests pass
- Functional tests for users and groups pass
- Test that an app (example syncthing) provides the necessary
permissions to users in that group (but not in admin group).
Signed-off-by: Joseph Nuthalapati <njoseph@riseup.net>
[sunil: Fix i18n of group descriptions]
[sunil: Update developer documentation]
[sunil: Separate out cosmetic changes]
[sunil: Fix component ID for mumble]
[sunil: sharing: Remove unneeded dependency on users app]
[sunil: Implement better API for getting groups in component]
[sunil: Fix incorrect regression change ttrss app]
[sunil: Make iterating over gourps more readable]
[sunil: Improve tests, drop single use fixtures]
[sunil: Simplify test_view.py fixture]
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Tested-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
Set autocapitalization='none' and autocomplete='username' on the username field.
Latest Django version uses those attributes by default on the username field.
Closes#1207
Signed-off-by: Veiko Aasa <veiko17@disroot.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- Username should match [a-zA-Z0-9_.@-], can't start with '-'
- Use Python pwd module to retrieve all users instead of getent command.
- Checking, that a username already exists or is reservered, is case insensitive
Created usernames are now compatible with openldap and nslcd. Didn't change
urlpatterns in case of an invalid username is already created by the admin.
Closes#1773
Signed-off-by: Veiko Aasa <veiko17@disroot.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- new share types - group and home shares
- users: when creating, deleting or changing user password, update also Samba
tdbsam backend database
- users: new managed packages - samba-common-bin, tdb-tools
- module page: show current samba users who are in freedombox-share group
- module page: show users who should re-enter their password in the password change page
- fix: use os.path.ismount() from Python standard library to validate a mount point
- fix: samba share permissions, fixes#1729
- fix: delete a share - do not raise an exception if the share doesn't exist
- storage: show samba share type in the directory selection form
Closes#1727
Signed-off-by: Veiko Aasa <veiko17@disroot.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- Added validation logic in the backend to compensate
Signed-off-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- Don't allow disabling the only available admin account.
- Don't allow deletion of the only available admin account.
- Don't allow removing admin privileges of the only available admin account.
Signed-off-by: Hemanth Kumar Veeranki <hems.india1997@gmail.com>
Reviewed-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
- It may not be a good thing for the user created/edit forms to inherit from
Django Form and ModelForm at the same time. So, simply by introducing a
minimal mixin.
- Save only when committing.
- Use auto-saving feature.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
Separate language cookie are only used if sessions (session middleware) are not
available. Otherwise, even anonymous users have their language preference in
sessions instead of cookies. This is default Django behavior, conform to it.
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- UserProfile model is created, it has one-to-one relationship with User.
- Language selection dropdown added to UserCreate and UserUpdate forms.
- Adds None to language selection dropdown to explicitly unselect.
- LANGUAGE_SESSION_KEY is set to User's preferred language on LogIn activity.
- LANGUAGE_SESSION_KEY is deleted on User's LogOut activity.
Signed-off-by: Sai Kiran Naragam <saikiran.rguiiit@gmail.com>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
- Remove conditional registration of groups on module initialization.
- Create uninitialized groups on addition/update of groups for user.
- Remove group creation on setup/installation of a module.
Tested for:
- Multi registration of groups.
- Manual UI test to check visibility of groups irrespective of whether module is
installed/enabled.
Signed-off-by: Aakanksha Saini <aakanksa@thoughtworks.com>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
- Edit user form fails because a 'wiki' group entry exists in the database
though the ikiwiki app hasn't been installed yet.
- Register group when a user group is created by an application, so that a
plinth restart can be avoided.
Signed-off-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- More user-friendly treatment of groups and their permissions
Closes#690
Signed-off-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
- Also wrote unit tests in users/tests/test_actions
Signed-off-by: Joseph Nuthalpati <njoseph@thoughtworks.com>
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit contains an implementation only for module repro
- Loop through all the loaded modules
- Get each module reserved_username attribute
- Check the username against the reserved_username
- Only admins can now edit the groups of any user
- Only admins can mark any user as active or not
- Refactored all occurrences of admin checks to its own utility function