From f90bf5964af1ab8a66dc7ceb614e53db76bb6b20 Mon Sep 17 00:00:00 2001 From: wajeeha-khalid Date: Wed, 29 Jun 2016 07:00:31 +0000 Subject: [PATCH] MA-2552: create revoke_token endpoint for oauth --- .../oauth_dispatch/tests/test_views.py | 104 ++++++++++++++++++ lms/djangoapps/oauth_dispatch/urls.py | 1 + lms/djangoapps/oauth_dispatch/views.py | 7 ++ 3 files changed, 112 insertions(+) diff --git a/lms/djangoapps/oauth_dispatch/tests/test_views.py b/lms/djangoapps/oauth_dispatch/tests/test_views.py index 06d84eaece..835f1db4d3 100644 --- a/lms/djangoapps/oauth_dispatch/tests/test_views.py +++ b/lms/djangoapps/oauth_dispatch/tests/test_views.py @@ -318,3 +318,107 @@ class TestViewDispatch(TestCase): def test_get_view_for_no_backend(self): view_object = views.AccessTokenView() self.assertRaises(KeyError, view_object.get_view_for_backend, None) + + +class TestRevokeTokenView(_DispatchingViewTestCase): # pylint: disable=abstract-method + """ + Test class for RevokeTokenView + """ + + login_with_access_token_url = reverse("login_with_access_token") + revoke_token_url = reverse('revoke_token') + access_token_url = reverse('access_token') + + def setUp(self): + super(TestRevokeTokenView, self).setUp() + response = self.client.post(self.access_token_url, self.access_token_post_body_with_password()) + access_token_data = json.loads(response.content) + self.access_token = access_token_data['access_token'] + self.refresh_token = access_token_data['refresh_token'] + + def access_token_post_body_with_password(self): + """ + Returns a dictionary to be used as the body of the access_token + POST request with 'password' grant + """ + return { + 'client_id': self.dot_app.client_id, + 'grant_type': 'password', + 'username': self.user.username, + 'password': 'test', + } + + def access_token_post_body_with_refresh_token(self, refresh_token): + """ + Returns a dictionary to be used as the body of the access_token + POST request with 'refresh_token' grant + """ + return { + 'client_id': self.dot_app.client_id, + 'grant_type': 'refresh_token', + 'refresh_token': refresh_token, + } + + def revoke_token_post_body(self, token): + """ + Returns a dictionary to be used as the body of the revoke_token POST request + """ + return { + 'client_id': self.dot_app.client_id, + 'token': token, + } + + def login_with_access_token(self): + """ + Login with access token and return response + """ + return self.client.post( + self.login_with_access_token_url, + HTTP_AUTHORIZATION="Bearer {0}".format(self.access_token) + ) + + def _assert_access_token_is_valid(self): + """ + Asserts that oauth assigned access_token is valid and usable + """ + self.assertEqual(self.login_with_access_token().status_code, 204) + + def _assert_access_token_invalidated(self): + """ + Asserts that oauth assigned access_token is not valid + """ + self.assertEqual(self.login_with_access_token().status_code, 401) + + def _assert_refresh_token_invalidated(self): + """ + Asserts that oauth assigned refresh_token is not valid + """ + response = self.client.post( + self.access_token_url, + self.access_token_post_body_with_refresh_token(self.refresh_token) + ) + self.assertEqual(response.status_code, 401) + + def verify_revoke_token(self, token): + """ + Verifies access of token before and after revoking + """ + self._assert_access_token_is_valid() + + response = self.client.post(self.revoke_token_url, self.revoke_token_post_body(token)) + self.assertEqual(response.status_code, 200) + + self._assert_access_token_invalidated() + self._assert_refresh_token_invalidated() + + def test_revoke_refresh_token_dot(self): + """ + Tests invalidation/revoke of user tokens against refresh token for django-oauth-toolkit + """ + self.verify_revoke_token(self.refresh_token) + + def test_revoke_access_token_dot(self): + """ + Tests invalidation/revoke of user access token for django-oauth-toolkit + """ + self.verify_revoke_token(self.access_token) diff --git a/lms/djangoapps/oauth_dispatch/urls.py b/lms/djangoapps/oauth_dispatch/urls.py index a42bed408b..bbf30d477f 100644 --- a/lms/djangoapps/oauth_dispatch/urls.py +++ b/lms/djangoapps/oauth_dispatch/urls.py @@ -13,6 +13,7 @@ urlpatterns = patterns( '', url(r'^authorize/?$', csrf_exempt(views.AuthorizationView.as_view()), name='authorize'), url(r'^access_token/?$', csrf_exempt(views.AccessTokenView.as_view()), name='access_token'), + url(r'^revoke_token/?$', csrf_exempt(views.RevokeTokenView.as_view()), name="revoke_token"), ) if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'): diff --git a/lms/djangoapps/oauth_dispatch/views.py b/lms/djangoapps/oauth_dispatch/views.py index 64c7739554..240ca44e77 100644 --- a/lms/djangoapps/oauth_dispatch/views.py +++ b/lms/djangoapps/oauth_dispatch/views.py @@ -130,3 +130,10 @@ class AccessTokenExchangeView(_DispatchingView): """ dop_view = auth_exchange_views.DOPAccessTokenExchangeView dot_view = auth_exchange_views.DOTAccessTokenExchangeView + + +class RevokeTokenView(_DispatchingView): + """ + Dispatch to the RevokeTokenView of django-oauth-toolkit + """ + dot_view = dot_views.RevokeTokenView