Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django AdminSite/ModelAdmin for end users?

Tags:

Not all software has the need for an admin interface for "content producers" on the left and a site for "visitors/members" on the right.

It is often said that "the Admin is not your app" (See for example the accepted answer (March 2009)).

I couldn't find such a limitation mentioned explicity in the Django documentation. There seems to be an underlying assumption of the above - "a powerful and production-ready interface that content producers can immediately use to start adding content to the site" - but different levels of access are certainly anticipated, even mentioned in the FAQ. And what other use case for multiple AdminSite instances anyway?

I'm currently working on a software which is mainly a CRUD interface. Every user must be authenticated, and the only difference between admin users and customers is that the latter can only work with "their" objects (and no access to certain models like "User" etc.). By the way "their" in my case not related to who created the object, but rather which "Company" its associated with.

Is there any compelling reason not to just stick with the admin interface, and just configure the right cocktail of permissions? Can the ModelAdmin permissions be trusted? Why not just call all logged in users "staff"?

For traditional non-admin views I'm seeing myself re-writing what seems to already be there: A ModelForm is a nice start but CRUD functionality and type-dependent filters (incl. date drill-down) are not readily available components. The functionality of the Admin already provides the vast majority of the features that end users need, and customization of fields/filters/templates etc. is sufficient for my needs. Obviously where I add a new feature, e.g. visibility of its button and access to the corresponding views needs a permission check. I'm not worried about that. I'm just curious whether in a case like this the Admin functionality is properly covered by its built-in set of permissions. Any experiences with that?

UPDATE: Sorry the main part of this question seems unclear. I'm not worried about my customizations, I'm worried about trusting the existing admin app and its implementation of permissions. See also comments to Daniel and FallenAngel.

like image 894
Danny W. Adair Avatar asked Apr 03 '11 19:04

Danny W. Adair


2 Answers

There is nothing inherently special about admin. It behaves just like any other view. So if it is using permissions to determine access (for example, if you set a user's .is_staff to True but give them access only to specific permissions) then it will be equally secure to any view you might create that uses permissions to determine access.

In the same vein, the customization you provide to a ModelAdmin is going to result in an implementation that is equally secure as anything you might write.

If you write a custom has_change_permission for your your model, for example:

def has_change_permission(self, request, obj=None):     return obj.company == request.user.get_profile().company 

This is going to work. It's not going to merely hide a button; it's going to completely block this object from being edited.

The people who wrote django.contrib.admin did not write it with the assumption that anyone with an is_staff = True could be trusted as much as a superuser, or was stupid enough to never take a look at the source code of a web page. Although writing your own views is encouraged, it is still a robust interface.

See, for example, this section of the source code which raises a PermissionDenied exception if you try to access the change_view without permission to edit the actual object:

def change_view(self, request, object_id, extra_context=None):     "The 'change' admin view for this model."     model = self.model     opts = model._meta      obj = self.get_object(request, unquote(object_id))      if not self.has_change_permission(request, obj):         raise PermissionDenied      # view continues... 

So even if someone were to craft the correct URL to edit a given object, so long as you had correctly implemented has_change_permission the user will be denied access.

like image 90
Jordan Reiter Avatar answered Nov 06 '22 09:11

Jordan Reiter


We have a system that just runs as you asked.

Program have a basic user login, which is tha basic site and uses hand written views and templates (as it needed to be)... There eexists a Customer part, which is the basic admin page with limited access rights. And there is admin whom are me and people like me.

Logic is, admins are people working in the company, who may have all access permissions (superusers as sjango said) or limited access to the applications but can see all related DB records from those they have access. Customers are people who we sell our program, they have limited access to the admin and can only see records related to them. users are customers of our costumers...

In that point, django permissions are not sufficient, because our customer must see record belong to his account, while a standard admin can see all records. These two can reach applications according to their permissions. Superuser can see and do anything...

For the solution, instead of usnig django site application (which i never used and do not have much information) we created a model that extends Django user, which have a field like role is user role is System administrator, then he can see everything (if superuser, otherwise he uses permissions as normal)... If not, he can reach records relatred to their website (Company in your situation).

So, nearly each database table must have a foreignkey defining owner company of the related record.

By that, you can filter records belong to a specific company if required...

In my models, i have Kullanici that inherits User model

class Kullanici(User):     rol = SmallIntegerField()# 1 if system admin, 2 if cusotmer etc... 

Then, i write a few methods to that overrides admin methods, like ;ModelAdmin.save and modelAdmin.queryset that do the following check...

#override admin queryset method def override_queryset(obj, req):     qs = super(type(obj), obj).queryset(req)     kullanici = Kullanici.objects.get(id=req.user.id)     if kullanici.rol == 10:         return qs     return qs.filter(site=kullanici.site) 

So, when a user go to list view of an application, he only sees sites related to him, other records will not be shown, or he will get permisson error if he tries to go to a record belong to some other site. These are all django bassed controls, so you can be sure they will not reach ant record that they must not.

You must override all Admin methods that require filtering belong to customer.

For further limitation i used a function to show/hide fields of the model. In the admin .py file:

class SomeModelAdmin(ModelAdmin):     exclude= []     def changelist_view(self, request, extra_context=None):         extra_context = {'exclude':['field1','field2']}         return get_admin_listview(self, request, extra_context)   def get_admin_listview(obj, req, extra): system_admin = Kullanici.objects.get(id=req.user.id).rol == 1 if not system_admin:     if 'exclude' in extra.keys():         for key in extra['exclude']:             if key not in obj.exclude:                 obj.exclude.add(key) 

you give a list of field names to be hidden, and it will hide them if user is not system admin...

Handycaps are, django admin caching may cause, which happened to me once or twice in 8 months. Other important part is, you can not limit admin filters, so if you have a filter that requred limited access, you can not filter the filter keys. You can either display it with all options or simply do not use it.

If this approach solves your problem, i may write a more detailed information...

UPDATE: Yes, permission system is simple and secure, if you check the source code of permission_required decorator from the latest trunk code...

Logic is simple, the user has relevant permisson, related view is ececuted. Otherwise related view or code is not executed at all. So, permissons provides enough security for django admin. Permission control can be be used both on view level and/or template level.

One point that must be carefull is hand written views, where insecure code might cause serious problems, but this is all about your coding, and this is the kind of security risk that you will face with on every framework and programming language...

Last point of issue is the filtering mechanism of django and admin view pages. Since Nearly all admin filters uses GET to filter data, and passes id's to urls for displaying a specific record. Seciruty part of django book shows basic information about possible security issues and how django handles them... On the other hand, 22 December 2010 security update shows a such important vulnerability, which requires enough information about model structure.

like image 40
FallenAngel Avatar answered Nov 06 '22 08:11

FallenAngel