diff options
Diffstat (limited to 'djangorestframework/authentication.py')
| -rw-r--r-- | djangorestframework/authentication.py | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/djangorestframework/authentication.py b/djangorestframework/authentication.py new file mode 100644 index 00000000..894b34fc --- /dev/null +++ b/djangorestframework/authentication.py @@ -0,0 +1,84 @@ +"""The :mod:`authentication` modules provides for pluggable authentication behaviour. + +Authentication behaviour is provided by adding the mixin class :class:`AuthenticatorMixin` to a :class:`.Resource` or Django :class:`View` class. + +The set of authentication which are use is then specified by setting the :attr:`authentication` attribute on the class, and listing a set of authentication classes. +""" +from django.contrib.auth import authenticate +from django.middleware.csrf import CsrfViewMiddleware +from djangorestframework.utils import as_tuple +import base64 + + +class BaseAuthenticator(object): + """All authentication should extend BaseAuthenticator.""" + + def __init__(self, view): + """Initialise the authentication with the mixin instance as state, + in case the authentication needs to access any metadata on the mixin object.""" + self.view = view + + def authenticate(self, request): + """Authenticate the request and return the authentication context or None. + + An authentication context might be something as simple as a User object, or it might + be some more complicated token, for example authentication tokens which are signed + against a particular set of permissions for a given user, over a given timeframe. + + The default permission checking on Resource will use the allowed_methods attribute + for permissions if the authentication context is not None, and use anon_allowed_methods otherwise. + + The authentication context is available to the method calls eg Resource.get(request) + by accessing self.auth in order to allow them to apply any more fine grained permission + checking at the point the response is being generated. + + This function must be overridden to be implemented.""" + return None + + +class BasicAuthenticator(BaseAuthenticator): + """Use HTTP Basic authentication""" + def authenticate(self, request): + from django.utils.encoding import smart_unicode, DjangoUnicodeDecodeError + + 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: + uname, passwd = smart_unicode(auth_parts[0]), smart_unicode(auth_parts[2]) + except DjangoUnicodeDecodeError: + return None + + user = authenticate(username=uname, password=passwd) + if user is not None and user.is_active: + return user + return None + + +class UserLoggedInAuthenticator(BaseAuthenticator): + """Use Django's built-in request session for authentication.""" + def authenticate(self, request): + if getattr(request, 'user', None) and request.user.is_active: + # If this is a POST request we enforce CSRF validation. + if request.method.upper() == 'POST': + # Temporarily replace request.POST with .RAW_CONTENT, + # so that we use our more generic request parsing + request._post = self.view.RAW_CONTENT + resp = CsrfViewMiddleware().process_view(request, None, (), {}) + del(request._post) + if resp is not None: # csrf failed + return None + return request.user + return None + + +#class DigestAuthentication(BaseAuthentication): +# pass +# +#class OAuthAuthentication(BaseAuthentication): +# pass |
