diff --git a/oauth2_provider/compat.py b/oauth2_provider/compat.py index e2c90eba1..e82e4ef97 100644 --- a/oauth2_provider/compat.py +++ b/oauth2_provider/compat.py @@ -15,9 +15,9 @@ from urllib.parse import urlparse, parse_qs, urlunparse try: - from urllib import urlencode + from urllib import urlencode, unquote_plus except ImportError: - from urllib.parse import urlencode + from urllib.parse import urlencode, unquote_plus # Django 1.5 add support for custom auth user model if django.VERSION >= (1, 5): diff --git a/oauth2_provider/oauth2_validators.py b/oauth2_provider/oauth2_validators.py index d52a8e099..c877e068a 100644 --- a/oauth2_provider/oauth2_validators.py +++ b/oauth2_provider/oauth2_validators.py @@ -8,6 +8,7 @@ from django.contrib.auth import authenticate from oauthlib.oauth2 import RequestValidator +from .compat import unquote_plus from .models import Grant, AccessToken, RefreshToken, get_application_model from .settings import oauth2_settings @@ -44,7 +45,7 @@ def _authenticate_basic_auth(self, request): client_id, client_secret = auth_string_decoded.split(':', 1) try: - request.client = Application.objects.get(client_id=client_id, client_secret=client_secret) + request.client = Application.objects.get(client_id=unquote_plus(client_id), client_secret=unquote_plus(client_secret)) return True except Application.DoesNotExist: diff --git a/oauth2_provider/tests/test_client_credential.py b/oauth2_provider/tests/test_client_credential.py index f65ab2106..7d64360e9 100644 --- a/oauth2_provider/tests/test_client_credential.py +++ b/oauth2_provider/tests/test_client_credential.py @@ -1,6 +1,11 @@ from __future__ import unicode_literals import json +import base64 +try: + import urllib.parse as urllib +except ImportError: + import urllib from django.core.urlresolvers import reverse from django.test import TestCase, RequestFactory @@ -116,3 +121,44 @@ def get_scopes(self): self.assertEqual(r.user, self.dev_user) self.assertEqual(r.client, self.application) self.assertEqual(r.scopes, ['read', 'write']) + + +class TestClientResourcePasswordBased(BaseTest): + def test_client_resource_password_based(self): + """ + Request an access token using Resource Owner Password Based flow + """ + + self.application.delete() + self.application = Application( + name="test_client_credentials_app", + user=self.dev_user, + client_type=Application.CLIENT_CONFIDENTIAL, + authorization_grant_type=Application.GRANT_PASSWORD, + ) + self.application.save() + + token_request_data = { + 'grant_type': 'password', + 'username': 'test_user', + 'password': '123456' + } + auth_headers = self.get_basic_auth_header(urllib.quote_plus(self.application.client_id), urllib.quote_plus(self.application.client_secret)) + response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers) + self.assertEqual(response.status_code, 200) + + content = json.loads(response.content.decode("utf-8")) + access_token = content['access_token'] + + # use token to access the resource + auth_headers = { + 'HTTP_AUTHORIZATION': 'Bearer ' + access_token, + } + request = self.factory.get("/fake-resource", **auth_headers) + request.user = self.test_user + + view = ResourceView.as_view() + response = view(request) + self.assertEqual(response, "This is a protected resource") + +