aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/permissions.py
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework/permissions.py')
-rw-r--r--rest_framework/permissions.py69
1 files changed, 57 insertions, 12 deletions
diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py
index 655b78a3..ae895f39 100644
--- a/rest_framework/permissions.py
+++ b/rest_framework/permissions.py
@@ -1,21 +1,36 @@
"""
Provides a set of pluggable permission policies.
"""
-
+from __future__ import unicode_literals
+import inspect
+import warnings
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
+from rest_framework.compat import oauth2_provider_scope, oauth2_constants
+
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.
+ """
+ return True
+
+ def has_object_permission(self, request, view, obj):
"""
Return `True` if permission is granted, `False` otherwise.
"""
- raise NotImplementedError(".has_permission() must be overridden.")
+ 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 +40,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 +49,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 +60,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 +71,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()):
@@ -89,6 +104,8 @@ class DjangoModelPermissions(BasePermission):
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
}
+ authenticated_users_only = True
+
def get_required_permissions(self, method, model_cls):
"""
Given a model and an HTTP method, return the list of permission
@@ -100,15 +117,43 @@ 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
+ queryset = getattr(view, 'queryset', None)
+
+ if model_cls is None and queryset is not None:
+ model_cls = queryset.model
+
+ assert model_cls, ('Cannot apply DjangoModelPermissions on a view that'
+ ' does not have `.model` or `.queryset` property.')
perms = self.get_required_permissions(request.method, model_cls)
if (request.user and
- request.user.is_authenticated() and
- request.user.has_perms(perms, obj)):
+ (request.user.is_authenticated() or not self.authenticated_users_only) and
+ request.user.has_perms(perms)):
return True
return False
+
+
+class TokenHasReadWriteScope(BasePermission):
+ """
+ The request is authenticated as a user and the token used has the right scope
+ """
+
+ def has_permission(self, request, view):
+ token = request.auth
+ read_only = request.method in SAFE_METHODS
+
+ if not token:
+ return False
+
+ if hasattr(token, 'resource'): # OAuth 1
+ return read_only or not request.auth.resource.is_readonly
+ elif hasattr(token, 'scope'): # OAuth 2
+ required = oauth2_constants.READ if read_only else oauth2_constants.WRITE
+ return oauth2_provider_scope.check(required, request.auth.scope)
+
+ assert False, ('TokenHasReadWriteScope requires either the'
+ '`OAuthAuthentication` or `OAuth2Authentication` authentication '
+ 'class to be used.')