diff options
| author | Pierre Dulac | 2013-03-01 02:08:58 +0100 | 
|---|---|---|
| committer | Pierre Dulac | 2013-03-01 02:08:58 +0100 | 
| commit | da9d7fb8ec19f289d9d2777738a45007c41a1289 (patch) | |
| tree | 5086af70af8dd827aa9cf9a2a1933688bd45b58e | |
| parent | 592a0a5980e4baf18102769997de8011be72cd6b (diff) | |
| download | django-rest-framework-da9d7fb8ec19f289d9d2777738a45007c41a1289.tar.bz2 | |
Add the OAuth2Authentication class
| -rw-r--r-- | rest_framework/authentication.py | 85 | ||||
| -rw-r--r-- | rest_framework/compat.py | 11 | 
2 files changed, 95 insertions, 1 deletions
| diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index 14b2136b..c20d9cb5 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -6,6 +6,7 @@ from django.contrib.auth import authenticate  from django.utils.encoding import DjangoUnicodeDecodeError  from rest_framework import exceptions, HTTP_HEADER_ENCODING  from rest_framework.compat import CsrfViewMiddleware +from rest_framework.compat import oauth2_provider, oauth2  from rest_framework.authtoken.models import Token  import base64 @@ -155,4 +156,86 @@ class TokenAuthentication(BaseAuthentication):          return 'Token' -# TODO: OAuthAuthentication +class OAuth2Authentication(BaseAuthentication): +    """ +    OAuth 2 authentication backend using `django-oauth2-provider` +    """ +    require_active = True + +    def __init__(self, **kwargs): +        super(OAuth2Authentication, self).__init__(**kwargs) +        if oauth2_provider is None: +            raise ImproperlyConfigured("The 'django-oauth2-provider' package could not be imported. It is required for use with the 'OAuth2Authentication' class.") + +    def authenticate(self, request): +        """ +        The Bearer type is the only finalized type + +        Read the spec for more details +        http://tools.ietf.org/html/rfc6749#section-7.1 +        """ +        auth = request.META.get('HTTP_AUTHORIZATION', '').split() +        print auth +        if not auth or auth[0].lower() != "bearer": +            return None + +        if len(auth) != 2: +            raise exceptions.AuthenticationFailed('Invalid token header') + +        return self.authenticate_credentials(request, auth[1]) + +    def authenticate_credentials(self, request, access_token): +        """ +        :returns: two-tuple of (user, auth) if authentication succeeds, or None otherwise. +        """ + +        # authenticate the client +        oauth2_client_form = oauth2.forms.ClientAuthForm(request.REQUEST) +        if not oauth2_client_form.is_valid(): +            raise exceptions.AuthenticationFailed("Client could not be validated") +        client = oauth2_client_form.cleaned_data.get('client') + +        # retrieve the `oauth2.models.OAuth2AccessToken` instance from the access_token +        auth_backend = oauth2.backends.AccessTokenBackend() +        token = auth_backend.authenticate(access_token, client) +        if token is None: +            raise exceptions.AuthenticationFailed("Invalid token")  # does not exist or is expired + +        # TODO check scope +        # try: +        #     self.validate_token(request, consumer, token) +        # except oauth2.Error, e: +        #     print "got e" +        #     raise exceptions.AuthenticationFailed(e.message) + +        if not self.check_active(token.user): +            raise exceptions.AuthenticationFailed('User not active: %s' % token.user.username) + +        if client and token: +            request.user = token.user +            return (request.user, None) + +        raise exceptions.AuthenticationFailed( +            'You are not allowed to access this resource.') + +        return None + +    def authenticate_header(self, request): +        """ +        Bearer is the only finalized type currently  + +        Check details on the `OAuth2Authentication.authenticate` method +        """ +        return 'Bearer' + +    def check_active(self, user): +        """ +        Ensures the user has an active account. + +        Optimized for the ``django.contrib.auth.models.User`` case. +        """ +        if not self.require_active: +            # Ignore & move on. +            return True + +        return user.is_active diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 07fdddce..5bba0c86 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -426,3 +426,14 @@ try:      import defusedxml.ElementTree as etree  except ImportError:      etree = None + + +# OAuth 2 support is optional +try: +    import provider as oauth2_provider +except ImportError: +    oauth2_provider = None +try: +    import provider.oauth2 as oauth2 +except ImportError: +    oauth2 = None | 
