class JwtHasContentOrgFilterForRequestedCourseTests(TestCase): """ Tests for JwtHasContentOrgFilterForRequestedCourse permission class. """ def setUp(self): super().setUp() self.user = UserFactory() @ddt.data( (JwtAuthentication(), ['content_org:edX'], { 'course_id': 'course-v1:edX+DemoX+Demo_Course' }, True), (JwtAuthentication(), ['content_org:TestX'], { 'course_id': 'course-v1:edX+DemoX+Demo_Course' }, False), (JwtAuthentication(), ['test:TestX'], { 'course_id': 'course-v1:edX+DemoX+Demo_Course' }, False), (JwtAuthentication(), [], { 'course_id': 'course-v1:edX+DemoX+Demo_Course' }, False), (None, [], { 'course_id': 'course-v1:edX+DemoX+Demo_Course' }, False), ) @ddt.unpack def test_has_permission(self, authentication_class, jwt_filters, view_kwargs, expected_result): request = RequestFactory().get('/') request.successful_authenticator = authentication_class request.auth = generate_jwt(self.user, filters=jwt_filters) view = Mock(kwargs=view_kwargs) self.assertEqual( permissions.JwtHasContentOrgFilterForRequestedCourse(). has_permission(request, view), expected_result, )
def test_authenticate_credentials_user_attributes_new_mergeable_attributes( self): """ Test whether the user model is being assigned all custom fields from the payload. """ username = '******' email = '*****@*****.**' new_tags = {'browser': 'Chrome'} user = factories.UserFactory(email=email, username=username, is_staff=False) self.assertEqual(user.email, email) self.assertFalse(user.is_staff) payload = { 'username': username, 'email': email, 'is_staff': True, 'tags': new_tags } # Patch get_or_create so that our tags attribute is on the user object with mock.patch( 'edx_rest_framework_extensions.auth.jwt.authentication.get_user_model' ) as mock_get_user_model: mock_get_user_model().objects.get_or_create.return_value = (user, False) user = JwtAuthentication().authenticate_credentials(payload) self.assertEqual(user.tags, new_tags) self.assertEqual(user.email, email) self.assertTrue(user.is_staff)
def test_authenticate_with_incorrect_jwt_authorization(self): """ With JWT header it continues and validates the credentials and throws error. """ auth_header = '{token_name} {token}'.format(token_name='JWT', token='wrongvalue') request = RequestFactory().get('/', HTTP_AUTHORIZATION=auth_header) with self.assertRaises(AuthenticationFailed): JwtAuthentication().authenticate(request)
def test_authenticate_credentials_user_creation(self, is_staff): """ Test whether the user model is being created and assigned fields from the payload. """ payload = self.get_jwt_payload(administrator=is_staff) user = JwtAuthentication().authenticate_credentials(payload) self.assertEqual(user.username, payload['preferred_username']) self.assertEqual(user.email, payload['email']) self.assertEqual(user.is_staff, is_staff)
def test_authenticate_with_correct_jwt_authorization(self): """ With JWT header it continues and validates the credentials and throws error. Note: CSRF protection should be skipped for this case, with no PermissionDenied. """ jwt_token = self._get_test_jwt_token() request = RequestFactory().get('/', HTTP_AUTHORIZATION=jwt_token) JwtAuthentication().authenticate(request)
def test_authenticate_credentials_user_retrieval_failed(self): """ Verify exceptions raised during user retrieval are properly logged. """ with mock.patch.object(User.objects, 'get_or_create', side_effect=ValueError): with mock.patch.object(Logger, 'exception') as logger: self.assertRaises( AuthenticationFailed, JwtAuthentication().authenticate_credentials, {'username': '******', 'email': '*****@*****.**'} ) logger.assert_called_with('User retrieval failed.')
def test_authenticate(self): """ Verify exceptions raised during authentication are properly logged. """ request = RequestFactory().get('/') with mock.patch.object(JSONWebTokenAuthentication, 'authenticate', side_effect=Exception): with mock.patch.object(Logger, 'debug') as logger: self.assertRaises( Exception, JwtAuthentication().authenticate, request ) self.assertTrue(logger.called)
class JwtHasScopeTests(TestCase): """ Tests for JwtHasScope permission class. """ def setUp(self): super().setUp() self.user = UserFactory() @ddt.data( (JwtAuthentication(), ('test:read', ), ('test:read', ), True), # match (JwtAuthentication(), ('test:write'), ('test:read', ), False), # mismatch (JwtAuthentication(), ('test:read'), (), False), # empty on API (JwtAuthentication(), ('test:read'), None, False), # missing on API (JwtAuthentication(), (), ('test:read', ), False), # missing on jwt (JwtAuthentication(), (), None, False), # missing on both (None, (), ('test:read'), False), # no auth ) @ddt.unpack def test_has_permission(self, authentication_class, jwt_scopes, required_scopes, expected_result): request = RequestFactory().get('/') request.successful_authenticator = authentication_class request.auth = generate_jwt(self.user, scopes=jwt_scopes) if required_scopes is None: view = APIView() else: view = Mock(required_scopes=required_scopes) self.assertEqual( permissions.JwtHasScope().has_permission(request, view), expected_result)
def test_authenticate_credentials_user_attributes_custom_attributes(self): """ Test whether the user model is being assigned all custom fields from the payload. """ username = '******' old_email = '*****@*****.**' new_email = '*****@*****.**' user = factories.UserFactory(email=old_email, username=username, is_staff=False) self.assertEqual(user.email, old_email) self.assertFalse(user.is_staff) payload = {'username': username, 'email': new_email, 'is_staff': True} user = JwtAuthentication().authenticate_credentials(payload) self.assertEqual(user.email, new_email) self.assertTrue(user.is_staff)
def test_authenticate_credentials_user_updates_default_attributes(self): """ Test whether the user model is being assigned default fields from the payload. """ username = '******' old_email = '*****@*****.**' new_email = '*****@*****.**' user = factories.UserFactory(email=old_email, username=username, is_staff=False) self.assertEqual(user.email, old_email) self.assertFalse(user.is_staff) payload = {'username': username, 'email': new_email, 'is_staff': True} user = JwtAuthentication().authenticate_credentials(payload) self.assertEqual(user.email, new_email) self.assertFalse(user.is_staff)
def test_authenticate_csrf_protected(self, mock_set_custom_attribute): """ Verify authenticate exception for CSRF protected cases. """ request = RequestFactory().post('/') request.META[USE_JWT_COOKIE_HEADER] = 'true' with mock.patch.object(JSONWebTokenAuthentication, 'authenticate', return_value=('mock-user', "mock-auth")): with self.assertRaises(PermissionDenied) as context_manager: JwtAuthentication().authenticate(request) assert context_manager.exception.detail.startswith('CSRF Failed') mock_set_custom_attribute.assert_called_once_with( 'jwt_auth_failed', "Exception:PermissionDenied('CSRF Failed: CSRF cookie not set.')", )
def test_authenticate_credentials_user_attributes_merge_attributes(self): """ Test whether the user model is being assigned all custom fields from the payload. """ username = '******' email = '*****@*****.**' old_tags = {'country': 'USA', 'browser': 'Firefox'} new_tags = {'browser': 'Chrome', 'new_attr': 'here!'} new_fun_attr = {'shiny': 'object'} expected_tags = { 'country': 'USA', 'browser': 'Chrome', 'new_attr': 'here!' } old_fruit = {'fruit': 'apple'} user = factories.UserFactory(email=email, username=username, is_staff=False) setattr(user, 'tags', old_tags) setattr(user, 'fruit', old_fruit) self.assertEqual(user.email, email) self.assertFalse(user.is_staff) self.assertEqual(user.tags, old_tags) self.assertEqual(user.fruit, old_fruit) payload = { 'username': username, 'email': email, 'is_staff': True, 'tags': new_tags, 'fun_attr': new_fun_attr } # Patch get_or_create so that our tags attribute is on the user object with mock.patch( 'edx_rest_framework_extensions.auth.jwt.authentication.get_user_model' ) as mock_get_user_model: mock_get_user_model().objects.get_or_create.return_value = (user, False) user = JwtAuthentication().authenticate_credentials(payload) self.assertEqual(user.tags, expected_tags) self.assertEqual(user.email, email) self.assertTrue(user.is_staff) self.assertEqual(user.fun_attr, new_fun_attr) self.assertEqual(user.fruit, old_fruit)
def test_authenticate_csrf_protected(self): """ Verify authenticate exception for CSRF protected cases. """ request = RequestFactory().post('/') request.META[USE_JWT_COOKIE_HEADER] = 'true' with mock.patch.object( JSONWebTokenAuthentication, 'authenticate', return_value=('mock-user', "mock-auth")): # noqa E501 line too long with mock.patch.object(Logger, 'debug') as debug_logger: with self.assertRaises(PermissionDenied) as context_manager: JwtAuthentication().authenticate(request) self.assertEqual(context_manager.exception.detail, 'CSRF Failed: CSRF cookie not set.') self.assertTrue(debug_logger.called)
def get_authenticators(self): # pragma: no cover """ Allow users authenticated via OAuth2 or normal session authentication. """ try: from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser from openedx.core.lib.api.authentication import SessionAuthenticationAllowInactiveUser except ImportError: from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser try: from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication except ImportError: from edx_rest_framework_extensions.authentication import JwtAuthentication return [ JwtAuthentication(), OAuth2AuthenticationAllowInactiveUser(), SessionAuthenticationAllowInactiveUser(), ]
def test_authenticate_csrf_exempt(self, enable_rollout, use_jwt_cookies, mocked_return_value_user_and_auth): """ Verify authenticate success for cases that are CSRF exempt. """ request = RequestFactory().post('/') if use_jwt_cookies: request.META[USE_JWT_COOKIE_HEADER] = 'true' with mock.patch.object(JSONWebTokenAuthentication, 'authenticate', return_value=mocked_return_value_user_and_auth ): # noqa E501 line too long with override_settings( EDX_DRF_EXTENSIONS={ ENABLE_ANONYMOUS_ACCESS_ROLLOUT: enable_rollout }): actual_user_and_auth = JwtAuthentication().authenticate( request) self.assertEqual(mocked_return_value_user_and_auth, actual_user_and_auth)
def test_authenticate_csrf_protected(self, enable_rollout, use_jwt_cookies, mocked_return_value_user_and_auth): """ Verify authenticate exception for CSRF protected cases. """ request = RequestFactory().post('/') if use_jwt_cookies: request.META[USE_JWT_COOKIE_HEADER] = 'true' with mock.patch.object(JSONWebTokenAuthentication, 'authenticate', return_value=mocked_return_value_user_and_auth ): # noqa E501 line too long with override_settings( EDX_DRF_EXTENSIONS={ ENABLE_ANONYMOUS_ACCESS_ROLLOUT: enable_rollout }): with mock.patch.object(Logger, 'debug') as debug_logger: with self.assertRaises( PermissionDenied) as context_manager: JwtAuthentication().authenticate(request) self.assertEqual(context_manager.exception.detail, 'CSRF Failed: CSRF cookie not set.') self.assertTrue(debug_logger.called)
def test_authenticate_credentials_no_usernames(self): """ Verify an AuthenticationFailed exception is raised if the payload contains no username claim. """ with self.assertRaises(AuthenticationFailed): JwtAuthentication().authenticate_credentials( {'email': '*****@*****.**'})
def test_authenticate_with_bearer_token(self): """ Returns a None for bearer header request. """ auth_header = '{token_name} {token}'.format(token_name='Bearer', token='abc123') request = RequestFactory().get('/', HTTP_AUTHORIZATION=auth_header) self.assertIsNone(JwtAuthentication().authenticate(request))