diff options
Diffstat (limited to 'rest_framework/authentication.py')
| -rw-r--r-- | rest_framework/authentication.py | 125 |
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 |
