#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------
     Reporter:  James Pic     |                    Owner:  nobody
         Type:  New feature   |                   Status:  new
    Component:  contrib.auth  |                  Version:  3.0
     Severity:  Normal        |               Resolution:
     Keywords:                |             Triage Stage:  Unreviewed
    Has patch:  0             |      Needs documentation:  0
  Needs tests:  0             |  Patch needs improvement:  0
Easy pickings:  0             |                    UI/UX:  0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

> Permissions on objects are based on two mechanisms that developers have
> to implement:
>
> - returning if a user has a permission on an object instance
> - filtering a queryset based on a user object and eventually a permission
> name
>
> Currently, permission backend allows developers to implement the first
> mechanism: you can allow a specific permission on an object with the
> permission backend.
>
> This works extremely well even for complex use cases: you get an model
> object, a user, a permission name and you can return True.
>
> Exemple:
>
> {{{
>     def has_perm(self, user_obj, perm, obj=None):
>         if not user_obj.is_authenticated or not isinstance(obj,
> SomeModel):
>             return False
>
>         return user_obj.is_superuser or obj.related_model_fk in
> user_obj.related_model_m2m.all()
> }}}
>
> However, permission framework should also allow developers to implement
> the second security mechanism: getting a filtered queryset with objects a
> user should be able to see, eventually for a given permission. Such
> implementation could look like:
>

> {{{
>     def filter_queryset(self, user_obj, perm, queryset=None):
>         if not queryset.model == SomeModel:
>             return queryset
>
>         if not user_obj.is_authenticated:
>             return queryset.none()
>
>         return
> queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())
> }}}
>
> The admin views could use this, and django.contrib.auth could provide
> generic views extensions which do check permissions, removing the need to
> share a mixin that just does return a Mixin with a get_queryset method to
> complement the code that they have in the permission backend. It would
> reduce chances to make a mistake when updating permission code if it's
> all at the same place, an opinion that I consider suited for a framework
> like Django.
>
> I consider that the subject of making ModelChoiceFields to be able to
> benefit from this is out of the scope of this ticket, but I could bring
> it up for discussion if this feature is implemented.

New description:

 Permissions on objects are based on two mechanisms that developers have to
 implement:

 - returning if a user has a permission on an object instance
 - filtering a queryset based on a user object and eventually a permission
 name

 Currently, permission backend allows developers to implement the first
 mechanism: you can allow a specific permission on an object with the
 permission backend.

 This works extremely well even for complex use cases: you get an model
 object, a user, a permission name and you can return True.

 Exemple:

 {{{
     def has_perm(self, user_obj, perm, obj=None):
         if not user_obj.is_authenticated or not isinstance(obj,
 SomeModel):
             return False

         return user_obj.is_superuser or obj.related_model_fk in
 user_obj.related_model_m2m.all()
 }}}

 However, permission framework should also allow developers to implement
 the second security mechanism: getting a filtered queryset with objects a
 user should be able to see, eventually for a given permission. Such
 implementation could look like:


 {{{
     def filter_queryset(self, user_obj, perm, queryset=None):
         if not queryset.model == SomeModel:
             return queryset

         if not user_obj.is_authenticated:
             return queryset.none()

         return
 queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())
 }}}

 The admin views could use this, and django.contrib.auth could provide
 generic views extensions which do check permissions, removing the need to
 share a mixin that just does return a Mixin with a get_queryset method to
 complement the code that they have in the permission backend. It would
 reduce chances to make a mistake when updating permission code if it's all
 at the same place, an opinion that I consider suited for a framework like
 Django.

 I consider that the subject of making ModelChoiceFields to be able to
 benefit from this is out of the scope of this ticket, but I could bring it
 up for discussion if this feature is implemented (ie. DRF serializers have
 a "context" variables where the request object is set by default, which
 allows to do user-based validation: a pretty standard requirement).

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:6>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/062.648ea42f07a2e9a53f71dbc898a5e470%40djangoproject.com.

Reply via email to