aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework
diff options
context:
space:
mode:
authorTom Christie2011-04-27 18:08:32 +0100
committerTom Christie2011-04-27 18:08:32 +0100
commit659898ffaf24f74b62e73c487cd81bad21904790 (patch)
tree4b3370ea540b4adeaaba950325abca273ae5843e /djangorestframework
parent028851bfa1ee44b8e92808b18d32278d4a473cc8 (diff)
downloaddjango-rest-framework-659898ffaf24f74b62e73c487cd81bad21904790.tar.bz2
Inital pass at generic permissions, throttling etc.
Diffstat (limited to 'djangorestframework')
-rw-r--r--djangorestframework/permissions.py74
-rw-r--r--djangorestframework/tests/throttling.py38
2 files changed, 112 insertions, 0 deletions
diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py
new file mode 100644
index 00000000..98d4b0be
--- /dev/null
+++ b/djangorestframework/permissions.py
@@ -0,0 +1,74 @@
+from django.core.cache import cache
+from djangorestframework import status
+import time
+
+
+class BasePermission(object):
+ """A base class from which all permission classes should inherit."""
+ def __init__(self, view):
+ self.view = view
+
+ def has_permission(self, auth):
+ return True
+
+class IsAuthenticated(BasePermission):
+ """"""
+ def has_permission(self, auth):
+ return auth is not None and auth.is_authenticated()
+
+#class IsUser(BasePermission):
+# """The request has authenticated as a user."""
+# def has_permission(self, auth):
+# pass
+#
+#class IsAdminUser():
+# """The request has authenticated as an admin user."""
+# def has_permission(self, auth):
+# pass
+#
+#class IsUserOrIsAnonReadOnly(BasePermission):
+# """The request has authenticated as a user, or is a read-only request."""
+# def has_permission(self, auth):
+# pass
+#
+#class OAuthTokenInScope(BasePermission):
+# def has_permission(self, auth):
+# pass
+#
+#class UserHasModelPermissions(BasePermission):
+# def has_permission(self, auth):
+# pass
+
+
+class Throttling(BasePermission):
+ """Rate throttling of requests on a per-user basis.
+
+ The rate is set by a 'throttle' attribute on the view class.
+ The attribute is a two tuple of the form (number of requests, duration in seconds).
+
+ The user's id will be used as a unique identifier if the user is authenticated.
+ For anonymous requests, the IP address of the client will be used.
+
+ Previous request information used for throttling is stored in the cache.
+ """
+ def has_permission(self, auth):
+ (num_requests, duration) = getattr(self.view, 'throttle', (0, 0))
+
+ if auth.is_authenticated():
+ ident = str(auth)
+ else:
+ ident = self.view.request.META.get('REMOTE_ADDR', None)
+
+ key = 'throttle_%s' % ident
+ history = cache.get(key, [])
+ now = time.time()
+
+ # Drop any requests from the history which have now passed the throttle duration
+ while history and history[0] < now - duration:
+ history.pop()
+
+ if len(history) >= num_requests:
+ raise ErrorResponse(status.HTTP_503_SERVICE_UNAVAILABLE, {'detail': 'request was throttled'})
+
+ history.insert(0, now)
+ cache.set(key, history, duration)
diff --git a/djangorestframework/tests/throttling.py b/djangorestframework/tests/throttling.py
new file mode 100644
index 00000000..46383271
--- /dev/null
+++ b/djangorestframework/tests/throttling.py
@@ -0,0 +1,38 @@
+from django.conf.urls.defaults import patterns
+from django.test import TestCase
+from django.utils import simplejson as json
+
+from djangorestframework.compat import RequestFactory
+from djangorestframework.resource import Resource
+from djangorestframework.permissions import Throttling
+
+
+class MockResource(Resource):
+ permissions = ( Throttling, )
+ throttle = (3, 1) # 3 requests per second
+
+ def get(self, request):
+ return 'foo'
+
+urlpatterns = patterns('',
+ (r'^$', MockResource.as_view()),
+)
+
+
+#class ThrottlingTests(TestCase):
+# """Basic authentication"""
+# urls = 'djangorestframework.tests.throttling'
+#
+# def test_requests_are_throttled(self):
+# """Ensure request rate is limited"""
+# for dummy in range(3):
+# response = self.client.get('/')
+# response = self.client.get('/')
+#
+# def test_request_throttling_is_per_user(self):
+# """Ensure request rate is only limited per user, not globally"""
+# pass
+#
+# def test_request_throttling_expires(self):
+# """Ensure request rate is limited for a limited duration only"""
+# pass