Remove DOP dispatching from oauth_dispatch.
https://openedx.atlassian.net/browse/BOM-1330
This commit is contained in:
@@ -14,45 +14,6 @@ from openedx.core.djangoapps.oauth_dispatch.tests.constants import DUMMY_REDIREC
|
||||
from ..views import DOTAccessTokenExchangeView
|
||||
|
||||
|
||||
class DOPAdapterMixin(object):
|
||||
"""
|
||||
Mixin to rewire existing tests to use django-oauth2-provider (DOP) backend
|
||||
|
||||
Overwrites self.client_id, self.access_token, self.oauth2_adapter
|
||||
"""
|
||||
client_id = 'dop_test_client_id'
|
||||
access_token = 'dop_test_access_token'
|
||||
oauth2_adapter = adapters.DOPAdapter()
|
||||
|
||||
def create_public_client(self, user, client_id=None):
|
||||
"""
|
||||
Create an oauth client application that is public.
|
||||
"""
|
||||
return self.oauth2_adapter.create_public_client(
|
||||
name='Test Public Client',
|
||||
user=user,
|
||||
client_id=client_id,
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
)
|
||||
|
||||
def create_confidential_client(self, user, client_id=None):
|
||||
"""
|
||||
Create an oauth client application that is confidential.
|
||||
"""
|
||||
return self.oauth2_adapter.create_confidential_client(
|
||||
name='Test Confidential Client',
|
||||
user=user,
|
||||
client_id=client_id,
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
)
|
||||
|
||||
def get_token_response_keys(self):
|
||||
"""
|
||||
Return the set of keys provided when requesting an access token
|
||||
"""
|
||||
return {'access_token', 'token_type', 'expires_in', 'scope'}
|
||||
|
||||
|
||||
class DOTAdapterMixin(object):
|
||||
"""
|
||||
Mixin to rewire existing tests to use django-oauth-toolkit (DOT) backend
|
||||
|
||||
@@ -3,5 +3,4 @@ Adapters to provide a common interface to django-oauth2-provider (DOP) and
|
||||
django-oauth-toolkit (DOT).
|
||||
"""
|
||||
|
||||
from .dop import DOPAdapter
|
||||
from .dot import DOTAdapter
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
"""
|
||||
Adapter to isolate django-oauth2-provider dependencies
|
||||
"""
|
||||
|
||||
|
||||
from provider import constants, scope
|
||||
from provider.oauth2 import models
|
||||
|
||||
|
||||
class DOPAdapter(object):
|
||||
"""
|
||||
Standard interface for working with django-oauth2-provider
|
||||
"""
|
||||
|
||||
backend = object()
|
||||
|
||||
def create_confidential_client(self, name, user, redirect_uri, client_id=None):
|
||||
"""
|
||||
Create an oauth client application that is confidential.
|
||||
"""
|
||||
return models.Client.objects.create(
|
||||
name=name,
|
||||
user=user,
|
||||
client_id=client_id,
|
||||
redirect_uri=redirect_uri,
|
||||
client_type=constants.CONFIDENTIAL,
|
||||
)
|
||||
|
||||
def create_public_client(self, name, user, redirect_uri, client_id=None):
|
||||
"""
|
||||
Create an oauth client application that is public.
|
||||
"""
|
||||
return models.Client.objects.create(
|
||||
name=name,
|
||||
user=user,
|
||||
client_id=client_id,
|
||||
redirect_uri=redirect_uri,
|
||||
client_type=constants.PUBLIC,
|
||||
)
|
||||
|
||||
def get_client(self, **filters):
|
||||
"""
|
||||
Get the oauth client application with the specified filters.
|
||||
|
||||
Wraps django's queryset.get() method.
|
||||
"""
|
||||
return models.Client.objects.get(**filters)
|
||||
|
||||
def get_client_for_token(self, token):
|
||||
"""
|
||||
Given an AccessToken object, return the associated client application.
|
||||
"""
|
||||
return token.client
|
||||
|
||||
def get_access_token(self, token_string):
|
||||
"""
|
||||
Given a token string, return the matching AccessToken object.
|
||||
"""
|
||||
return models.AccessToken.objects.get(token=token_string)
|
||||
|
||||
def create_access_token_for_test(self, token_string, client, user, expires):
|
||||
"""
|
||||
Returns a new AccessToken object created from the given arguments.
|
||||
This method is currently used only by tests.
|
||||
"""
|
||||
return models.AccessToken.objects.create(
|
||||
token=token_string,
|
||||
client=client,
|
||||
user=user,
|
||||
expires=expires,
|
||||
)
|
||||
|
||||
def get_token_scope_names(self, token):
|
||||
"""
|
||||
Given an access token object, return its scopes.
|
||||
"""
|
||||
return scope.to_names(token.scope)
|
||||
|
||||
def is_client_restricted(self, client): # pylint: disable=unused-argument
|
||||
"""
|
||||
Returns true if the client is set up as a RestrictedApplication.
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_authorization_filters(self, client): # pylint: disable=unused-argument
|
||||
"""
|
||||
Get the authorization filters for the given client application.
|
||||
"""
|
||||
return []
|
||||
@@ -5,16 +5,12 @@ from oauth2_provider.models import AccessToken as dot_access_token
|
||||
from oauth2_provider.models import RefreshToken as dot_refresh_token
|
||||
from oauth2_provider.settings import oauth2_settings as dot_settings
|
||||
from oauthlib.oauth2.rfc6749.tokens import BearerToken
|
||||
from provider.oauth2.models import AccessToken as dop_access_token
|
||||
from provider.oauth2.models import RefreshToken as dop_refresh_token
|
||||
|
||||
|
||||
def destroy_oauth_tokens(user):
|
||||
"""
|
||||
Destroys ALL OAuth access and refresh tokens for the given user.
|
||||
"""
|
||||
dop_access_token.objects.filter(user=user.id).delete()
|
||||
dop_refresh_token.objects.filter(user=user.id).delete()
|
||||
dot_access_token.objects.filter(user=user.id).delete()
|
||||
dot_refresh_token.objects.filter(user=user.id).delete()
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
"""
|
||||
Tests for DOP Adapter
|
||||
"""
|
||||
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
import ddt
|
||||
from django.test import TestCase
|
||||
from django.utils.timezone import now
|
||||
from provider import constants
|
||||
from provider.oauth2 import models
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
from ..adapters import DOPAdapter
|
||||
from .constants import DUMMY_REDIRECT_URL
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class DOPAdapterTestCase(TestCase):
|
||||
"""
|
||||
Test class for DOPAdapter.
|
||||
"""
|
||||
|
||||
adapter = DOPAdapter()
|
||||
|
||||
def setUp(self):
|
||||
super(DOPAdapterTestCase, self).setUp()
|
||||
self.user = UserFactory()
|
||||
self.public_client = self.adapter.create_public_client(
|
||||
name='public client',
|
||||
user=self.user,
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
client_id='public-client-id',
|
||||
)
|
||||
self.confidential_client = self.adapter.create_confidential_client(
|
||||
name='confidential client',
|
||||
user=self.user,
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
client_id='confidential-client-id',
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
('confidential', constants.CONFIDENTIAL),
|
||||
('public', constants.PUBLIC),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_create_client(self, client_name, client_type):
|
||||
client = getattr(self, '{}_client'.format(client_name))
|
||||
self.assertIsInstance(client, models.Client)
|
||||
self.assertEqual(client.client_id, '{}-client-id'.format(client_name))
|
||||
self.assertEqual(client.client_type, client_type)
|
||||
|
||||
def test_get_client(self):
|
||||
client = self.adapter.get_client(client_type=constants.CONFIDENTIAL)
|
||||
self.assertIsInstance(client, models.Client)
|
||||
self.assertEqual(client.client_type, constants.CONFIDENTIAL)
|
||||
|
||||
def test_get_client_not_found(self):
|
||||
with self.assertRaises(models.Client.DoesNotExist):
|
||||
self.adapter.get_client(client_id='not-found')
|
||||
|
||||
def test_get_client_for_token(self):
|
||||
token = models.AccessToken(
|
||||
user=self.user,
|
||||
client=self.public_client,
|
||||
)
|
||||
self.assertEqual(self.adapter.get_client_for_token(token), self.public_client)
|
||||
|
||||
def test_get_access_token(self):
|
||||
token = self.adapter.create_access_token_for_test(
|
||||
'token-id',
|
||||
client=self.public_client,
|
||||
user=self.user,
|
||||
expires=now() + timedelta(days=30),
|
||||
)
|
||||
self.assertEqual(self.adapter.get_access_token(token_string='token-id'), token)
|
||||
@@ -10,7 +10,7 @@ from django.utils.timezone import now
|
||||
from mock import patch
|
||||
|
||||
from openedx.core.djangoapps.oauth_dispatch import jwt as jwt_api
|
||||
from openedx.core.djangoapps.oauth_dispatch.adapters import DOPAdapter, DOTAdapter
|
||||
from openedx.core.djangoapps.oauth_dispatch.adapters import DOTAdapter
|
||||
from openedx.core.djangoapps.oauth_dispatch.models import RestrictedApplication
|
||||
from openedx.core.djangoapps.oauth_dispatch.tests.mixins import AccessTokenMixin
|
||||
from openedx.core.djangoapps.oauth_dispatch.toggles import ENFORCE_JWT_SCOPES
|
||||
@@ -61,9 +61,8 @@ class TestCreateJWTs(AccessTokenMixin, TestCase):
|
||||
jwt_token, self.user, self.default_scopes, should_be_asymmetric_key=should_be_asymmetric_key,
|
||||
)
|
||||
|
||||
@ddt.data(DOPAdapter, DOPAdapter)
|
||||
def test_create_jwt_for_token(self, oauth_adapter_cls):
|
||||
oauth_adapter = oauth_adapter_cls()
|
||||
def test_create_jwt_for_token(self):
|
||||
oauth_adapter = DOTAdapter()
|
||||
jwt_token = self._create_jwt_for_token(oauth_adapter, use_asymmetric_key=False)
|
||||
self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=False)
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ from django.urls import reverse
|
||||
from jwkest import jwk
|
||||
from mock import call, patch
|
||||
from oauth2_provider import models as dot_models
|
||||
from provider import constants
|
||||
|
||||
from openedx.core.djangoapps.oauth_dispatch.toggles import ENFORCE_JWT_SCOPES
|
||||
from student.tests.factories import UserFactory
|
||||
@@ -86,7 +85,6 @@ class _DispatchingViewTestCase(TestCase):
|
||||
"""
|
||||
def setUp(self):
|
||||
super(_DispatchingViewTestCase, self).setUp()
|
||||
self.dop_adapter = adapters.DOPAdapter()
|
||||
self.dot_adapter = adapters.DOTAdapter()
|
||||
self.user = UserFactory()
|
||||
self.dot_app = self.dot_adapter.create_public_client(
|
||||
@@ -95,12 +93,6 @@ class _DispatchingViewTestCase(TestCase):
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
client_id='dot-app-client-id',
|
||||
)
|
||||
self.dop_app = self.dop_adapter.create_public_client(
|
||||
name='test dop client',
|
||||
user=self.user,
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
client_id='dop-app-client-id',
|
||||
)
|
||||
|
||||
self.dot_app_access = models.ApplicationAccess.objects.create(
|
||||
application=self.dot_app,
|
||||
@@ -197,7 +189,7 @@ class TestAccessTokenView(AccessTokenLoginMixin, mixins.AccessTokenMixin, _Dispa
|
||||
should_be_restricted=False,
|
||||
)
|
||||
|
||||
@ddt.data('dop_app', 'dot_app')
|
||||
@ddt.data('dot_app')
|
||||
def test_access_token_fields(self, client_attr):
|
||||
client = getattr(self, client_attr)
|
||||
response = self._post_request(self.user, client)
|
||||
@@ -227,15 +219,15 @@ class TestAccessTokenView(AccessTokenLoginMixin, mixins.AccessTokenMixin, _Dispa
|
||||
True
|
||||
)
|
||||
|
||||
@ddt.data('dop_app', 'dot_app')
|
||||
@ddt.data('dot_app')
|
||||
def test_jwt_access_token_from_parameter(self, client_attr):
|
||||
self._test_jwt_access_token(client_attr, token_type='jwt')
|
||||
|
||||
@ddt.data('dop_app', 'dot_app')
|
||||
@ddt.data('dot_app')
|
||||
def test_jwt_access_token_from_header(self, client_attr):
|
||||
self._test_jwt_access_token(client_attr, headers={'HTTP_X_TOKEN_TYPE': 'jwt'})
|
||||
|
||||
@ddt.data('dop_app', 'dot_app')
|
||||
@ddt.data('dot_app')
|
||||
def test_jwt_access_token_from_parameter_not_header(self, client_attr):
|
||||
self._test_jwt_access_token(client_attr, token_type='jwt', headers={'HTTP_X_TOKEN_TYPE': 'invalid'})
|
||||
|
||||
@@ -261,7 +253,7 @@ class TestAccessTokenView(AccessTokenLoginMixin, mixins.AccessTokenMixin, _Dispa
|
||||
'grant_type': grant_type.replace('-', '_'),
|
||||
}
|
||||
bad_response = self.client.post(self.url, invalid_body)
|
||||
self.assertEqual(bad_response.status_code, 400)
|
||||
self.assertEqual(bad_response.status_code, 401)
|
||||
expected_calls = [
|
||||
call('oauth_token_type', 'no_token_type_supplied'),
|
||||
call('oauth_grant_type', 'password'),
|
||||
@@ -322,12 +314,6 @@ class TestAccessTokenView(AccessTokenLoginMixin, mixins.AccessTokenMixin, _Dispa
|
||||
data = json.loads(response.content.decode('utf-8'))
|
||||
self.assertIn('refresh_token', data)
|
||||
|
||||
def test_dop_public_client_access_token(self):
|
||||
response = self._post_request(self.user, self.dop_app)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = json.loads(response.content.decode('utf-8'))
|
||||
self.assertNotIn('refresh_token', data)
|
||||
|
||||
@ddt.data(dot_models.Application.GRANT_CLIENT_CREDENTIALS, dot_models.Application.GRANT_PASSWORD)
|
||||
def test_jwt_access_token_scopes_and_filters(self, grant_type):
|
||||
"""
|
||||
@@ -396,7 +382,6 @@ class TestAuthorizationView(_DispatchingViewTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAuthorizationView, self).setUp()
|
||||
self.dop_adapter = adapters.DOPAdapter()
|
||||
self.user = UserFactory()
|
||||
self.dot_app = self.dot_adapter.create_confidential_client(
|
||||
name='test dot application',
|
||||
@@ -412,16 +397,10 @@ class TestAuthorizationView(_DispatchingViewTestCase):
|
||||
'other_filter:filter_val',
|
||||
]
|
||||
)
|
||||
self.dop_app = self.dop_adapter.create_confidential_client(
|
||||
name='test dop client',
|
||||
user=self.user,
|
||||
redirect_uri=DUMMY_REDIRECT_URL,
|
||||
client_id='confidential-dop-app-client-id',
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
('dop', 'authorize'),
|
||||
('dot', 'allow')
|
||||
('dot', 'allow'),
|
||||
('dot', 'authorize')
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_post_authorization_view(self, client_type, allow_field):
|
||||
@@ -506,23 +485,6 @@ class TestAuthorizationView(_DispatchingViewTestCase):
|
||||
expected_redirect_prefix = u'{}?'.format(DUMMY_REDIRECT_URL)
|
||||
self._assert_startswith(self._redirect_destination(response), expected_redirect_prefix)
|
||||
|
||||
def _check_dop_response(self, response):
|
||||
"""
|
||||
Check that django-oauth2-provider gives an appropriate authorization response.
|
||||
"""
|
||||
# django-oauth-provider redirects to a confirmation page
|
||||
self.assertRedirects(response, u'/oauth2/authorize/confirm', target_status_code=200)
|
||||
|
||||
context = response.context_data
|
||||
form = context['form']
|
||||
self.assertIsNone(form['authorize'].value())
|
||||
|
||||
oauth_data = context['oauth_data']
|
||||
self.assertEqual(oauth_data['redirect_uri'], DUMMY_REDIRECT_URL)
|
||||
self.assertEqual(oauth_data['state'], 'random_state_string')
|
||||
# TODO: figure out why it chooses this scope.
|
||||
self.assertEqual(oauth_data['scope'], constants.READ_WRITE)
|
||||
|
||||
def _assert_startswith(self, string, prefix):
|
||||
"""
|
||||
Assert that the string starts with the specified prefix.
|
||||
@@ -545,16 +507,9 @@ class TestViewDispatch(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestViewDispatch, self).setUp()
|
||||
self.dop_adapter = adapters.DOPAdapter()
|
||||
self.dot_adapter = adapters.DOTAdapter()
|
||||
self.user = UserFactory()
|
||||
self.view = views._DispatchingView() # pylint: disable=protected-access
|
||||
self.dop_adapter.create_public_client(
|
||||
name='',
|
||||
user=self.user,
|
||||
client_id='dop-id',
|
||||
redirect_uri=DUMMY_REDIRECT_URL
|
||||
)
|
||||
self.dot_adapter.create_public_client(
|
||||
name='',
|
||||
user=self.user,
|
||||
@@ -589,54 +544,26 @@ class TestViewDispatch(TestCase):
|
||||
"""
|
||||
return RequestFactory().get('/?client_id={}'.format(client_id))
|
||||
|
||||
def _verify_oauth_metrics_calls(self, mock_set_custom_metric, expected_oauth_adapter):
|
||||
"""
|
||||
Args:
|
||||
mock_set_custom_metric: MagicMock of set_custom_metric
|
||||
expected_oauth_adapter: Either 'dot' or 'dop'
|
||||
"""
|
||||
expected_calls = [
|
||||
call('oauth_client_id', '{}-id'.format(expected_oauth_adapter)),
|
||||
call('oauth_adapter', expected_oauth_adapter),
|
||||
]
|
||||
mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True)
|
||||
|
||||
@patch('edx_django_utils.monitoring.set_custom_metric')
|
||||
def test_dispatching_post_to_dot(self, mock_set_custom_metric):
|
||||
def test_dispatching_post_to_dot(self):
|
||||
request = self._post_request('dot-id')
|
||||
self.assertEqual(self.view.select_backend(request), self.dot_adapter.backend)
|
||||
self._verify_oauth_metrics_calls(mock_set_custom_metric, 'dot')
|
||||
|
||||
@patch('edx_django_utils.monitoring.set_custom_metric')
|
||||
def test_dispatching_post_to_dop(self, mock_set_custom_metric):
|
||||
request = self._post_request('dop-id')
|
||||
self.assertEqual(self.view.select_backend(request), self.dop_adapter.backend)
|
||||
self._verify_oauth_metrics_calls(mock_set_custom_metric, 'dop')
|
||||
|
||||
def test_dispatching_get_to_dot(self):
|
||||
request = self._get_request('dot-id')
|
||||
self.assertEqual(self.view.select_backend(request), self.dot_adapter.backend)
|
||||
|
||||
def test_dispatching_get_to_dop(self):
|
||||
request = self._get_request('dop-id')
|
||||
self.assertEqual(self.view.select_backend(request), self.dop_adapter.backend)
|
||||
|
||||
def test_dispatching_with_no_client(self):
|
||||
request = self._post_request(None)
|
||||
self.assertEqual(self.view.select_backend(request), self.dop_adapter.backend)
|
||||
self.assertEqual(self.view.select_backend(request), self.dot_adapter.backend)
|
||||
|
||||
def test_dispatching_with_invalid_client(self):
|
||||
request = self._post_request('abcesdfljh')
|
||||
self.assertEqual(self.view.select_backend(request), self.dop_adapter.backend)
|
||||
self.assertEqual(self.view.select_backend(request), self.dot_adapter.backend)
|
||||
|
||||
def test_get_view_for_dot(self):
|
||||
view_object = views.AccessTokenView()
|
||||
self.assert_is_view(view_object.get_view_for_backend(self.dot_adapter.backend))
|
||||
|
||||
def test_get_view_for_dop(self):
|
||||
view_object = views.AccessTokenView()
|
||||
self.assert_is_view(view_object.get_view_for_backend(self.dop_adapter.backend))
|
||||
|
||||
def test_get_view_for_no_backend(self):
|
||||
view_object = views.AccessTokenView()
|
||||
self.assertRaises(KeyError, view_object.get_view_for_backend, None)
|
||||
|
||||
@@ -10,8 +10,6 @@ from django.conf import settings
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import View
|
||||
from edx_django_utils import monitoring as monitoring_utils
|
||||
from edx_oauth2_provider import views as dop_views # django-oauth2-provider views
|
||||
from oauth2_provider import models as dot_models # django-oauth-toolkit
|
||||
from oauth2_provider import views as dot_views
|
||||
from ratelimit import ALL
|
||||
from ratelimit.decorators import ratelimit
|
||||
@@ -30,7 +28,6 @@ class _DispatchingView(View):
|
||||
"""
|
||||
|
||||
dot_adapter = adapters.DOTAdapter()
|
||||
dop_adapter = adapters.DOPAdapter()
|
||||
|
||||
def get_adapter(self, request):
|
||||
"""
|
||||
@@ -39,12 +36,7 @@ class _DispatchingView(View):
|
||||
client_id = self._get_client_id(request)
|
||||
monitoring_utils.set_custom_metric('oauth_client_id', client_id)
|
||||
|
||||
if dot_models.Application.objects.filter(client_id=client_id).exists() or not settings.ENABLE_DOP_ADAPTER:
|
||||
monitoring_utils.set_custom_metric('oauth_adapter', 'dot')
|
||||
return self.dot_adapter
|
||||
else:
|
||||
monitoring_utils.set_custom_metric('oauth_adapter', 'dop')
|
||||
return self.dop_adapter
|
||||
return self.dot_adapter
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
"""
|
||||
@@ -69,11 +61,7 @@ class _DispatchingView(View):
|
||||
Return the appropriate view from the requested backend.
|
||||
"""
|
||||
if backend == self.dot_adapter.backend:
|
||||
monitoring_utils.set_custom_metric('oauth_view', 'dot')
|
||||
return self.dot_view.as_view()
|
||||
elif backend == self.dop_adapter.backend:
|
||||
monitoring_utils.set_custom_metric('oauth_view', 'dop')
|
||||
return self.dop_view.as_view()
|
||||
else:
|
||||
raise KeyError('Failed to dispatch view. Invalid backend {}'.format(backend))
|
||||
|
||||
@@ -98,7 +86,6 @@ class AccessTokenView(_DispatchingView):
|
||||
Handle access token requests.
|
||||
"""
|
||||
dot_view = dot_views.TokenView
|
||||
dop_view = dop_views.AccessTokenView
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
response = super(AccessTokenView, self).dispatch(request, *args, **kwargs)
|
||||
@@ -128,7 +115,6 @@ class AuthorizationView(_DispatchingView):
|
||||
"""
|
||||
Part of the authorization flow.
|
||||
"""
|
||||
dop_view = dop_views.Capture
|
||||
dot_view = dot_overrides_views.EdxOAuth2AuthorizationView
|
||||
|
||||
|
||||
@@ -138,19 +124,6 @@ class AccessTokenExchangeView(_DispatchingView):
|
||||
"""
|
||||
dot_view = auth_exchange_views.DOTAccessTokenExchangeView
|
||||
|
||||
def get_view_for_backend(self, backend):
|
||||
"""
|
||||
Return the appropriate view from the requested backend.
|
||||
Since AccessTokenExchangeView no longer supports dop, this function needed to
|
||||
be overwritten from _DispatchingView, it was decided that the dop path should not be removed
|
||||
from _DispatchingView due to it still being used in other views(AuthorizationView, AccessTokenView)
|
||||
"""
|
||||
if backend == self.dot_adapter.backend:
|
||||
monitoring_utils.set_custom_metric('oauth_view', 'dot')
|
||||
return self.dot_view.as_view()
|
||||
else:
|
||||
raise KeyError('Failed to dispatch view. Invalid backend {}'.format(backend))
|
||||
|
||||
|
||||
class RevokeTokenView(_DispatchingView):
|
||||
"""
|
||||
|
||||
@@ -68,7 +68,6 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(OAuth2AllowInActiveUsersTests, self).setUp()
|
||||
self.dop_adapter = adapters.DOPAdapter()
|
||||
self.dot_adapter = adapters.DOTAdapter()
|
||||
self.csrf_client = APIClient(enforce_csrf_checks=True)
|
||||
self.username = 'john'
|
||||
@@ -76,29 +75,6 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
self.password = 'password'
|
||||
self.user = User.objects.create_user(self.username, self.email, self.password)
|
||||
|
||||
self.CLIENT_ID = 'client_key' # pylint: disable=invalid-name
|
||||
self.CLIENT_SECRET = 'client_secret' # pylint: disable=invalid-name
|
||||
self.ACCESS_TOKEN = 'access_token' # pylint: disable=invalid-name
|
||||
self.REFRESH_TOKEN = 'refresh_token' # pylint: disable=invalid-name
|
||||
|
||||
self.dop_oauth2_client = self.dop_adapter.create_public_client(
|
||||
name='example',
|
||||
user=self.user,
|
||||
client_id=self.CLIENT_ID,
|
||||
redirect_uri='https://example.edx/redirect',
|
||||
)
|
||||
|
||||
self.access_token = oauth2_provider.oauth2.models.AccessToken.objects.create(
|
||||
token=self.ACCESS_TOKEN,
|
||||
client=self.dop_oauth2_client,
|
||||
user=self.user,
|
||||
)
|
||||
self.refresh_token = oauth2_provider.oauth2.models.RefreshToken.objects.create(
|
||||
user=self.user,
|
||||
access_token=self.access_token,
|
||||
client=self.dop_oauth2_client,
|
||||
)
|
||||
|
||||
self.dot_oauth2_client = self.dot_adapter.create_public_client(
|
||||
name='example',
|
||||
user=self.user,
|
||||
@@ -111,6 +87,11 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
application=self.dot_oauth2_client,
|
||||
expires=now() + timedelta(days=30),
|
||||
)
|
||||
self.dot_refresh_token = dot_models.RefreshToken.objects.create(
|
||||
user=self.user,
|
||||
token='dot-refresh-token',
|
||||
application=self.dot_oauth2_client,
|
||||
)
|
||||
|
||||
# This is the a change we've made from the django-rest-framework-oauth version
|
||||
# of these tests.
|
||||
@@ -125,6 +106,11 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
# edx-auth2-provider.
|
||||
scope.SCOPE_NAME_DICT = {'read': constants.READ, 'write': constants.WRITE}
|
||||
|
||||
def _create_authorization_header(self, token=None):
|
||||
if token is None:
|
||||
token = self.dot_access_token.token
|
||||
return "Bearer {0}".format(token)
|
||||
|
||||
def get_with_bearer_token(self, target_url, params=None, token=None):
|
||||
"""
|
||||
Make a GET request to the specified URL with an OAuth2 bearer token. If
|
||||
@@ -151,11 +137,6 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
self.assertEqual(response.status_code, status_code)
|
||||
self.assertEqual(response_dict['error_code'], error_code)
|
||||
|
||||
def _create_authorization_header(self, token=None):
|
||||
if token is None:
|
||||
token = self.access_token.token
|
||||
return "Bearer {0}".format(token)
|
||||
|
||||
@ddt.data(None, {})
|
||||
@unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed')
|
||||
def test_get_form_with_wrong_authorization_header_token_type_failing(self, params):
|
||||
@@ -173,18 +154,13 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
# provided (yet).
|
||||
self.assertNotIn('error_code', json.loads(response.content.decode('utf-8')))
|
||||
|
||||
def test_get_form_passing_auth(self):
|
||||
"""Ensure GETing form over OAuth with correct client credentials succeed"""
|
||||
response = self.get_with_bearer_token(self.OAUTH2_BASE_TESTING_URL)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
def test_get_form_passing_auth_with_dot(self):
|
||||
response = self.get_with_bearer_token(self.OAUTH2_BASE_TESTING_URL, token=self.dot_access_token.token)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
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})
|
||||
query = urlencode({'access_token': self.dot_access_token.token})
|
||||
response = self.csrf_client.get(self.OAUTH2_BASE_TESTING_URL + '?%s' % query)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
@@ -198,7 +174,7 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
|
||||
def test_post_form_token_removed_failing_auth(self):
|
||||
"""Ensure POSTing when there is no OAuth access token in db fails"""
|
||||
self.access_token.delete()
|
||||
self.dot_access_token.delete()
|
||||
response = self.post_with_bearer_token(self.OAUTH2_BASE_TESTING_URL)
|
||||
self.check_error_codes(
|
||||
response,
|
||||
@@ -208,7 +184,7 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
|
||||
def test_post_form_with_refresh_token_failing_auth(self):
|
||||
"""Ensure POSTing with refresh token instead of access token fails"""
|
||||
response = self.post_with_bearer_token(self.OAUTH2_BASE_TESTING_URL, token=self.refresh_token.token)
|
||||
response = self.post_with_bearer_token(self.OAUTH2_BASE_TESTING_URL, token=self.dot_refresh_token.token)
|
||||
self.check_error_codes(
|
||||
response,
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
@@ -217,8 +193,8 @@ class OAuth2AllowInActiveUsersTests(TestCase):
|
||||
|
||||
def test_post_form_with_expired_access_token_failing_auth(self):
|
||||
"""Ensure POSTing with expired access token fails with a 'token_expired' error"""
|
||||
self.access_token.expires = now() - timedelta(seconds=10) # 10 seconds late
|
||||
self.access_token.save()
|
||||
self.dot_access_token.expires = now() - timedelta(seconds=10) # 10 seconds late
|
||||
self.dot_access_token.save()
|
||||
response = self.post_with_bearer_token(self.OAUTH2_BASE_TESTING_URL)
|
||||
self.check_error_codes(
|
||||
response,
|
||||
|
||||
Reference in New Issue
Block a user