Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More

Introduction to user management

This page explains to developers and server administrators how to get started with Lino’s functionality for managing the users of a Lino site.

It assumes that you have read the end-user documentation about The users plugin.

See users : user management for detailed developer documentation.

Side note: Code snippets (lines starting with >>>) in this document get tested as part of our development workflow. The following initialization snippet tells you which demo project is being used in this document.

>>> from lino import startup
>>> startup('lino_book.projects.min1.settings')
>>> from lino.api.doctest import *
>>> from atelier.sheller import Sheller
>>> shell = Sheller("lino_book/projects/min1")

Creating a site manager

A site manager is any site user having “Administrator” as user type, which gives them permission to edit the list of site users.

On a default Lino site this permission is given only to the “Administrator” user type. More precisely this permission is given by the SiteAdmin user role, which is inherited by the “Administrator” user type, and an application can use a custom user_types_module to define other user types.

The most Linoish way to create a site manager and a set of demo users is to run pm prep. This will reset the database to a virgin state and then load the demo fixture, which will create the demo users Robin, Rolf, Romain, Rando, Rik, Ronaldo … depending on your site’s language distribution (lino.core.site.Site.languages).

Once you have a site manager, you can sign in via the web interface and work as described in The users plugin.

Managing users from the command line

Django has a django-admin command named createsuperuser but this is quite limited. Lino gives a more useful command passwd.

passwd

Update or optionally create password, name and type of a user. The default action displays and optionally edits the user. Specify -c to create a new user.

Usage: go to your project directory and say:

$ python manage.py passwd [options] USERNAME

Where USERNAME is the username of the user to process. Default value for USERNAME is your system username.

Options

-c, --create

Create the given user. Fail if that username exists already.

--batch

Run in batch mode, i.e. without asking any questions. Assume yes to all questions.

>>> shell("python manage.py show users.AllUsers")
... 
========== ===================== ============ ===========
 Username   User type             First name   Last name
---------- --------------------- ------------ -----------
 robin      900 (Administrator)   Robin        Rood
 rolf       900 (Administrator)   Rolf         Rompen
 romain     900 (Administrator)   Romain       Raffault
========== ===================== ============ ===========
>>> shell("python manage.py passwd -c test --batch")
Creating new user
User test has been saved.
>>> shell("python manage.py show users.AllUsers")
... 
========== ===================== ============ ===========
 Username   User type             First name   Last name
---------- --------------------- ------------ -----------
 robin      900 (Administrator)   Robin        Rood
 rolf       900 (Administrator)   Rolf         Rompen
 romain     900 (Administrator)   Romain       Raffault
 test
========== ===================== ============ ===========
>>> u = users.User.objects.get(username="test")
>>> u.has_usable_password()
False

Managing users programmatically

For more fancy situations you can write a Python script and run it with pm run. For example:

from lino.api.shell import users
obj = users.User(username="root")
obj.set_password("1234!")
obj.full_clean()
obj.save()

Passwords of new users

The password field of a newly created user is empty, and the account therefore cannot be used to sign in. When you created a new user manually using the web interface, you must click their ChangePassword action and set their password.

>>> u = users.User(username="test")
>>> u.full_clean()
>>> u.save()

Since we didn’t set a password, Django stores a “non usable” password, and the User.check_password() method returns False:

>>> u.password  
'!...'
>>> u.check_password('')
False
>>> u.has_usable_password()
False

When setting the password for a newly created user, leave the field Current password empty.

>>> ses = rt.login('robin')
>>> values = dict(current="", new1="2rgXx2EdJp", new2="2rgXx2EdJp")
>>> rv = ses.run(u.change_password, action_param_values=values)
>>> print(rv['message'])
New password has been set for test.
>>> u.delete()

Password validation

A Lino site defaults to use the four password validators that come included with Django:

>>> pprint(settings.AUTH_PASSWORD_VALIDATORS)
[{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
 {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
 {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
 {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}]

See also the Django docs about Password validation

Note that password validators are being run only in situations where a potentially naive end user is being asked to provide a password. They do not apply e.g. when a user is created programmatically or when the password is set at the command line using pm passwd.

That’s why the demo fixtures of the lino.modlib.users plugin can create users with such a terrible password as “1234”.

A server administrator can customize password validation by manually setting a custom AUTH_PASSWORD_VALIDATORS. To disable password validation alltogether, just add the following line at the end of your settings.py file:

AUTH_PASSWORD_VALIDATORS = []