diff options
| -rw-r--r-- | .travis.yml | 6 | ||||
| -rw-r--r-- | rest_framework/authentication.py | 12 | ||||
| -rw-r--r-- | rest_framework/request.py | 4 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 8 | ||||
| -rw-r--r-- | rest_framework/tests/test_authentication.py | 26 | ||||
| -rw-r--r-- | tox.ini | 32 |
6 files changed, 64 insertions, 24 deletions
diff --git a/.travis.yml b/.travis.yml index f6b4753d..60b48cba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: - "3.3" env: - - DJANGO="https://www.djangoproject.com/download/1.7a2/tarball/" + - DJANGO="https://www.djangoproject.com/download/1.7b1/tarball/" - DJANGO="django==1.6.2" - DJANGO="django==1.5.5" - DJANGO="django==1.4.10" @@ -23,7 +23,7 @@ install: - "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi" - "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} == '3' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7a2/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" + - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7b1/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - export PYTHONPATH=. script: @@ -32,7 +32,7 @@ script: matrix: exclude: - python: "2.6" - env: DJANGO="https://www.djangoproject.com/download/1.7a2/tarball/" + env: DJANGO="https://www.djangoproject.com/download/1.7b1/tarball/" - python: "3.2" env: DJANGO="django==1.4.10" - python: "3.2" diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index b0e88d88..da9ca510 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -6,6 +6,7 @@ import base64 from django.contrib.auth import authenticate from django.core.exceptions import ImproperlyConfigured +from django.conf import settings from rest_framework import exceptions, HTTP_HEADER_ENCODING from rest_framework.compat import CsrfViewMiddleware from rest_framework.compat import oauth, oauth_provider, oauth_provider_store @@ -291,6 +292,7 @@ class OAuth2Authentication(BaseAuthentication): OAuth 2 authentication backend using `django-oauth2-provider` """ www_authenticate_realm = 'api' + allow_query_params_token = settings.DEBUG def __init__(self, *args, **kwargs): super(OAuth2Authentication, self).__init__(*args, **kwargs) @@ -308,7 +310,13 @@ class OAuth2Authentication(BaseAuthentication): auth = get_authorization_header(request).split() - if not auth or auth[0].lower() != b'bearer': + if auth and auth[0].lower() == b'bearer': + access_token = auth[1] + elif 'access_token' in request.POST: + access_token = request.POST['access_token'] + elif 'access_token' in request.GET and self.allow_query_params_token: + access_token = request.GET['access_token'] + else: return None if len(auth) == 1: @@ -318,7 +326,7 @@ class OAuth2Authentication(BaseAuthentication): msg = 'Invalid bearer header. Token string should not contain spaces.' raise exceptions.AuthenticationFailed(msg) - return self.authenticate_credentials(request, auth[1]) + return self.authenticate_credentials(request, access_token) def authenticate_credentials(self, request, access_token): """ diff --git a/rest_framework/request.py b/rest_framework/request.py index ca70b49e..40467c03 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -346,7 +346,7 @@ class Request(object): media_type = self.content_type if stream is None or media_type is None: - empty_data = QueryDict('', self._request._encoding) + empty_data = QueryDict('', encoding=self._request._encoding) empty_files = MultiValueDict() return (empty_data, empty_files) @@ -362,7 +362,7 @@ class Request(object): # re-raise. Ensures we don't simply repeat the error when # attempting to render the browsable renderer response, or when # logging the request or similar. - self._data = QueryDict('', self._request._encoding) + self._data = QueryDict('', encoding=self._request._encoding) self._files = MultiValueDict() raise diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 01606e9c..cb7539e0 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -757,6 +757,9 @@ class ModelSerializer(Serializer): field.read_only = True ret[accessor_name] = field + + # Ensure that 'read_only_fields' is an iterable + assert isinstance(self.opts.read_only_fields, (list, tuple)), '`read_only_fields` must be a list or tuple' # Add the `read_only` flag to any fields that have been specified # in the `read_only_fields` option @@ -771,7 +774,10 @@ class ModelSerializer(Serializer): "on serializer '%s'." % (field_name, self.__class__.__name__)) ret[field_name].read_only = True - + + # Ensure that 'write_only_fields' is an iterable + assert isinstance(self.opts.write_only_fields, (list, tuple)), '`write_only_fields` must be a list or tuple' + for field_name in self.opts.write_only_fields: assert field_name not in self.base_fields.keys(), ( "field '%s' on serializer '%s' specified in " diff --git a/rest_framework/tests/test_authentication.py b/rest_framework/tests/test_authentication.py index 8caeb081..c37d2a51 100644 --- a/rest_framework/tests/test_authentication.py +++ b/rest_framework/tests/test_authentication.py @@ -3,6 +3,7 @@ from django.contrib.auth.models import User from django.http import HttpResponse from django.test import TestCase from django.utils import unittest +from django.utils.http import urlencode from rest_framework import HTTP_HEADER_ENCODING from rest_framework import exceptions from rest_framework import permissions @@ -53,10 +54,14 @@ urlpatterns = patterns('', permission_classes=[permissions.TokenHasReadWriteScope])) ) +class OAuth2AuthenticationDebug(OAuth2Authentication): + allow_query_params_token = True + if oauth2_provider is not None: urlpatterns += patterns('', url(r'^oauth2/', include('provider.oauth2.urls', namespace='oauth2')), url(r'^oauth2-test/$', MockView.as_view(authentication_classes=[OAuth2Authentication])), + url(r'^oauth2-test-debug/$', MockView.as_view(authentication_classes=[OAuth2AuthenticationDebug])), url(r'^oauth2-with-scope-test/$', MockView.as_view(authentication_classes=[OAuth2Authentication], permission_classes=[permissions.TokenHasReadWriteScope])), ) @@ -546,6 +551,27 @@ class OAuth2Tests(TestCase): self.assertEqual(response.status_code, 200) @unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed') + def test_post_form_passing_auth_url_transport(self): + """Ensure GETing form over OAuth with correct client credentials in form data succeed""" + response = self.csrf_client.post('/oauth2-test/', + data={'access_token': self.access_token.token}) + self.assertEqual(response.status_code, 200) + + @unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed') + def test_get_form_passing_auth_url_transport(self): + """Ensure GETing form over OAuth with correct client credentials in query succeed when DEBUG is True""" + query = urlencode({'access_token': self.access_token.token}) + response = self.csrf_client.get('/oauth2-test-debug/?%s' % query) + self.assertEqual(response.status_code, 200) + + @unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed') + def test_get_form_failing_auth_url_transport(self): + """Ensure GETing form over OAuth with correct client credentials in query fails when DEBUG is False""" + query = urlencode({'access_token': self.access_token.token}) + response = self.csrf_client.get('/oauth2-test/?%s' % query) + self.assertIn(response.status_code, (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN)) + + @unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed') def test_post_form_passing_auth(self): """Ensure POSTing form over OAuth with correct credentials passes and does not require CSRF""" auth = self._create_authorization_header() @@ -7,22 +7,22 @@ commands = {envpython} rest_framework/runtests/runtests.py [testenv:py3.3-django1.7] basepython = python3.3 -deps = https://www.djangoproject.com/download/1.7a2/tarball/ - django-filter==0.6a1 +deps = https://www.djangoproject.com/download/1.7b1/tarball/ + django-filter==0.7 defusedxml==0.3 Pillow==2.3.0 [testenv:py3.2-django1.7] basepython = python3.2 -deps = https://www.djangoproject.com/download/1.7a2/tarball/ - django-filter==0.6a1 +deps = https://www.djangoproject.com/download/1.7b1/tarball/ + django-filter==0.7 defusedxml==0.3 Pillow==2.3.0 [testenv:py2.7-django1.7] basepython = python2.7 -deps = https://www.djangoproject.com/download/1.7a2/tarball/ - django-filter==0.6a1 +deps = https://www.djangoproject.com/download/1.7b1/tarball/ + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 @@ -33,21 +33,21 @@ deps = https://www.djangoproject.com/download/1.7a2/tarball/ [testenv:py3.3-django1.6] basepython = python3.3 deps = Django==1.6 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 Pillow==2.3.0 [testenv:py3.2-django1.6] basepython = python3.2 deps = Django==1.6 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 Pillow==2.3.0 [testenv:py2.7-django1.6] basepython = python2.7 deps = Django==1.6 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 @@ -58,7 +58,7 @@ deps = Django==1.6 [testenv:py2.6-django1.6] basepython = python2.6 deps = Django==1.6 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 @@ -69,21 +69,21 @@ deps = Django==1.6 [testenv:py3.3-django1.5] basepython = python3.3 deps = django==1.5.5 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 Pillow==2.3.0 [testenv:py3.2-django1.5] basepython = python3.2 deps = django==1.5.5 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 Pillow==2.3.0 [testenv:py2.7-django1.5] basepython = python2.7 deps = django==1.5.5 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 @@ -94,7 +94,7 @@ deps = django==1.5.5 [testenv:py2.6-django1.5] basepython = python2.6 deps = django==1.5.5 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 @@ -105,7 +105,7 @@ deps = django==1.5.5 [testenv:py2.7-django1.4] basepython = python2.7 deps = django==1.4.10 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 @@ -116,7 +116,7 @@ deps = django==1.4.10 [testenv:py2.6-django1.4] basepython = python2.6 deps = django==1.4.10 - django-filter==0.6a1 + django-filter==0.7 defusedxml==0.3 django-oauth-plus==2.2.1 oauth2==1.5.211 |
