diff options
| author | Tom Christie | 2013-02-11 12:47:56 +0000 | 
|---|---|---|
| committer | Tom Christie | 2013-02-12 08:58:28 +0000 | 
| commit | 09b01887f234be55c14943028330f569823b2369 (patch) | |
| tree | 6457258308dbc63a24c7a4f16b544999adc6c2b3 /rest_framework | |
| parent | aa03425c09c2eb4fc0a24276de92a320af09c33e (diff) | |
| download | django-rest-framework-09b01887f234be55c14943028330f569823b2369.tar.bz2 | |
New style object-level permission checks
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/generics.py | 2 | ||||
| -rw-r--r-- | rest_framework/permissions.py | 27 | ||||
| -rw-r--r-- | rest_framework/renderers.py | 2 | ||||
| -rw-r--r-- | rest_framework/tests/permissions.py | 4 | ||||
| -rw-r--r-- | rest_framework/tests/renderers.py | 2 | ||||
| -rw-r--r-- | rest_framework/views.py | 18 | 
6 files changed, 41 insertions, 14 deletions
diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 5abb915b..19dca7e6 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -131,7 +131,7 @@ class SingleObjectAPIView(SingleObjectMixin, GenericAPIView):          Override default to add support for object-level permissions.          """          obj = super(SingleObjectAPIView, self).get_object(queryset) -        if not self.has_permission(self.request, obj): +        if not self.has_object_permission(self.request, obj):              self.permission_denied(self.request)          return obj diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index c9bbf4c4..306f00ca 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -2,6 +2,8 @@  Provides a set of pluggable permission policies.  """  from __future__ import unicode_literals +import inspect +import warnings  SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'] @@ -11,11 +13,22 @@ class BasePermission(object):      A base class from which all permission classes should inherit.      """ -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          """          Return `True` if permission is granted, `False` otherwise.          """ -        raise NotImplementedError(".has_permission() must be overridden.") +        return True + +    def has_object_permission(self, request, view, obj): +        """ +        Return `True` if permission is granted, `False` otherwise. +        """ +        if len(inspect.getargspec(self.has_permission)[0]) == 4: +            warnings.warn('The `obj` argument in `has_permission` is due to be deprecated. ' +                      'Use `has_object_permission()` instead for object permissions.', +                       PendingDeprecationWarning, stacklevel=2) +            return self.has_permission(request, view, obj) +        return True  class AllowAny(BasePermission): @@ -25,7 +38,7 @@ class AllowAny(BasePermission):      permission_classes list, but it's useful because it makes the intention      more explicit.      """ -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          return True @@ -34,7 +47,7 @@ class IsAuthenticated(BasePermission):      Allows access only to authenticated users.      """ -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          if request.user and request.user.is_authenticated():              return True          return False @@ -45,7 +58,7 @@ class IsAdminUser(BasePermission):      Allows access only to admin users.      """ -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          if request.user and request.user.is_staff:              return True          return False @@ -56,7 +69,7 @@ class IsAuthenticatedOrReadOnly(BasePermission):      The request is authenticated as a user, or is a read-only request.      """ -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          if (request.method in SAFE_METHODS or              request.user and              request.user.is_authenticated()): @@ -100,7 +113,7 @@ class DjangoModelPermissions(BasePermission):          }          return [perm % kwargs for perm in self.perms_map[method]] -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          model_cls = getattr(view, 'model', None)          if not model_cls:              return True diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 960d4849..e7df8758 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -301,7 +301,7 @@ class BrowsableAPIRenderer(BaseRenderer):          request = clone_request(request, method)          try: -            if not view.has_permission(request, obj): +            if not view.has_permission(request):                  return  # Don't have permission          except Exception:              return  # Don't have permission and exception explicitly raise diff --git a/rest_framework/tests/permissions.py b/rest_framework/tests/permissions.py index 26a34319..b8e1d89c 100644 --- a/rest_framework/tests/permissions.py +++ b/rest_framework/tests/permissions.py @@ -115,9 +115,7 @@ class OwnerModel(models.Model):  class IsOwnerPermission(permissions.BasePermission): -    def has_permission(self, request, view, obj=None): -        if not obj: -            return True +    def has_object_permission(self, request, view, obj):          return request.user == obj.owner diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index 72405336..e3f45ce6 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -95,7 +95,7 @@ urlpatterns = patterns('',  class POSTDeniedPermission(permissions.BasePermission): -    def has_permission(self, request, view, obj=None): +    def has_permission(self, request, view):          return request.method != 'POST' diff --git a/rest_framework/views.py b/rest_framework/views.py index fd6b4313..dd8889ae 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -13,6 +13,7 @@ from rest_framework.response import Response  from rest_framework.request import Request  from rest_framework.settings import api_settings  import re +import warnings  def _remove_trailing_string(content, trailing): @@ -261,8 +262,23 @@ class APIView(View):          """          Return `True` if the request should be permitted.          """ +        if obj is not None: +            warnings.warn('The `obj` argument in `has_permission` is due to be deprecated. ' +                      'Use `has_object_permission()` instead for object permissions.', +                       PendingDeprecationWarning, stacklevel=2) +            return self.has_object_permission(request, obj) + +        for permission in self.get_permissions(): +            if not permission.has_permission(request, self): +                return False +        return True + +    def has_object_permission(self, request, obj): +        """ +        Return `True` if the request should be permitted for a given object. +        """          for permission in self.get_permissions(): -            if not permission.has_permission(request, self, obj): +            if not permission.has_object_permission(request, self, obj):                  return False          return True  | 
