diff options
Diffstat (limited to 'djangorestframework/authentication.py')
| -rw-r--r-- | djangorestframework/authentication.py | 106 | 
1 files changed, 106 insertions, 0 deletions
| diff --git a/djangorestframework/authentication.py b/djangorestframework/authentication.py new file mode 100644 index 00000000..7d6e2114 --- /dev/null +++ b/djangorestframework/authentication.py @@ -0,0 +1,106 @@ +""" +The :mod:`authentication` module provides a set of pluggable authentication classes. + +Authentication behavior is provided by mixing the :class:`mixins.AuthMixin` class into a :class:`View` class. + +The set of authentication methods which are used is then specified by setting the +:attr:`authentication` attribute on the :class:`View` class, and listing a set of :class:`authentication` classes. +""" + +from django.contrib.auth import authenticate +from django.middleware.csrf import CsrfViewMiddleware +from djangorestframework.utils import as_tuple +import base64 + +__all__ = ( +    'BaseAuthenticaton', +    'BasicAuthenticaton', +    'UserLoggedInAuthenticaton' +) + + +class BaseAuthenticaton(object): +    """ +    All authentication classes should extend BaseAuthentication. +    """ + +    def __init__(self, view): +        """ +        :class:`Authentication` classes are always passed the current view on creation. +        """ +        self.view = view + +    def authenticate(self, request): +        """ +        Authenticate the :obj:`request` and return a :obj:`User` or :const:`None`. [*]_ +        +        .. [*] The authentication context *will* typically be a :obj:`User`, +            but it need not be.  It can be any user-like object so long as the +            permissions classes (see the :mod:`permissions` module) on the view can +            handle the object and use it to determine if the request has the required +            permissions or not.  +         +            This can be an important distinction if you're implementing some token +            based authentication mechanism, where the authentication context +            may be more involved than simply mapping to a :obj:`User`. +        """ +        return None + + +class BasicAuthenticaton(BaseAuthenticaton): +    """ +    Use HTTP Basic authentication. +    """ + +    def authenticate(self, request): +        """ +        Returns a :obj:`User` if a correct username and password have been supplied +        using HTTP Basic authentication.  Otherwise returns :const:`None`.   +        """ +        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 UserLoggedInAuthenticaton(BaseAuthenticaton): +    """ +    Use Django's session framework for authentication. +    """ + +    def authenticate(self, request): +        """ +        Returns a :obj:`User` if the request session currently has a logged in user. +        Otherwise returns :const:`None`. +        """ +        # TODO: Switch this back to request.POST, and let FormParser/MultiPartParser deal with the consequences. +        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 .DATA, +                # so that we use our more generic request parsing +                request._post = self.view.DATA +                resp = CsrfViewMiddleware().process_view(request, None, (), {}) +                del(request._post) +                if resp is not None:  # csrf failed +                    return None +            return request.user +        return None + + +# TODO: TokenAuthentication, DigestAuthentication, OAuthAuthentication | 
