diff options
Diffstat (limited to 'rest_framework/authentication.py')
| -rw-r--r-- | rest_framework/authentication.py | 118 |
1 files changed, 108 insertions, 10 deletions
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index d4ba7967..4d6e3375 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -3,10 +3,11 @@ Provides a set of pluggable authentication policies. """ from __future__ import unicode_literals from django.contrib.auth import authenticate -from django.utils.encoding import DjangoUnicodeDecodeError +from django.core.exceptions import ImproperlyConfigured from rest_framework import exceptions, HTTP_HEADER_ENCODING from rest_framework.compat import CsrfViewMiddleware -from rest_framework.compat import oauth2_provider +from rest_framework.compat import oauth, oauth_provider, oauth_provider_store +from rest_framework.compat import oauth2_provider, oauth2_provider_forms, oauth2_provider_backends from rest_framework.authtoken.models import Token import base64 @@ -59,11 +60,7 @@ class BasicAuthentication(BaseAuthentication): except (TypeError, UnicodeDecodeError): raise exceptions.AuthenticationFailed('Invalid basic header') - try: - userid, password = auth_parts[0], auth_parts[2] - except DjangoUnicodeDecodeError: - raise exceptions.AuthenticationFailed('Invalid basic header') - + userid, password = auth_parts[0], auth_parts[2] return self.authenticate_credentials(userid, password) def authenticate_credentials(self, userid, password): @@ -156,6 +153,107 @@ class TokenAuthentication(BaseAuthentication): return 'Token' +class OAuthAuthentication(BaseAuthentication): + """ + OAuth 1.0a authentication backend using `django-oauth-plus` and `oauth2`. + + Note: The `oauth2` package actually provides oauth1.0a support. Urg. + We import it from the `compat` module as `oauth`. + """ + www_authenticate_realm = 'api' + + def __init__(self, **kwargs): + super(OAuthAuthentication, self).__init__(**kwargs) + + if oauth is None: + raise ImproperlyConfigured( + "The 'oauth2' package could not be imported." + "It is required for use with the 'OAuthAuthentication' class.") + + if oauth_provider is None: + raise ImproperlyConfigured( + "The 'django-oauth-plus' package could not be imported." + "It is required for use with the 'OAuthAuthentication' class.") + + def authenticate(self, request): + """ + Returns two-tuple of (user, token) if authentication succeeds, + or None otherwise. + """ + try: + oauth_request = oauth_provider.utils.get_oauth_request(request) + except oauth.Error as err: + raise exceptions.AuthenticationFailed(err.message) + + oauth_params = oauth_provider.consts.OAUTH_PARAMETERS_NAMES + + found = any(param for param in oauth_params if param in oauth_request) + missing = list(param for param in oauth_params if param not in oauth_request) + + if not found: + # OAuth authentication was not attempted. + return None + + if missing: + # OAuth was attempted but missing parameters. + msg = 'Missing parameters: %s' % (', '.join(missing)) + raise exceptions.AuthenticationFailed(msg) + + if not self.check_nonce(request, oauth_request): + msg = 'Nonce check failed' + raise exceptions.AuthenticationFailed(msg) + + try: + consumer_key = oauth_request.get_parameter('oauth_consumer_key') + consumer = oauth_provider_store.get_consumer(request, oauth_request, consumer_key) + except oauth_provider_store.InvalidConsumerError as err: + raise exceptions.AuthenticationFailed(err) + + if consumer.status != oauth_provider.consts.ACCEPTED: + msg = 'Invalid consumer key status: %s' % consumer.get_status_display() + raise exceptions.AuthenticationFailed(msg) + + try: + token_param = oauth_request.get_parameter('oauth_token') + token = oauth_provider_store.get_access_token(request, oauth_request, consumer, token_param) + except oauth_provider_store.InvalidTokenError: + msg = 'Invalid access token: %s' % oauth_request.get_parameter('oauth_token') + raise exceptions.AuthenticationFailed(msg) + + try: + self.validate_token(request, consumer, token) + except oauth.Error as err: + raise exceptions.AuthenticationFailed(err.message) + + user = token.user + + if not user.is_active: + msg = 'User inactive or deleted: %s' % user.username + raise exceptions.AuthenticationFailed(msg) + + return (token.user, token) + + def authenticate_header(self, request): + """ + If permission is denied, return a '401 Unauthorized' response, + with an appropraite 'WWW-Authenticate' header. + """ + return 'OAuth realm="%s"' % self.www_authenticate_realm + + def validate_token(self, request, consumer, token): + """ + Check the token and raise an `oauth.Error` exception if invalid. + """ + oauth_server, oauth_request = oauth_provider.utils.initialize_server_request(request) + oauth_server.verify_request(oauth_request, consumer, token) + + def check_nonce(self, request, oauth_request): + """ + Checks nonce of request, and return True if valid. + """ + return oauth_provider_store.check_nonce(request, oauth_request, oauth_request['oauth_nonce']) + + class OAuth2Authentication(BaseAuthentication): """ OAuth 2 authentication backend using `django-oauth2-provider` @@ -189,13 +287,13 @@ class OAuth2Authentication(BaseAuthentication): """ # authenticate the client - oauth2_client_form = oauth2_provider.forms.ClientAuthForm(request.REQUEST) + oauth2_client_form = oauth2_provider_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_provider.models.OAuth2AccessToken` instance from the access_token - auth_backend = oauth2_provider.backends.AccessTokenBackend() + 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 @@ -214,7 +312,7 @@ class OAuth2Authentication(BaseAuthentication): def authenticate_header(self, request): """ - Bearer is the only finalized type currently + Bearer is the only finalized type currently Check details on the `OAuth2Authentication.authenticate` method """ |
