From 7ab63cb587ec51d8ba1e15e4e8ef8f4b30dfdeac Mon Sep 17 00:00:00 2001 From: Clinton Blackburn Date: Tue, 12 Apr 2016 18:22:39 -0400 Subject: [PATCH] Updated the default scopes for the client credentials grant ECOM-4196 --- provider/__init__.py | 2 +- provider/oauth2/forms.py | 19 ++++++++++++------- provider/oauth2/tests.py | 12 +++++++++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/provider/__init__.py b/provider/__init__.py index a6221b3d..3f6fab60 100644 --- a/provider/__init__.py +++ b/provider/__init__.py @@ -1 +1 @@ -__version__ = '1.0.2' +__version__ = '1.0.3' diff --git a/provider/oauth2/forms.py b/provider/oauth2/forms.py index dcd5a69e..9ddbab17 100644 --- a/provider/oauth2/forms.py +++ b/provider/oauth2/forms.py @@ -3,7 +3,7 @@ from django.utils.encoding import smart_unicode from django.utils.translation import ugettext as _ -from provider import constants, scope +from provider import scope from provider.constants import RESPONSE_TYPE_CHOICES, SCOPES from provider.forms import OAuthForm, OAuthValidationError from provider.oauth2.models import Client, Grant, RefreshToken @@ -340,10 +340,15 @@ def clean(self): class ClientCredentialsGrantForm(ScopeMixin, OAuthForm): """ Validate a client credentials grant request. """ + scope = forms.CharField(required=False) - def clean(self): - cleaned_data = super(ClientCredentialsGrantForm, self).clean() - # We do not fully support scopes for this grant type; however, a scope is required - # in order to create an access token. Default to read-only access. - cleaned_data['scope'] = constants.READ - return cleaned_data + def clean_scope(self): + # NOTE (CCB): This is a horrible hack, like much of our OAuth work. The scopes are declared in + # edx-oauth2-provider. (See edx_oauth2_provider/constants.py.) However, we need to provide a default scope + # that (a) gives the token basic read access and (b) allows access to the user info endpoint. This value + # represents the following scopes: openid (1), profile (2), email (4), permissions (32). At present, this is + # all scopes except course_staff and course_instructor. These scopes are normally associated with actual + # users, whereas the client credentials grant will primarily be used by service users. + # + # In the future, we should limit the allowable scopes either at a global or per-client level. + return 39 diff --git a/provider/oauth2/tests.py b/provider/oauth2/tests.py index 96caf86d..0f636160 100644 --- a/provider/oauth2/tests.py +++ b/provider/oauth2/tests.py @@ -597,7 +597,7 @@ def setUp(self): super(ClientCredentialsAccessTokenTests, self).setUp() AccessToken.objects.all().delete() - def request_access_token(self, client_id=None, client_secret=None): + def request_access_token(self, client_id=None, client_secret=None, scope=None): """ Issues an access token request using the client credentials grant. Arguments: @@ -614,6 +614,11 @@ def request_access_token(self, client_id=None, client_secret=None): 'client_secret': client_secret or client.client_secret, } + if scope: + data.update({ + 'scope': scope, + }) + return self.client.post(self.access_token_url(), data) def assert_valid_access_token_response(self, access_token, response): @@ -634,9 +639,10 @@ def assert_valid_access_token_response(self, access_token, response): def get_latest_access_token(self): return AccessToken.objects.filter(client=self.get_client()).order_by('-id')[0] - def test_authorize_success(self): + @ddt.data(None, 'read') + def test_authorize_success(self, scope): """ Verify the endpoint successfully issues an access token using the client credentials grant. """ - response = self.request_access_token() + response = self.request_access_token(scope=scope) self.assertEqual(200, response.status_code, response.content) access_token = self.get_latest_access_token()