Django user entitlements on creation / privilege escalation

884 views Asked by At

I got the following issue: If I give a user staff-status and allow him to create users but not to create new groups and assign entitlements, he is still able to assign another user the 'admin'-entitlements - so he can easily add a user who has more entitlements than himself! Has anyone found a way to avoid that without providing a custom user-model / -view?

I'm thankful for any response.

1

There are 1 answers

2
mgibsonbr On BEST ANSWER

Django requires that users with permission Can add user have also the permission Can change user. Quoting the documentation:

Also note: if you want your own user account to be able to create users using the Django admin site, you'll need to give yourself permission to add users and change users (i.e., the "Add user" and "Change user" permissions). If your account has permission to add users but not to change them, you won't be able to add users. Why? Because if you have permission to add users, you have the power to create superusers, which can then, in turn, change other users. So Django requires add and change permissions as a slight security measure.

However, it might be possible to restrict the set of permissions available for a given user to assign by modifying the ModelAdmin (or its form). Here's an answer showing how to redefine the UserAdmin.

I believe your new ModelAdmin would have to: a) filter out users that have more permissions than you (so you can't remove permissions from them); b) modify the change user form so you can't set the superuser field and the permissions you're not allowed to assign are excluded from the list (or disable the whole list altogether - but I dunno that's what you really need, right? Creating an user with no permissions at all would be of little use IMO).

Update: Here's what I found so far. Should satisfy all goals above, except the permission filtering problem (it behaves like you asked in the question - deny assiging any permissions by users who are not entitled to). You can modify it to better suit your needs (for instance, replace .is_superuser by whatever logic you want to allow/deny changing permissions).

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User

class MyUserAdmin(UserAdmin):
    def queryset(self,request):
        qs = admin.ModelAdmin.queryset(self,request)
        if request.user.is_superuser:
            return qs
        # Only allow viewing/editing users who are not superusers
        return qs.filter(is_superuser=False)
    def get_readonly_fields(self, request, obj=None):
        # Deny editing groups, permissions and the superuser status
        return () if request.user.is_superuser else ('is_superuser', 'groups', 'user_permissions')

admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)