aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
authorPierre Dulac2013-03-01 02:08:58 +0100
committerPierre Dulac2013-03-01 02:08:58 +0100
commitda9d7fb8ec19f289d9d2777738a45007c41a1289 (patch)
tree5086af70af8dd827aa9cf9a2a1933688bd45b58e /rest_framework
parent592a0a5980e4baf18102769997de8011be72cd6b (diff)
downloaddjango-rest-framework-da9d7fb8ec19f289d9d2777738a45007c41a1289.tar.bz2
Add the OAuth2Authentication class
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/authentication.py85
-rw-r--r--rest_framework/compat.py11
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