Merge pull request #20076 from edx/robrap/ARCH-603-oauth-application-access-command

ARCH-603: add optional scopes to create application access
This commit is contained in:
Robert Raposa
2019-03-29 10:01:54 -04:00
committed by GitHub
2 changed files with 54 additions and 5 deletions

View File

@@ -1,5 +1,7 @@
"""
Management command for creating a Django OAuth Toolkit Application model.
Also creates an oauth_dispatch application access if scopes are provided.
"""
from __future__ import unicode_literals
@@ -9,6 +11,7 @@ import logging
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from oauth2_provider.models import get_application_model
from openedx.core.djangoapps.oauth_dispatch.models import ApplicationAccess
logger = logging.getLogger(__name__)
@@ -59,6 +62,35 @@ class Command(BaseCommand):
dest='client_secret',
default='',
help='The client_secret for this application. If omitted, one will be generated.')
parser.add_argument('--scopes',
action='store',
dest='scopes',
default='',
help='Comma-separated list of scopes that this application will be allowed to request.')
def _create_application_access(self, application, scopes):
"""
If scopes are supplied, creates an oauth_dispatch ApplicationAccess for the provided
scopes and DOT application.
"""
if not scopes:
return
if ApplicationAccess.objects.filter(application_id=application.id).exists():
logger.info('Application access for application {} already exists.'.format(
application.name,
))
return
application_access = ApplicationAccess.objects.create(
application_id=application.id,
scopes=scopes,
)
application_access.save()
logger.info('Created application access for {} with scopes: {}'.format(
application.name,
application_access.scopes,
))
def handle(self, *args, **options):
app_name = options['name']
@@ -69,6 +101,7 @@ class Command(BaseCommand):
client_type = Application.CLIENT_PUBLIC if options['public'] else Application.CLIENT_CONFIDENTIAL
client_id = options['client_id']
client_secret = options['client_secret']
scopes = options['scopes']
user = User.objects.get(username=username)
@@ -77,6 +110,8 @@ class Command(BaseCommand):
app_name,
username
))
application = Application.objects.get(user=user, name=app_name)
self._create_application_access(application, scopes)
return
create_kwargs = dict(
@@ -100,3 +135,4 @@ class Command(BaseCommand):
application.client_id,
application.client_secret
))
self._create_application_access(application, scopes)

View File

@@ -9,6 +9,7 @@ from django.core.management import call_command
from django.test import TestCase
from oauth2_provider.models import get_application_model
from openedx.core.djangoapps.oauth_dispatch.models import ApplicationAccess
from student.tests.factories import UserFactory
from ..create_dot_application import Command
@@ -31,13 +32,13 @@ class TestCreateDotApplication(TestCase):
Application.objects.filter(user=self.user).delete()
@ddt.data(
(None, None, None, None, False),
(None, None, 'client-abc', None, False),
(None, None, None, 'great-big-secret', False),
('password', True, 'client-dce', 'has-a-great-big-secret', True),
(None, None, None, None, False, None),
(None, None, 'client-abc', None, False, None),
(None, None, None, 'great-big-secret', False, 'email,profile,user_id'),
('password', True, 'client-dce', 'has-a-great-big-secret', True, None),
)
@ddt.unpack
def test_create_dot_application(self, grant_type, public, client_id, client_secret, skip_auth):
def test_create_dot_application(self, grant_type, public, client_id, client_secret, skip_auth, scopes):
# Add optional arguments if provided
call_args = ['testing_application', self.user.username]
if grant_type:
@@ -60,6 +61,9 @@ class TestCreateDotApplication(TestCase):
call_args.append(client_secret)
if skip_auth:
call_args.append('--skip-authorization')
if scopes:
call_args.append('--scopes')
call_args.append(scopes)
call_command(Command(), *call_args)
@@ -78,8 +82,17 @@ class TestCreateDotApplication(TestCase):
if client_secret:
self.assertEqual(client_secret, application.client_secret)
if scopes:
app_access_list = ApplicationAccess.objects.filter(application_id=application.id)
self.assertEqual(1, len(app_access_list))
app_access = app_access_list[0]
self.assertEqual(scopes.split(','), app_access.scopes)
# When called a second time with the same arguments, the command should
# exit gracefully without creating a second application.
call_command(Command(), *call_args)
apps = Application.objects.filter(name='testing_application')
self.assertEqual(1, len(apps))
if scopes:
app_access_list = ApplicationAccess.objects.filter(application_id=application.id)
self.assertEqual(1, len(app_access_list))