diff options
| author | Tom Christie | 2013-09-25 09:44:26 +0100 | 
|---|---|---|
| committer | Tom Christie | 2013-09-25 09:44:26 +0100 | 
| commit | 21cd6386593aea0b122abec1c5cc3bd5c544aa87 (patch) | |
| tree | b7d197c9c04f56448bee36c4789c93c66fb541a8 /rest_framework/permissions.py | |
| parent | 9a5b2eefa92dede844ab94d049093e91ac98af5b (diff) | |
| parent | e8c6cd5622f62fcf2d4cf2b28b504fe5ff5228f9 (diff) | |
| download | django-rest-framework-21cd6386593aea0b122abec1c5cc3bd5c544aa87.tar.bz2 | |
Merge master
Diffstat (limited to 'rest_framework/permissions.py')
| -rw-r--r-- | rest_framework/permissions.py | 60 | 
1 files changed, 60 insertions, 0 deletions
| diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 0c7b02ff..14bec42c 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -2,6 +2,7 @@  Provides a set of pluggable permission policies.  """  from __future__ import unicode_literals +from django.http import Http404  from rest_framework.compat import oauth2_provider_scope, oauth2_constants  SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'] @@ -141,6 +142,65 @@ class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions):      authenticated_users_only = False +class DjangoObjectPermissions(DjangoModelPermissions): +    """ +    The request is authenticated using Django's object-level permissions. +    It requires an object-permissions-enabled backend, such as Django Guardian. + +    It ensures that the user is authenticated, and has the appropriate +    `add`/`change`/`delete` permissions on the object using .has_perms. + +    This permission can only be applied against view classes that +    provide a `.model` or `.queryset` attribute. +    """ + +    perms_map = { +        'GET': [], +        'OPTIONS': [], +        'HEAD': [], +        'POST': ['%(app_label)s.add_%(model_name)s'], +        'PUT': ['%(app_label)s.change_%(model_name)s'], +        'PATCH': ['%(app_label)s.change_%(model_name)s'], +        'DELETE': ['%(app_label)s.delete_%(model_name)s'], +    } + +    def get_required_object_permissions(self, method, model_cls): +        kwargs = { +            'app_label': model_cls._meta.app_label, +            'model_name': model_cls._meta.module_name +        } +        return [perm % kwargs for perm in self.perms_map[method]] + +    def has_object_permission(self, request, view, obj): +        model_cls = getattr(view, 'model', None) +        queryset = getattr(view, 'queryset', None) + +        if model_cls is None and queryset is not None: +            model_cls = queryset.model + +        perms = self.get_required_object_permissions(request.method, model_cls) +        user = request.user + +        if not user.has_perms(perms, obj): +            # If the user does not have permissions we need to determine if +            # they have read permissions to see 403, or not, and simply see +            # a 404 reponse. + +            if request.method in ('GET', 'OPTIONS', 'HEAD'): +                # Read permissions already checked and failed, no need +                # to make another lookup. +                raise Http404 + +            read_perms = self.get_required_object_permissions('GET', model_cls) +            if not user.has_perms(read_perms, obj): +                raise Http404 + +            # Has read permissions. +            return False + +        return True + +  class TokenHasReadWriteScope(BasePermission):      """      The request is authenticated as a user and the token used has the right scope | 
