aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/authentication.py
diff options
context:
space:
mode:
authorTom Christie2013-03-08 20:23:11 +0000
committerTom Christie2013-03-08 20:23:25 +0000
commit650d8e6a8ecd092e1bdd7269097044563f4ea449 (patch)
treed3f34ef99b0642f8af10103059b208668a4341d4 /rest_framework/authentication.py
parente42e49852d032a888a17a09be6732a4c6a8fee72 (diff)
downloaddjango-rest-framework-650d8e6a8ecd092e1bdd7269097044563f4ea449.tar.bz2
More bits of cleanup
Diffstat (limited to 'rest_framework/authentication.py')
-rw-r--r--rest_framework/authentication.py125
1 files changed, 66 insertions, 59 deletions
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
index 4d6e3375..3000de3a 100644
--- a/rest_framework/authentication.py
+++ b/rest_framework/authentication.py
@@ -12,6 +12,19 @@ from rest_framework.authtoken.models import Token
import base64
+def get_authorization_header(request):
+ """
+ Return request's 'Authorization:' header, as a bytestring.
+
+ Hide some test client ickyness where the header can be unicode.
+ """
+ auth = request.META.get('HTTP_AUTHORIZATION', b'')
+ if type(auth) == type(''):
+ # Work around django test client oddness
+ auth = auth.encode(HTTP_HEADER_ENCODING)
+ return auth
+
+
class BaseAuthentication(object):
"""
All authentication classes should extend BaseAuthentication.
@@ -43,22 +56,22 @@ class BasicAuthentication(BaseAuthentication):
Returns a `User` if a correct username and password have been supplied
using HTTP Basic authentication. Otherwise returns `None`.
"""
- auth = request.META.get('HTTP_AUTHORIZATION', b'')
- if type(auth) == type(''):
- # Work around django test client oddness
- auth = auth.encode(HTTP_HEADER_ENCODING)
- auth = auth.split()
+ auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != b'basic':
return None
- if len(auth) != 2:
- raise exceptions.AuthenticationFailed('Invalid basic header')
+ if len(auth) == 1:
+ msg = 'Invalid basic header. No credentials provided.'
+ if len(auth) > 2:
+ msg = 'Invalid basic header. Credentials string should not contain spaces.'
+ raise exceptions.AuthenticationFailed(msg)
try:
auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')
except (TypeError, UnicodeDecodeError):
- raise exceptions.AuthenticationFailed('Invalid basic header')
+ msg = 'Invalid basic header. Credentials not correctly base64 encoded'
+ raise exceptions.AuthenticationFailed(msg)
userid, password = auth_parts[0], auth_parts[2]
return self.authenticate_credentials(userid, password)
@@ -68,9 +81,9 @@ class BasicAuthentication(BaseAuthentication):
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)
- raise exceptions.AuthenticationFailed('Invalid username/password')
+ if user is None or not user.is_active:
+ raise exceptions.AuthenticationFailed('Invalid username/password')
+ return (user, None)
def authenticate_header(self, request):
return 'Basic realm="%s"' % self.www_authenticate_realm
@@ -129,13 +142,16 @@ class TokenAuthentication(BaseAuthentication):
"""
def authenticate(self, request):
- auth = request.META.get('HTTP_AUTHORIZATION', '').split()
+ auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != "token":
return None
- if len(auth) != 2:
- raise exceptions.AuthenticationFailed('Invalid token header')
+ if len(auth) == 1:
+ msg = 'Invalid token header. No credentials provided.'
+ if len(auth) > 2:
+ msg = 'Invalid token header. Token string should not contain spaces.'
+ raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(auth[1])
@@ -145,9 +161,10 @@ class TokenAuthentication(BaseAuthentication):
except self.model.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid token')
- if token.user.is_active:
- return (token.user, token)
- raise exceptions.AuthenticationFailed('User inactive or deleted')
+ if not token.user.is_active:
+ raise exceptions.AuthenticationFailed('User inactive or deleted')
+
+ return (token.user, token)
def authenticate_header(self, request):
return 'Token'
@@ -162,8 +179,8 @@ class OAuthAuthentication(BaseAuthentication):
"""
www_authenticate_realm = 'api'
- def __init__(self, **kwargs):
- super(OAuthAuthentication, self).__init__(**kwargs)
+ def __init__(self, *args, **kwargs):
+ super(OAuthAuthentication, self).__init__(*args, **kwargs)
if oauth is None:
raise ImproperlyConfigured(
@@ -258,57 +275,59 @@ class OAuth2Authentication(BaseAuthentication):
"""
OAuth 2 authentication backend using `django-oauth2-provider`
"""
- require_active = True
+ www_authenticate_realm = 'api'
+
+ def __init__(self, *args, **kwargs):
+ super(OAuth2Authentication, self).__init__(*args, **kwargs)
- 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.")
+ 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
+ Returns two-tuple of (user, token) if authentication succeeds,
+ or None otherwise.
"""
- auth = request.META.get('HTTP_AUTHORIZATION', '').split()
- if not auth or auth[0].lower() != "bearer":
- raise exceptions.AuthenticationFailed('Invalid Authorization token type')
- if len(auth) != 2:
- raise exceptions.AuthenticationFailed('Invalid token header')
+ auth = get_authorization_header(request).split()
+
+ if not auth or auth[0].lower() != 'bearer':
+ return None
+
+ if len(auth) == 1:
+ msg = 'Invalid bearer header. No credentials provided.'
+ if len(auth) > 2:
+ msg = 'Invalid bearer header. Token string should not contain spaces.'
+ raise exceptions.AuthenticationFailed(msg)
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 request, given the access token.
"""
- # authenticate the client
+ # Authenticate the client
oauth2_client_form = oauth2_provider_forms.ClientAuthForm(request.REQUEST)
if not oauth2_client_form.is_valid():
- raise exceptions.AuthenticationFailed("Client could not be validated")
+ raise exceptions.AuthenticationFailed('Client could not be validated')
client = oauth2_client_form.cleaned_data.get('client')
- # retrieve the `oauth2_provider.models.OAuth2AccessToken` instance from the access_token
+ # Retrieve the `OAuth2AccessToken` instance from the access_token
auth_backend = oauth2_provider_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
+ raise exceptions.AuthenticationFailed('Invalid token')
- if not self.check_active(token.user):
- raise exceptions.AuthenticationFailed('User not active: %s' % token.user.username)
+ user = token.user
- if client and token:
- request.user = token.user
- return (request.user, None)
+ if not user.is_active:
+ msg = 'User inactive or deleted: %s' % user.username
+ raise exceptions.AuthenticationFailed(msg)
- raise exceptions.AuthenticationFailed(
- 'You are not allowed to access this resource.')
+ return (token.user, token)
def authenticate_header(self, request):
"""
@@ -316,16 +335,4 @@ class OAuth2Authentication(BaseAuthentication):
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
+ return 'Bearer realm="%s"' % self.www_authenticate_realm