def test_inactive_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): self.student.is_active = False self.student.save() resp = self._get_response(self.student, auth_type) self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_another_user_with_certs_shared_custom(self, auth_type, scopes_enforced): """ Returns 200 with cert list for OAuth, Session, and JWT auth. Returns 200 for jwt_restricted and user:me filter unset. """ self.student.profile.year_of_birth = 1977 self.student.profile.save() UserPreferenceFactory.build( user=self.student, key='account_privacy', value='custom', ).save() UserPreferenceFactory.build( user=self.student, key='visibility.course_certificates', value='all_users', ).save() with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self.get_response(auth_type, requesting_user=self.other_student) self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 1)
def test_inactive_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): self.student.is_active = False self.student.save() resp = self._get_response(self.student, auth_type) self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_restricted_jwt_access_token(self, enforce_jwt_scopes_enabled, expiration_expected): """ Verify that when requesting a JWT token from a restricted Application within the DOT subsystem, that our claims is marked as already expired (i.e. expiry set to Jan 1, 1970) """ with ENFORCE_JWT_SCOPES.override(enforce_jwt_scopes_enabled): response = self._post_request(self.user, self.restricted_dot_app, token_type='jwt') self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode('utf-8')) self.assertIn('expires_in', data) self.assertEqual(data['expires_in'] < 0, expiration_expected) self.assertEqual(data['token_type'], 'JWT') self.assert_valid_jwt_access_token( data['access_token'], self.user, data['scope'].split(' '), should_be_expired=expiration_expected, should_be_asymmetric_key=enforce_jwt_scopes_enabled, should_be_restricted=True, )
def should_expire_access_token(cls, application): set_token_expired = not ENFORCE_JWT_SCOPES.is_enabled() jwt_not_requested = get_request_or_stub().POST.get('token_type', '').lower() != 'jwt' restricted_application = cls.objects.filter( application=application).exists() return restricted_application and (jwt_not_requested or set_token_expired)
def test_jwt_on_behalf_of_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, include_me_filter=True) resp = self.get_response(AuthType.jwt, token=jwt_token) self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_dot_create_jwt_for_token(self, scopes_enforced, client_restricted): with ENFORCE_JWT_SCOPES.override(scopes_enforced): jwt_token = self._create_jwt_for_token( DOTAdapter(), use_asymmetric_key=None, client_restricted=client_restricted, ) self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=scopes_enforced and client_restricted)
def test_dot_create_jwt_for_token(self, scopes_enforced, client_restricted): with ENFORCE_JWT_SCOPES.override(scopes_enforced): jwt_token = self._create_jwt_for_token( DOTAdapter(), use_asymmetric_key=None, client_restricted=client_restricted, ) self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=scopes_enforced and client_restricted)
def test_another_user(self, auth_type, scopes_enforced, mock_log): """ Returns 200 with empty list for OAuth, Session, and JWT auth. Returns 200 for jwt_restricted and user:me filter unset. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self.get_response(auth_type, requesting_user=self.other_student) self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 0)
def test_another_user(self, auth_type, scopes_enforced, mock_log): """ Returns 200 with empty list for OAuth, Session, and JWT auth. Returns 200 for jwt_restricted and user:me filter unset. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self.get_response(auth_type, requesting_user=self.other_student) self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 0)
def test_jwt_no_filter(self, auth_type, scopes_enforced, mock_log): """ Returns 403 when scopes are enforced with JwtHasContentOrgFilterForRequestedCourse. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, include_org_filter=False) resp = self._get_response(self.student, AuthType.jwt, token=jwt_token) is_enforced = scopes_enforced and auth_type == AuthType.jwt_restricted self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN if is_enforced else status.HTTP_200_OK) if is_enforced: self._assert_in_log("JwtHasContentOrgFilterForRequestedCourse", mock_log.warning)
def test_jwt_no_scopes(self, auth_type, scopes_enforced, mock_log): """ Returns 403 when scopes are enforced with JwtHasScope. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, scopes=[]) resp = self._get_response(self.student, AuthType.jwt, token=jwt_token) is_enforced = scopes_enforced and auth_type == AuthType.jwt_restricted self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN if is_enforced else status.HTTP_200_OK) if is_enforced: self._assert_in_log("JwtHasScope", mock_log.warning)
def test_jwt_no_filter(self, auth_type, scopes_enforced, mock_log): """ Returns 403 when scopes are enforced with JwtHasContentOrgFilterForRequestedCourse. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, include_org_filter=False) resp = self.get_response(AuthType.jwt, token=jwt_token) is_enforced = scopes_enforced and auth_type == AuthType.jwt_restricted self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN if is_enforced else status.HTTP_200_OK) if is_enforced: self._assert_in_log("JwtHasContentOrgFilterForRequestedCourse", mock_log.warning)
def test_jwt_on_behalf_of_other_user(self, auth_type, scopes_enforced, mock_log): """ Returns 403 when scopes are enforced with JwtHasUserFilterForRequestedUser. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.other_student, auth_type, include_me_filter=True) resp = self.get_response(AuthType.jwt, token=jwt_token) if scopes_enforced and auth_type == AuthType.jwt_restricted: self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN) self._assert_in_log("JwtHasUserFilterForRequestedUser", mock_log.warning) else: self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 0)
def test_jwt_on_behalf_of_other_user(self, auth_type, scopes_enforced, mock_log): """ Returns 403 when scopes are enforced with JwtHasUserFilterForRequestedUser. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.other_student, auth_type, include_me_filter=True) resp = self.get_response(AuthType.jwt, token=jwt_token) if scopes_enforced and auth_type == AuthType.jwt_restricted: self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN) self._assert_in_log("JwtHasUserFilterForRequestedUser", mock_log.warning) else: self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 0)
def test_jwt_on_behalf_of_user(self, auth_type, scopes_enforced): """ We have to override this super method due to this API being restricted to staff users only. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, include_me_filter=True) # include_me_filter=True means a JWT filter will require the username # of the requesting user to be in the requested URL url = self.get_url(self.student) + '?username={}'.format(self.student.username) resp = self.get_response(AuthType.jwt, token=jwt_token, url=url) assert status.HTTP_200_OK == resp.status_code
def test_another_user(self, auth_type, scopes_enforced, mock_log): """ Returns 403 for OAuth and Session auth with IsUserInUrl. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self._get_response(self.student_no_cert, auth_type) # Restricted JWT tokens without the user:me filter have access to other users expected_jwt_access_granted = scopes_enforced and auth_type == AuthType.jwt_restricted self.assertEqual( resp.status_code, status.HTTP_200_OK if expected_jwt_access_granted else status.HTTP_403_FORBIDDEN, ) if not expected_jwt_access_granted: self._assert_in_log("IsUserInUrl", mock_log.info)
def test_another_user(self, auth_type, scopes_enforced, mock_log): """ Returns 403 for OAuth and Session auth with IsUserInUrl. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self._get_response(self.student_no_cert, auth_type) # Restricted JWT tokens without the user:me filter have access to other users expected_jwt_access_granted = scopes_enforced and auth_type == AuthType.jwt_restricted self.assertEqual( resp.status_code, status.HTTP_200_OK if expected_jwt_access_granted else status.HTTP_403_FORBIDDEN, ) if not expected_jwt_access_granted: self._assert_in_log("IsUserInUrl", mock_log.info)
def test_jwt_no_scopes(self, auth_type, scopes_enforced, mock_log): """ Returns 403 when scopes are enforced with JwtHasScope. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, scopes=[]) resp = self.get_response(AuthType.jwt, token=jwt_token) is_enforced = scopes_enforced and auth_type == AuthType.jwt_restricted self.assertEqual( resp.status_code, status.HTTP_403_FORBIDDEN if is_enforced else status.HTTP_200_OK) if is_enforced: self._assert_in_log("JwtHasScope", mock_log.warning)
def _get_use_asymmetric_key_value(is_restricted, use_asymmetric_key): """ Returns the value to use for use_asymmetric_key. """ # TODO: (ARCH-162) # If JWT scope enforcement is enabled, we need to sign tokens # given to restricted applications with a key that # other IDAs do not have access to. This prevents restricted # applications from getting access to API endpoints available # on other IDAs which have not yet been protected with the # scope-related DRF permission classes. Once all endpoints have # been protected, we can enable all IDAs to use the same new # (asymmetric) key. if use_asymmetric_key is None: use_asymmetric_key = ENFORCE_JWT_SCOPES.is_enabled() and is_restricted return use_asymmetric_key
def test_jwt_on_behalf_of_user(self, auth_type, scopes_enforced): """ We have to override this super method due to this API being restricted to staff users only. """ with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, include_me_filter=True) # include_me_filter=True means a JWT filter will require the username # of the requesting user to be in the requested URL url = self.get_url(self.student) + '?username={}'.format( self.student.username) resp = self.get_response(AuthType.jwt, token=jwt_token, url=url) assert status.HTTP_200_OK == resp.status_code
def _get_use_asymmetric_key_value(is_restricted, use_asymmetric_key): """ Returns the value to use for use_asymmetric_key. """ # TODO: (ARCH-162) # If JWT scope enforcement is enabled, we need to sign tokens # given to restricted applications with a key that # other IDAs do not have access to. This prevents restricted # applications from getting access to API endpoints available # on other IDAs which have not yet been protected with the # scope-related DRF permission classes. Once all endpoints have # been protected, we can enable all IDAs to use the same new # (asymmetric) key. if use_asymmetric_key is None: use_asymmetric_key = ENFORCE_JWT_SCOPES.is_enabled() and is_restricted return use_asymmetric_key
def test_restricted_non_jwt_access_token_fields(self, enforce_jwt_scopes_enabled): with ENFORCE_JWT_SCOPES.override(enforce_jwt_scopes_enabled): response = self._post_request(self.user, self.restricted_dot_app) self.assertEqual(response.status_code, 200) data = json.loads(response.content) self.assertIn('access_token', data) self.assertIn('expires_in', data) self.assertIn('scope', data) self.assertIn('token_type', data) # Verify token expiration. self.assertEqual(data['expires_in'] < 0, True) access_token = dot_models.AccessToken.objects.get(token=data['access_token']) self.assertEqual( models.RestrictedApplication.verify_access_token_as_expired(access_token), True )
def test_restricted_non_jwt_access_token_fields(self, enforce_jwt_scopes_enabled): with ENFORCE_JWT_SCOPES.override(enforce_jwt_scopes_enabled): response = self._post_request(self.user, self.restricted_dot_app) self.assertEqual(response.status_code, 200) data = json.loads(response.content) self.assertIn('access_token', data) self.assertIn('expires_in', data) self.assertIn('scope', data) self.assertIn('token_type', data) # Verify token expiration. self.assertEqual(data['expires_in'] < 0, True) access_token = dot_models.AccessToken.objects.get(token=data['access_token']) self.assertEqual( models.RestrictedApplication.verify_access_token_as_expired(access_token), True )
def test_another_user_with_certs_shared_public(self, auth_type, scopes_enforced): """ Returns 200 with cert list for OAuth, Session, and JWT auth. Returns 200 for jwt_restricted and user:me filter unset. """ self.student.profile.year_of_birth = 1977 self.student.profile.save() UserPreferenceFactory.build( user=self.student, key='account_privacy', value='all_users', ).save() with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self.get_response(auth_type, requesting_user=self.other_student) self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 1)
def test_restricted_jwt_access_token(self, enforce_jwt_scopes_enabled, expiration_expected): """ Verify that when requesting a JWT token from a restricted Application within the DOT subsystem, that our claims is marked as already expired (i.e. expiry set to Jan 1, 1970) """ with ENFORCE_JWT_SCOPES.override(enforce_jwt_scopes_enabled): response = self._post_request(self.user, self.restricted_dot_app, token_type='jwt') self.assertEqual(response.status_code, 200) data = json.loads(response.content) self.assertIn('expires_in', data) self.assertEqual(data['expires_in'] < 0, expiration_expected) self.assertEqual(data['token_type'], 'JWT') self.assert_valid_jwt_access_token( data['access_token'], self.user, data['scope'].split(' '), should_be_expired=expiration_expected, should_be_asymmetric_key=enforce_jwt_scopes_enabled, should_be_restricted=True, )
def test_restricted_jwt_access_token(self, enforce_jwt_scopes_enabled, expiration_expected): """ Verify that when requesting a JWT token from a restricted Application within the DOT subsystem, that our claims is marked as already expired (i.e. expiry set to Jan 1, 1970) """ with ENFORCE_JWT_SCOPES.override(enforce_jwt_scopes_enabled): public_jwk_set, private_jwk = self._generate_key_pair() jwt_auth_settings = settings.JWT_AUTH jwt_auth_settings.update({ 'JWT_PRIVATE_SIGNING_JWK': private_jwk, 'JWT_PUBLIC_SIGNING_JWK_SET': public_jwk_set, }) with override_settings(JWT_AUTH=jwt_auth_settings): response = self._post_request(self.user, self.restricted_dot_app, token_type='jwt') self.assertEqual(response.status_code, 200) data = json.loads(response.content) self.assertIn('expires_in', data) self.assertEqual(data['expires_in'] < 0, expiration_expected) self.assertEqual(data['token_type'], 'JWT') self.assert_valid_jwt_access_token( data['access_token'], self.user, data['scope'].split(' '), should_be_expired=expiration_expected, should_be_asymmetric_key=enforce_jwt_scopes_enabled, should_be_restricted=True, )
def test_staff_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self._get_response(self.staff_user, auth_type) self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_staff_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self._get_response(self.staff_user, auth_type) self.assertEqual(resp.status_code, status.HTTP_200_OK)
def should_expire_access_token(cls, application): set_token_expired = not ENFORCE_JWT_SCOPES.is_enabled() jwt_not_requested = get_request_or_stub().POST.get('token_type', '').lower() != 'jwt' restricted_application = cls.objects.filter(application=application).exists() return restricted_application and (jwt_not_requested or set_token_expired)
def test_staff_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self.get_response(auth_type, requesting_user=self.global_staff) self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assert_success_response_for_student(resp)
def test_jwt_on_behalf_of_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): jwt_token = self._create_jwt_token(self.student, auth_type, include_me_filter=True) resp = self.get_response(AuthType.jwt, token=jwt_token) self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_staff_user(self, auth_type, scopes_enforced): with ENFORCE_JWT_SCOPES.override(active=scopes_enforced): resp = self.get_response(auth_type, requesting_user=self.global_staff) self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assert_success_response_for_student(resp)