Manage user rights in Django

Tram Ho

Managing users in the Django admin is a difficult topic. If you monitor too many rights, you may interfere with your daily activities. If you allow granting permissions freely without supervision, your system is at risk. Django provides a good authentication framework, tightly integrated with Django admin. However, Django admin does not enforce special restrictions on user administrators. This can lead to dangerous situations that can damage your system. Do you know the staff users who manage other users in the admin page can edit their own permissions? Did you know they can also turn themselves into superuser? Nothing in Django’s admin system prevents that, so it’s up to you! By the end of this article, you will know how to protect your system from the following risks:

  • Protect against escalation by preventing users from editing their own permissions
  • Keep permissions neat and manageable by putting users in groups
  • Prevent leakage rights through custom actions by explicitly defining the required permissions

Decentralization on Model (Model Permissions)

Decentralization is quite difficult. If you do not set permissions, then you put your system at risk of being compromised, data leakage and human error. If you abuse the rights or use them too much, you may accidentally interfere with the normal operation of the system. Django comes with an integrated authentication system (built-in authentication system). This system includes users, groups and permissions. When a model is created, Django will automatically create 4 default permissions for the following:

  1. add: user with this permission can create an object of the model.
  2. delete: This user can delete an object of the model.
  3. change: The user with this permission can change the information of an object of the model.
  4. views: This user can view detailed information of an object of the model. The name of the permisson is set according to the very specific rule as follows:

Inside:

  • <app> is the name of the app. For example, the User model is imported from the app ‘auth’ (django.contrib.auth)
  • <action> is one of the above operations (add, delete, change, view)
  • <modelname> is the name of the model, lowercase Knowing the naming rules can help you manage your rights more easily. For example, the right to change a user is set as follows: auth.change_user

How to check permissons?

The permissions on the model are assigned to users or groups. To check if a user has specific rights, you can do the following:

It is noted that the has_perm () method will always return True for the superuser, regardless of whether the permisson exists or not.

As you can see, when you check for superuser permissions, those permissions are not actually checked.

How to monitor rights

The model in Django does not really monitor permissions. By default, the only place that monitors permissions is Django Admin. The reason the model does not allow to monitor permissions is that normally, the model does not know the user that performed the action. In Django applications, the user is usually taken from the request. This is why, most of the time, permissions are monitored in the view class. For example, to prevent users who do not have view permissions on the ‘user’ model from accessing the view displaying user information, do the following:

If the user makes a login request and is authenticated, request.user will store the information of an User object. If the user is not logged in, request.user will be an object of AnonymousUser. This is a special object used by Django to refer to unauthenticated users. If the user making the request does not have view_user permission, then an exception is given to the PermissionDenied and the 403 response is returned to the client. To make checking permissions in the view easier, Django provides a decorator shortcut called permisson_required, which does the same thing:

For the template, you can access the current user’s rights through a special template variable called ‘perms’. For example, if you only want to show the delete button to a user who has the right to delete, do the following:

Some popular third-party applications like the Django rest framework also provide useful integration with Django model rights.

Django Admin and Model Permissions:

Django Admin has a very tight integration with the authentication system available, specifically the rights on the model.

  • If the user does not have permission on a model, they cannot see it or access it in the admin page.
  • If the user has permission to view and change on a model, then they will be able to view and update the model’s objects, but they cannot add new objects or delete existing objects. With the appropriate permissions in place, users who are admin are less likely to make mistakes and intruders will have a harder time doing harm.

Deploying custom business role in Django Admin

One of the most vulnerable places in every application is the authentication system. In Django applications, this is the User model. So, to better protect your application, you will start with the User model. First, you need to control the admin page for the User model. Django comes with a nice admin page for user management. To take advantage of that, you will expand the existing ‘admin’ model.

Set up a custom Admin Page

To provide a custom admin page for the User model, you need to unregister the existing admin model provided by Django and register your own admin user:

Your CustomUserAdmin is inheriting Django UserAdmin. Thanks to that you can take advantage of all the functions created by the Django developers. At this point, if you log in to your Admin page at http://127.0.0.1:8000/admin/auth/user , you will see that the admin page for the user remains unchanged:

By inheriting UserAdmin, you can use all of Django Admin’s integrated features.

Prevent arbitrary updates of fields:

Unattended forms of management are a major cause of terrible mistakes. A staff user can easily update an object’s information through the admin page in ways that the application does not expect. Most of the time, users are unaware of what is going on. Such mistakes are often difficult to track and correct. To prevent these errors from occurring, you can prevent users of the admin page from modifying certain fields in the model. If you want to prevent any user, including superuser, from updating a field, you can mark the field as read-only. For example, the date_joined field is set when a user registers a new account. This information should never be changed by any user, so you mark it as read-only:

Once a field is added to readonly_fields, it cannot be edited in the administrator’s default form. When a field is marked as read-only, Django will display its input field as ‘disabled’. But, what if you want to prevent only some users from updating a field?

Prevent conditional field updates:

Sometimes, it is useful to update fields directly in the admin page. But you don’t want to allow any user to do that: you want to allow only superuser to do that. Suppose you want to prevent non-superuser users from changing usernames. To do so, you need to modify the input form created by Django and disable the username field based on the current user:

Inside:

  • To edit a form, override the get_form () method. This function is used by Django to generate the default update form for the model.
  • To conditionally disable the field, first fetch the default form created by Django and then if the user is not a superuser, turn off the username field. Now, when a non-superuser tries to edit a user, the username field will be disabled. Attempts to modify the username through Django Admin will fail. When a superuser wants to edit a user, the username field is turned on again and working as expected.

Prevent non-superuser users from granting superuser privileges:

Superuser is a very powerful permission that should not be granted arbitrarily. However, any user who has the right to change on the model user can turn any user into a superuser, including themselves. This goes against the entire purpose of the licensing system, so you must close this vulnerability. Based on the previous example, to prevent non-superuser people from turning themselves into superuser, you need to add the following restrictions:

Inside:

  • You have initialized a blank set of disabled_fields to save the fields that will be disabled.
  • Next, if the user is not a superuser, add two fields to the collection (username from previous example and is_superuser). This will prevent non-superuser people from turning themselves into superuser.
  • Finally, you browse the set elements, mark them all as disabled, then return the form.

Override Permission

Sometimes it can be helpful to completely override the rights in a Django administrator. A common situation is when you use permissions elsewhere and you don’t want staff users to make changes when using the admin page. Django uses hooks for four default permissions. Internally, hooks use the rights of the current user to make decisions. You can override these hooks and make different decisions. To prevent staff users from deleting an object, regardless of their rights, you can do the following:

As with get_form (), obj is the object you are manipulating: When obj is None, the user only asks for a list of objects. When obj is not None, the user has requested to update a specific object.

Deny access to corrective actions

Corrective actions need to be carefully licensed. Django by default cannot restrict access to these actions. An edit action will be accessible to any admin page user with any permission on the model. To illustrate, add a handy management action that marks multiple users as ‘active’:

Using this action, a staff user can mark one or more users and activate them all at once. This is useful in some cases, such as if you encounter an error during the signup process and need to activate multiple users. This action updates the user information, so you only want users with change rights to perform it. Django Admins uses an internal function to get the action. To hide active_users () from users without permission to change, override get_actions ():

get_actions () returns an OrderedDict. Where key is the name of the action and value is the function of the action. To adjust the return value, you override the function, fetch the initial value, and then, depending on the user’s rights, can delete the active_users action. For staff users who do not have change_user () permission, active_users will not appear in the action list.

Conclude

Django admin is a great tool to manage a Django project. Many teams rely on it to maintain efficiency in managing daily activities. If you use the Django admin to perform operations on models, then it is important to know the permissions. The techniques described in this article are useful for any admin model, not just the User model. Now your system is much safer at the beginning.

Share the news now

Source : Viblo