aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/authentication.py
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework/authentication.py')
-rw-r--r--rest_framework/authentication.py125
1 files changed, 125 insertions, 0 deletions
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
new file mode 100644
index 00000000..30c78ebc
--- /dev/null
+++ b/rest_framework/authentication.py
@@ -0,0 +1,125 @@
+"""
+Provides a set of pluggable authentication policies.
+"""
+
+from django.contrib.auth import authenticate
+from django.utils.encoding import smart_unicode, DjangoUnicodeDecodeError
+from rest_framework import exceptions
+from rest_framework.compat import CsrfViewMiddleware
+from rest_framework.authtoken.models import Token
+import base64
+
+
+class BaseAuthentication(object):
+ """
+ All authentication classes should extend BaseAuthentication.
+ """
+
+ def authenticate(self, request):
+ """
+ Authenticate the request and return a two-tuple of (user, token).
+ """
+ raise NotImplementedError(".authenticate() must be overridden.")
+
+
+class BasicAuthentication(BaseAuthentication):
+ """
+ HTTP Basic authentication against username/password.
+ """
+
+ def authenticate(self, request):
+ """
+ Returns a `User` if a correct username and password have been supplied
+ using HTTP Basic authentication. Otherwise returns `None`.
+ """
+ if 'HTTP_AUTHORIZATION' in request.META:
+ auth = request.META['HTTP_AUTHORIZATION'].split()
+ if len(auth) == 2 and auth[0].lower() == "basic":
+ try:
+ auth_parts = base64.b64decode(auth[1]).partition(':')
+ except TypeError:
+ return None
+
+ try:
+ userid = smart_unicode(auth_parts[0])
+ password = smart_unicode(auth_parts[2])
+ except DjangoUnicodeDecodeError:
+ return None
+
+ return self.authenticate_credentials(userid, password)
+
+ def authenticate_credentials(self, userid, password):
+ """
+ Authenticate the userid and password against username and password.
+ """
+ user = authenticate(username=userid, password=password)
+ if user is not None and user.is_active:
+ return (user, None)
+
+
+class SessionAuthentication(BaseAuthentication):
+ """
+ Use Django's session framework for authentication.
+ """
+
+ def authenticate(self, request):
+ """
+ Returns a `User` if the request session currently has a logged in user.
+ Otherwise returns `None`.
+ """
+
+ # Get the underlying HttpRequest object
+ http_request = request._request
+ user = getattr(http_request, 'user', None)
+
+ # Unauthenticated, CSRF validation not required
+ if not user or not user.is_active:
+ return
+
+ # Enforce CSRF validation for session based authentication.
+ class CSRFCheck(CsrfViewMiddleware):
+ def _reject(self, request, reason):
+ # Return the failure reason instead of an HttpResponse
+ return reason
+
+ reason = CSRFCheck().process_view(http_request, None, (), {})
+ if reason:
+ # CSRF failed, bail with explicit error message
+ raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
+
+ # CSRF passed with authenticated user
+ return (user, None)
+
+
+class TokenAuthentication(BaseAuthentication):
+ """
+ Simple token based authentication.
+
+ Clients should authenticate by passing the token key in the "Authorization"
+ HTTP header, prepended with the string "Token ". For example:
+
+ Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a
+ """
+
+ model = Token
+ """
+ A custom token model may be used, but must have the following properties.
+
+ * key -- The string identifying the token
+ * user -- The user to which the token belongs
+ """
+
+ def authenticate(self, request):
+ auth = request.META.get('HTTP_AUTHORIZATION', '').split()
+
+ if len(auth) == 2 and auth[0].lower() == "token":
+ key = auth[1]
+ try:
+ token = self.model.objects.get(key=key)
+ except self.model.DoesNotExist:
+ return None
+
+ if token.user.is_active:
+ return (token.user, token)
+
+# TODO: OAuthAuthentication