Opinions on permissions stategy

55 views
Skip to first unread message

Avraham Serour

unread,
Dec 11, 2016, 12:35:09 AM12/11/16
to django-users
Hi,

I'm using DRF and need to implement object based permissions, I sublassed BasePermission to create my own logic.

Currently all models that make sense to have permission inherits from a base Object model, implementing common behaviour and fields.

The object has two many to many fields to UserProfile, read_access and write_access.

So checking if a User has permission to an object is simple as:

base_query = models.Q(pk=user_profile.id)  # base query is for current user
        for group in user_profile.get_groups():
            base_query |= models.Q(pk=group.id)  # make an OR query for each group the user belongs
return obj.read_access.filter(base_query).exists()

So checking if a user has permission to a given object can be done cheap in one query

But the objects in the system have an hierarchy, a Project has tasks which may have substaks.

So should I check the parent object permissions? or just checking the current object is enough?

I'm thinking of copying the parent permissions when an object is created, in this way creating an object could be expensive and the permissions table may get too big, but reading the permissions can be cheap.

Thoughts? Ideas?

Thanks
Avraham

Vinicius Assef

unread,
Dec 12, 2016, 8:35:04 PM12/12/16
to django...@googlegroups.com
Considerations follow inline...

On 11 December 2016 at 03:34, Avraham Serour <tov...@gmail.com> wrote:
> ...
>
> So should I check the parent object permissions? or just checking the
> current object is enough?

It depends on the granularity level of your permissions.

Could a child object have a different permission from its parent? If
yes, you only need to check the object itself. If it doesn't override
the parent permission, you should check the parent's permission,
additionally.

Or must it always obey the parent permissions? If that's the case, you
only need to check the parent permission.

>
> I'm thinking of copying the parent permissions when an object is created, in
> this way creating an object could be expensive and the permissions table may
> get too big, but reading the permissions can be cheap.

Or children objects can simply point to the parent to check its permission.

You could have a column called `parent_id` in each object. If it is
the higher level, it will point to nobody (or to itself. It will
depend on your logic). So, each child will point to the parent.
Permissions must be checked using `parent_id` for relationship.

But, again, it will depend on the granularity of your permissions and
how much you want to allow or forbid a child override a parent
permission.

--
Vinicius Assef

Avraham Serour

unread,
Dec 13, 2016, 1:25:04 AM12/13/16
to django-users
Hi,

Thanks for taking your time on this.

Could a child object have a different permission from its parent?
Yes, I'm thinking someone may have access to the parent but not to all childs, or read access to the project and write access to some tasks (probably the ones I'm responsible)
So each object has

>  If it doesn't override the parent permission, you should check the parent's permission, additionally.

Well, I see two problems here.
1 - Currently the system stores only who has access, a lack of it means the user has no permission.
Not so big of a problem, I can change this, so it is a minor problem.

2 - I don't know the depth level, a task for example may have subtasks, which are task objects itself, which may each have subtasks and so on
I would need to check each in a loop, can't do it in one query.

I'm now thinking that I could use a mptt for this or maybe this would be too complicated?
Using mptt I could have hierarchical permissions and check for permissions on an object and each parent if permissions are not defined, but I would need to change the way permissions are stored right now to also store negative permissions

Avraham



--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAFmXjSDOybmJ0EfBA1ECv9Mf6MFAtaEx6%2BrP8XB4x%3D%2BHsOK21Q%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Vinicius Assef

unread,
Dec 13, 2016, 8:06:18 AM12/13/16
to django...@googlegroups.com
Yes, mptt can save your day.

When handling hierarchies it's important to establish clear priorities.

An example: given the following hierarchy: Project (1st "floor") -> Module (2nd "floor") -> Task (3rd "floor"), if not directly assigned, a task should consider module's permission? Or the project's permission should always rule that situation?

The object's "floor" is important.

--
Vinicius


For more options, visit https://groups.google.com/d/optout.


--
Sent from Gmail Mobile

Avraham Serour

unread,
Dec 15, 2016, 12:44:51 AM12/15/16
to django-users
Hi,

I've given a lot of thought on this, I have also searched for django apps that deal with permissions, I didn't find something that implements hierarchical object level permissions, I have a feeling that I am overcomplicating things if none did this...

Well, first of all I thought of creating a through table for the Object and user relation, so permission should have a value (how should I name this? level?)
The idea is that a value of 1 means the user can read and 2 that the user can write, so to check if a user can read I can compare value>=1
In this way I can also pave the way if I want to implement revoke permission, which could be value=0

Actually the module would be the root level, so Module->project->project->project->task->task->task

So a user with permissions to a project has also permissions for its subprojects and tasks.

What do you mean floor?

mptt seems a very nice solution but...

To check an object permission I would need to get the first ascendent with permissions registered, with django-mptt I can get all ascendents, this could be a problem if the object is too deep.
I then would need to loop through the ascendents and check if there are permissions registered for the current user, this would make yet another query, the permissions are on another table

Also, I'm not sure how I would list the objects the user can read for example, opening an project page should list only the tasks and subprojects the user can read.
Of course if I ca loop all tasks to get the ones the user can read, but this would be prohibitive slow, how can I do this with django mptt in one query?

On the other hand the idea of copying the parent permission when an object is created have cheap reads, not so expensive writes but I'm afraid would make a too big permissions table (number of users X number of lines for most tables)

Thanks for the considerations
Avraham


Vinicius Assef

unread,
Dec 15, 2016, 9:41:52 AM12/15/16
to django...@googlegroups.com
On 15 December 2016 at 03:43, Avraham Serour <tov...@gmail.com> wrote:
> Hi,
>
> I've given a lot of thought on this, I have also searched for django apps
> that deal with permissions, I didn't find something that implements
> hierarchical object level permissions, I have a feeling that I am
> overcomplicating things if none did this...
>
> Well, first of all I thought of creating a through table for the Object and
> user relation, so permission should have a value (how should I name this?
> level?)

Or "type" (1=read, 2=write, 0=no permission).

It's up to you. ;-)


>
> Actually the module would be the root level, so
> Module->project->project->project->task->task->task
>
> So a user with permissions to a project has also permissions for its
> subprojects and tasks.

This is exactly what I meant by "clear rules". This is one of them. :-)

>
> What do you mean floor?

Using your example above: Module (1st floor)->project (2nd
floor)->project (3rd floor)->project (4th floor)->task (5th
floor)->task (6th floor)->task (7th floor)

"Floor" would be "the level in hierarchy one given object belongs to".

Anyone with write level on the 1st floor, will have the same access on
2nd, 3rd, 4th, 5th, 6th and 7th as well. Otherwise you allow it to be
overriden.

Anyone with write level on the 5th floor, will have the same access on
6th and 7h.

Did you get it?


>
> mptt seems a very nice solution but...
>
> To check an object permission I would need to get the first ascendent with
> permissions registered, with django-mptt I can get all ascendents, this
> could be a problem if the object is too deep.

It'll depend how deep an object can be and the number of children an
object could have.


> I then would need to loop through the ascendents and check if there are
> permissions registered for the current user, this would make yet another
> query, the permissions are on another table

Maybe let the DB solve this through join?

>
> Also, I'm not sure how I would list the objects the user can read for
> example, opening an project page should list only the tasks and subprojects
> the user can read.
> Of course if I ca loop all tasks to get the ones the user can read, but this
> would be prohibitive slow, how can I do this with django mptt in one query?

I don't know django-mptt but maybe you should start reading from your
permissions table and, based on permissions, get which objects the
user could see.

I should know more about your requirements. It's complicated to
explain it here. If you want call me at http://telegram.me/viniciusban

Talking in pt_BR is better in this case for me.

>
> On the other hand the idea of copying the parent permission when an object
> is created have cheap reads, not so expensive writes but I'm afraid would
> make a too big permissions table (number of users X number of lines for most
> tables)

Maybe that's the price to pay for.

But I think it won't be too expensive in terms of performance.

>
> Thanks for the considerations
> Avraham

You're welcome.

--
Vinicius
Reply all
Reply to author
Forward
0 new messages