Managing superusers when using the Django admin as a backend for employees

Expiring a superuser in Django after a due date

Out-of-the-box Django comes with a superuser checkbox that can be set on each user in the admin. Superusers are somewhat equivalent to the root user in Linux: it gives all permissions no matter what group you are in.

Staff users and super users

Superuser is a powerful feature but if you have other staff users, e.g. employees of your company that also log into the admin, this can be a problem:

  1. Staff users can change their own user and set superuser for themselves or others, even if they are not supposed to.

  2. Users with superuser permissions can see every admin page and automatically have permissions to view, create, update and delete. Even if you've set certain group and user permissions, these will be overruled by superuser authority.

So from a security and usability perspective, the best thing to do is create dedicated groups for certain employees, with their own permissions. This will also ensure that they will only be bothered with the models that are relevant to them.

There will also be a group of developers and system admins who will be the actual superusers of the system. If appropriate all available permissions can be assigned to this group, you are in control what is off-limits. The superuser feature however will only be used for special elevated occasions, just like the root user.

Making the superuser expire

From experience, people who have superuser access will keep that access. But just like the Linux root user, you should reserve the use of this power for certain (destructive) operations. You don't want people deleting the contents of an entire model by accident. Therefore, it's best to have superuser permission that expires by itself after a while.

Below is a gist of a mixin to change the superuser checkbox into a datetime field. The next time the permission for superuser will be evaluated, the field will be checked set empty if the datetime has expired.

Apply the mixin like this:

class User(ExpiringSuperuserMixin, AbstractUser):
    ...

And don't forget to set AUTH_USER_MODEL = 'yourapp.User' in your settings.py

Special privilege for assigning superuser

At this point, any user that has the "Can change user" permission can also still elevate a user to superuser. To prevent this a can_assign_superuser permission is created that will be checked in UserAdmin.get_readonly_fields(). If the user does not have this permission it will just show the superuser field as read-only.

You probably also want to make the user's "Groups" and "User permission" fields also read-only this way so they cannot assign themselves to things they are not allowed to.

Go ahead and try the code: