Heirarchies of permissions in Django - inheriting from models and from other permissions - python

Django allows you to give users and groups of users custom permissions on objects (and django-guardian adds some nice ways of using this). There are various ways of putting users into hierarchies. What I'd like to do is add two types of hierarchies to the permissions themselves. For example if someone has a given permission on a Book object, I want them to implicitly have that permission on each Page object. Also, if someone has an change permission on a Page, I want them to implicitly have the view permission on that Page.
In sum, I want page.has_permission('view', user) to check both page.has_permission('*edit*', user) and page *.book* .has_permission('view', user), and for book.has_permission('view', user) to itself check book.has_permission('*edit*', user). (Asterisks just for emphasis.)
I don't need anything as complex as django-rules, and I prefer the generic foreign key approach as I will not have large numbers and it keeps the model structure clean and focused. I'd like to avoid repeating the logic for these permission relationships in views, or cluttering models, and I'd ideally keep this permission structure centralized somewhere, ideally declaratively. For example
perm_hierarchy = {'view': ['edit', 'delete', ]}
model_perm_hierarchy = { Page : [Chapter, ],
Chapter : [Book, ]}
Then a layer that when checking for 'view' on Page checks for 'edit' and 'delete' permissions on that Page object.
And similarly when checking Page for a permission, checks Chapter for the same permission (if that same named permission is defined for Chapter).
Very happy to be told I'm thinking about this wrong.

I document a solution using django-rules on top of django-guardian in this answer

Related

Django user permissions on variable data

Ran into a problem that has me scratching my head, documentation hasn't really pulled me any luck so I figured I'd see if anyone else has been in this situation. So let's say I have a model (among others):
Organization
That sort of acts like a psuedo-tenant. The thing is, users within my app may or may not have permissions to multiple organizations, some only 1, some this, some that. Point is, there's no clear structure on where permissions lay for each user. By default it should be none as it is now until manually granting, but instead of granting permissions to all or no organizations has anyone ran into a similar situation of being in need to control permissions in a granular/dynamic fashion? It is important to note that these 'organizations' are loaded dynamically via an API to an external product.
I realize this can be done by crafting my own sort of permissions system outside of Django but my main question is can this be done with conventional Django permissions or is this out of scope?
Thanks
You need object-level permission
As already mentioned, you could use something to help you with the object permissions, like django-guardian. However, if it is for one model and it is something simple, consider also defining a custom permission in your organisation model:
class Organisation(models.Model):
# your fields
class Meta:
permissions = (('my_shiny_permission', 'Some description for it'),)
And then in your views you can define the logic for it:
def my_view(request):
if request.user.has_perm('my_app.my_shiny_permission'):
# do something
More about custom permissions - here.

Django group permission activate

If you have django.contrib.auth in your INSTALLED_APPS django will automatically create add, change, delete and view permissions to every model in your system (or any one you add later). These are stored in auth_permission.
In django doc, here is what we can read under Groups section:
django.contrib.auth.models.Group models are a generic way of categorizing users so you can apply permissions, or some other label, to those users. A user can belong to any number of groups.
A user in a group automatically has the permissions granted to that group. For example, if the group 'Site editors' has the permission can_edit_home_page, any user in that group will have that permission.
I've a group with no permission at all (call it NADA) and I've assign that group to a specific user (let's call him Pierre). Pierre can still connect and create, update, delete or view anything on my web interface.
How can I make it working? There's few or no doc on the web for native Django Permission.
I've read this nice publication
django-permission-apps-comparison.
I know I could install django-guardian, django-role-permissions or
django-rules...
I know we can manage access via middleware or decorator But since django IS creating these tables for us (user, groups, permissions and group_permissions)
I thought it was extremely simple to implement CRUD access to any model class!
Wrong?
Do I miss something?
Note: Working with Python3.6 and Django 2.1.3
Django permissions are simple. As far as I understand your question, you are trying to create a user with no permission and he should not see any entries on the Django admin.
First thing is to make sure the user is not marked as "superuser", the superuser sees everything no matter which group they are added in.
If he is not a superuser and is still able to see the model then you should make sure he is not part of multiple groups. If a user is in multiple groups then a union of all permissions is what is applied to them. This link will give you more details on different flags for a user https://djangobook.com/users-groups-permissions/. Let me know if this helps.

Getting rid of Django's default_permissions by default

In the Django project I work on, the built in ('add', 'change', 'delete') permissions are next to useless for us, and only confuse our users in forms; we don't use the Django admin, it often doesn't make much sense for us to have three permissions instead of one edit permission, and our models are more granular than the objects we want to assign permissions to (as a made-up example, it doesn't make sense to have seperate permissions for an Invoice and an InvoiceLine - they're conceptually the same thing).
Anyway, at the moment I'm accomplishing this by subclassing each model from a custom abstract base model which has default_permissions = () in it's Meta, plus some ugly hacks to make the permissions from third-party models go away. Is there any way I can make Django not create those three permissions by default?
If you don't use the admin then just don't bother about the default permissions. They are not enforced by default anywhere else. Feel free to create your own Permission and check that the user has this in your edit views, with permission_required for function views and PermissionRequiredMixin for class based view (and Django>1.9).

django permission to other owners

Imagine these models:
User has many Buckets and each Bucket has many Items. User A only sees his own list of buckets and items in it. Now, I want to give user B permission to see user's A buckets but not items. Is this possible with Django built-in permission system or I need something like django-guardian for this purpose?
I am new to django and I am a little confused.
Django has two different levels of permissions when it comes to models: model-level and object-level.
Model-level permissions are the default type in Django, and they are enforced by the default permissions backend. They work on an "all or nothing" basis, so a user can either have a permission (such as removing) for all objects of a model, or they don't.
If you are running into a situation where "User A needs to be able to remove any comment" or "User B needs to be able to edit any blog post", you are probably looking for model-level permissions.
Object-level permissions are supported in Django, but they require you to use a third-party permission backend. They work in a similar way to model-level permissions, but instead of being "all or nothing" on all model objects, it is only for a single object. There are many packages out there for object-level permissions, and the one you choose depends on what you need out of the permission backend.
If you are running into a situation where "User A needs to be able to remove only objects where they are the creator" or "User B needs to be able to remove a subset of objects", you are probably looking for object-level permissions.
You appear to be interested in object-level permissions.

Django - permissions and profiles

I have a couple of different profiles. I want to associate permissions with these profiles. I've done so like this:
class StudentProfile(UserProfile):
school = models.CharField(max_length=30)
class Meta:
permissions = (
("is_student","Can access student pages"),
)
however, when I try and check if that permission exists using has_perm on that profile object, I get an error "'StudentProfile' object has no attribute 'has_perm'" am I not supposed to check for permissions in this way? I've read the docs and that's what I thought I was supposed to do
Edit: After reading the docs again, it seems that has_perm is a method belonging to Users and NOT their profiles. However, when I try to show the permissions:
print user.get_all_permissions()
I get an empty set. Shouldn't I see something like "appname.is_student"
.has_perm is a method on the User object, not on a UserProfile object. If you are trying to validate that a user has the permission has_student, you'd need to do something like this:
user.has_perm('profiles.is_student')
assuming that your StudentProfile model is in a profiles application.
EDIT: To address your rephrased question, you should assign permissions the normal way, either to the group or to a particular user, and use User.has_perm. Your latter example goes completely against the point of the Django permission system.

Categories