def __test__extract_security_info(self): """""" date_folder_cls = model_fixture.models.get('date_folder_cls') hacs_query = date_folder_cls.objects.all() # No user is set yet! so security guard is disabled and obiously user is none self.assertEqual((False, None, date_folder_cls.__hacs_base_content_type__), hacs_query._extract_security_info()) attach_system_user() # System is user is set, so security guard is disabled self.assertEqual((False, SYSTEM_USER, date_folder_cls.__hacs_base_content_type__), hacs_query._extract_security_info()) release_system_user() # Test With authenticated user HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.memberuser # Test with member user self.assertEqual((True, model_fixture.memberuser, date_folder_cls.__hacs_base_content_type__), hacs_query._extract_security_info()) hacs_query = get_group_model().objects.all() self.assertEqual((True, model_fixture.memberuser, get_group_model().__hacs_base_content_type__), hacs_query._extract_security_info()) hacs_query = get_workflow_model().objects.all() self.assertEqual((True, model_fixture.memberuser, get_workflow_model().__hacs_base_content_type__), hacs_query._extract_security_info())
def init_data(self): """ :return: """ try: attach_system_user() setupModels(*self.models.values()) # Initialized Hacs ContentType self.init_hacs_content_types() # Initialized Hacs ContentType Data self.init_hacs_content_data() finally: release_system_user()
def tear_down(self): """ :return: """ try: attach_system_user() for model in self.models.values(): try: ct = ContentType.objects.get_for_model(model) try: HacsContentType.objects.get(content_type=ct).delete() except HacsContentType.DoesNotExist: pass ct.delete() except model.DoesNotExist: pass tearDownModels(*self.models.values()) finally: release_system_user()
def update(self, **kwargs): """ :param kwargs: :return: """ # Copied from parent assert self.query.can_filter(), "Cannot update a query once a slice has been taken." active_security_guard, current_user, base_type = self._extract_security_info() if active_security_guard: # Yep! security guard applicable self._add_security_guard(base_type, current_user, 'object.update') if self._queryset_update_allowed(base_type, kwargs): # We are doing normal update return super(HacsBaseQuerySet, self).update(**kwargs) # Special Kind of Update delete_query = self._clone() count = 0 # @TODO: should save faster, use system user? attach_system_user() for obj in delete_query: for key in kwargs.keys(): if hasattr(obj, key): setattr(obj, key, kwargs[key]) obj.save(update_fields=kwargs.keys()) count += 1 release_system_user() return count
def test_check(self): """ :return: """ # enable us to capture any warns happen logging.captureWarnings(False) security_manager = SecurityManager() with warnings.catch_warnings(record=True) as warns: # http://stackoverflow.com/questions/5644836/in-python-how-does-one-catch-warnings-as-if-they-were-exceptions warnings.simplefilter("always") security_manager._check('hacs.ManagePortal') new_warns = filter(lambda x: issubclass(x.category, UserWarning), warns) # Should be two warnings. one. get_ac_user() two. _check() # User is not set yet! (usually should done by `AccessControlMiddleware`) # This assertion is offed for now! because of unknown error or bug, it works while running single # test suite # self.assertEqual(2, len(tuple(new_warns))) with warnings.catch_warnings(record=True) as warns: # http://stackoverflow.com/questions/5644836/in-python-how-does-one-catch-warnings-as-if-they-were-exceptions # Test with system user attach_system_user() warnings.simplefilter("always") # should have permission without any complain because of system user self.assertTrue(security_manager._check('hacs.ManagePortal')) new_warns = filter(lambda x: issubclass(x.category, UserWarning), warns) # Should not any warnings # System User is set! (usually should done by `AccessControlMiddleware`) self.assertEqual(0, len(tuple(new_warns))) # Let's clean up system user release_system_user() # Test If Release local is working try: HACS_ACCESS_CONTROL_LOCAL.current_user except AttributeError: pass else: AssertionError( "Code should not come here! as should raise attribute error after release local" ) superuser = get_user_model().objects.get_by_natural_key( '*****@*****.**') memberuser = get_user_model().objects.get_by_natural_key( '*****@*****.**') HACS_ACCESS_CONTROL_LOCAL.current_user = superuser # Test superuser has permissions self.assertTrue(security_manager._check('hacs.ManagePortal')) HACS_ACCESS_CONTROL_LOCAL.current_user = memberuser # Test member user has no permissions of course self.assertFalse(security_manager._check('hacs.ManagePortal')) # Test with multiple permissions # Test member user should have permission now self.assertTrue( security_manager._check(( 'hacs.ManagePortal', 'hacs.AuthenticatedView', ))) # Test with object and local roles HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.contributoruser news_item_1 = model_fixture.models.get( 'news_item_cls').objects.get_by_natural_key('news-one') news_item_2 = model_fixture.models.get('news_item_cls'). \ objects.get_by_natural_key('news-two-with-local-roles') # Contributor should not have Editor permission self.assertFalse( security_manager._check('hacs.ManageContent', news_item_1)) # As `news_item_2` has local roles for contributor, so should have editor permission for this object self.assertTrue( security_manager._check('hacs.ManageContent', news_item_2))
def test_check(self): """ :return: """ # enable us to capture any warns happen logging.captureWarnings(False) security_manager = SecurityManager() with warnings.catch_warnings(record=True) as warns: # http://stackoverflow.com/questions/5644836/in-python-how-does-one-catch-warnings-as-if-they-were-exceptions warnings.simplefilter("always") security_manager._check('hacs.ManagePortal') new_warns = filter(lambda x: issubclass(x.category, UserWarning), warns) # Should be two warnings. one. get_ac_user() two. _check() # User is not set yet! (usually should done by `AccessControlMiddleware`) # This assertion is offed for now! because of unknown error or bug, it works while running single # test suite # self.assertEqual(2, len(tuple(new_warns))) with warnings.catch_warnings(record=True) as warns: # http://stackoverflow.com/questions/5644836/in-python-how-does-one-catch-warnings-as-if-they-were-exceptions # Test with system user attach_system_user() warnings.simplefilter("always") # should have permission without any complain because of system user self.assertTrue(security_manager._check('hacs.ManagePortal')) new_warns = filter(lambda x: issubclass(x.category, UserWarning), warns) # Should not any warnings # System User is set! (usually should done by `AccessControlMiddleware`) self.assertEqual(0, len(tuple(new_warns))) # Let's clean up system user release_system_user() # Test If Release local is working try: HACS_ACCESS_CONTROL_LOCAL.current_user except AttributeError: pass else: AssertionError("Code should not come here! as should raise attribute error after release local") superuser = get_user_model().objects.get_by_natural_key('*****@*****.**') memberuser = get_user_model().objects.get_by_natural_key('*****@*****.**') HACS_ACCESS_CONTROL_LOCAL.current_user = superuser # Test superuser has permissions self.assertTrue(security_manager._check('hacs.ManagePortal')) HACS_ACCESS_CONTROL_LOCAL.current_user = memberuser # Test member user has no permissions of course self.assertFalse(security_manager._check('hacs.ManagePortal')) # Test with multiple permissions # Test member user should have permission now self.assertTrue(security_manager._check(('hacs.ManagePortal', 'hacs.AuthenticatedView',))) # Test with object and local roles HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.contributoruser news_item_1 = model_fixture.models.get('news_item_cls').objects.get_by_natural_key('news-one') news_item_2 = model_fixture.models.get('news_item_cls'). \ objects.get_by_natural_key('news-two-with-local-roles') # Contributor should not have Editor permission self.assertFalse(security_manager._check('hacs.ManageContent', news_item_1)) # As `news_item_2` has local roles for contributor, so should have editor permission for this object self.assertTrue(security_manager._check('hacs.ManageContent', news_item_2))
def test_dict_query(self): """ :return: """ date_folder_cls = model_fixture.models.get('date_folder_cls') # All normal tries results = date_folder_cls.objects.filter(permissions_actions_map__has_key="object.view") self.assertEqual(1, results.count()) results = date_folder_cls.objects.filter(permissions_actions_map__has_key="object.fake") self.assertEqual(0, results.count()) results = date_folder_cls.objects.filter(permissions_actions_map__has_any_keys=["object.fake", "object.delete"]) self.assertEqual(1, results.count()) results = date_folder_cls.objects.filter(permissions_actions_map__has_keys=["object.fake", "object.delete"]) self.assertEqual(0, results.count()) results = date_folder_cls.objects.filter(permissions_actions_map__has_keys=["object.view", "object.delete"]) self.assertEqual(1, results.count()) # Try with level 1 key path search _filter = { "permissions_actions_map__object.view__has_key": "hacs.ViewContent" } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) # Try with invalid path _filter = { "permissions_actions_map__object.fake__has_key": "hacs.ViewContent" } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count()) _filter = { "permissions_actions_map__object.view__contains": ["hacs.ViewContent"] } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "permissions_actions_map__object.view__contained_by": ["hacs.ViewContent", "hacs.Fake", "hacs.ManageUtilsContent"] } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "permissions_actions_map__object.view__contained_by": ["hacs.ManagePortal", "hacs.Fake", "hacs.ManageUtilsContent"] } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count()) _filter = { "permissions_actions_map__object.view__has_any_keys": ["hacs.ViewContent", "hacs.Fake", "hacs.ManageUtilsContent"] } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "permissions_actions_map__object.view__has_any_keys": ["hacs.ManagePortal", "hacs.Fake", "hacs.ManageUtilsContent"] } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count()) # Test with user _filter = { "permissions_actions_map__object.view__has_any_keys": model_fixture.memberuser.get_all_permissions() } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count()) _filter = { "permissions_actions_map__object.view__contained_by": list(model_fixture.memberuser.get_all_permissions()) } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count()) _filter = { "permissions_actions_map__object.view__has_any_keys": model_fixture.contributoruser.get_all_permissions() } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "permissions_actions_map__object.view__contained_by": list(model_fixture.contributoruser.get_all_permissions()) } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "permissions_actions_map__object.view__has_any_keys": model_fixture.editoruser.get_all_permissions() } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "permissions_actions_map__object.view__contained_by": list( model_fixture.editoruser.get_all_permissions()) } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) # Test With 3rd Level path search date_folder = date_folder_cls.objects.get(pk=1) date_folder.extra_info = { "hacs.action": { "level2": { "level3": date_folder.permissions_actions_map['object.view'] } } } attach_system_user() date_folder.save() release_system_user() _filter = { "extra_info__hacs.action__level2__level3__contained_by": list( model_fixture.editoruser.get_all_permissions()) } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "extra_info__hacs.action__level2__level3__has_any_keys": model_fixture.editoruser.get_all_permissions() } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(1, results.count()) _filter = { "extra_info__hacs.action__level2__level3__contained_by": list( model_fixture.memberuser.get_all_permissions()) } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count()) _filter = { "extra_info__object.view__level2__level3__contained_by": list( model_fixture.editoruser.get_all_permissions()) } results = date_folder_cls.objects.filter(**_filter) self.assertEqual(0, results.count())
def test_array_query(self): """ :return: """ workflows = get_workflow_model().objects.filter(permissions__has_any_keys=["hacs.ManageUtilsContent"]) # should have two entries as both workflows have same permissions self.assertEqual(2, workflows.count()) workflows = get_workflow_model().objects.filter(permissions__has_any_keys=["hacs.ManageUtilsContent", "fake_key"]) self.assertEqual(2, workflows.count()) workflows = get_workflow_model().objects.filter(permissions__has_any_keys=["hacs.ManageUtilsConte"]) self.assertEqual(0, workflows.count()) workflows = get_workflow_model().objects.filter(permissions__has_any_keys=["hacs.ManageUtilsConte", "fake_permission"]) self.assertEqual(0, workflows.count()) attach_system_user() workflow1 = get_workflow_model().objects.get(pk=1) workflow1.permissions = ["hacs.AuthenticatedView"] workflow1.save() release_system_user() workflows = get_workflow_model().objects.filter(permissions__has_any_keys=["hacs.ManageUtilsContent"]) self.assertEqual(1, workflows.count()) workflows = get_workflow_model().objects.filter(permissions__has_any_keys=["hacs.ManageUtilsContent", "hacs.AuthenticatedView"]) self.assertEqual(2, workflows.count()) # ** Let's with user permissions = model_fixture.memberuser.get_all_permissions() workflows = get_workflow_model().objects.filter(permissions__has_any_keys=permissions) # Should one because we allowed AuthenticatedView self.assertEqual(1, workflows.count()) workflows = get_workflow_model().objects.filter(permissions__contained_by=list(permissions)) self.assertEqual(1, workflows.count()) # Anonymous user should not have permissions permissions = ANONYMOUS_USER.get_all_permissions() workflows = get_workflow_model().objects.filter(permissions__has_any_keys=permissions) self.assertEqual(0, workflows.count()) # Let's changed permissions attach_system_user() workflow1 = get_workflow_model().objects.get(pk=1) workflow1.permissions = ["hacs.ManagePortal"] workflow1.save() release_system_user() permissions = model_fixture.memberuser.get_all_permissions() workflows = get_workflow_model().objects.filter(permissions__has_any_keys=permissions) # no permissions for member user self.assertEqual(0, workflows.count()) permissions = model_fixture.editoruser.get_all_permissions() workflows = get_workflow_model().objects.filter(permissions__has_any_keys=permissions) # no permission for editor user also self.assertEqual(0, workflows.count()) permissions = model_fixture.superuser.get_all_permissions() workflows = get_workflow_model().objects.filter(permissions__has_any_keys=permissions) # should have two workflow access self.assertEqual(2, workflows.count()) workflows = get_workflow_model().objects.filter(permissions__contained_by=list(permissions)) self.assertEqual(2, workflows.count())
def test__add_security_guard(self): """ :return: """ news_folder = model_fixture.models.get('news_folder_cls').objects.get(pk=1) date_folder_cls = model_fixture.models.get('date_folder_cls') hacs_query = date_folder_cls.objects.filter(created_by=model_fixture.superuser, created_on__year=2017).\ exclude(Q(slug='fake-slug') | ~Q(slug='2016-10-10')).filter(Q(recursive=True, parent_container_id=news_folder.pk) & Q(acquire_parent=True)) hacs_query._add_security_guard(date_folder_cls.__hacs_base_content_type__, model_fixture.contributoruser) sql_str = str(hacs_query.query) """ sql_str = 'SELECT "test_date_folder"."id", "test_date_folder"."uuid", "test_date_folder"."name", "test_date_folder"."slug", "test_date_folder"."created_on", "test_date_folder"."created_by_id", "test_date_folder"."modified_by_id", "test_date_folder"."modified_on", "test_date_folder"."state", "test_date_folder"."permissions_actions_map", "test_date_folder"."roles_actions_map", "test_date_folder"."local_roles", "test_date_folder"."owner_id", "test_date_folder"."acquired_owners", "test_date_folder"."acquire_parent", "test_date_folder"."description", "test_date_folder"."workflow_id", "test_date_folder"."container_content_type_id", "test_date_folder"."parent_container_id", "test_date_folder"."recursive", "test_date_folder"."extra_info" FROM "test_date_folder" WHERE ("test_date_folder"."created_on" BETWEEN 2017-01-01 00:00:00+00:00 AND 2017-12-31 23:59:59.999999+00:00 AND "test_date_folder"."created_by_id" = 5 AND NOT (("test_date_folder"."slug" = fake-slug OR NOT ("test_date_folder"."slug" = 2016-10-10))) AND "test_date_folder"."parent_container_id" = 1 AND "test_date_folder"."recursive" = True AND "test_date_folder"."acquire_parent" = True AND ("test_date_folder"."permissions_actions_map" -> \'object.view\' ?| [u\'hacs.PublicView\', u\'hacs.AuthenticatedView\', u\'hacs.ViewContent\', u\'hacs.AddContent\', u\'hacs.CanListObjects\', u\'hacs.CanTraverseContainer\'] OR "test_date_folder"."acquired_owners" @> \'"*****@*****.**"\' OR "test_date_folder"."roles_actions_map" -> \'object.view\' ?| (ARRAY(SELECT jsonb_array_elements_text("test_date_folder"."local_roles" -> [email protected]))) OR "test_date_folder"."owner_id" = 3))' """ attach_system_user() user_permissions = model_fixture.contributoruser.get_all_permissions() release_system_user() for perm in user_permissions: if perm not in sql_str: pass #raise AssertionError("%s permission should have inside SQL string" % perm) # *********************************** # Test Local Roles Works! # Test Ownership Works! # Test Required Permission Works! # Security Should Respect Local roles # ************************************ # If news item in private state then `hacs.ManageContent` permission is required news_item_cls = model_fixture.models.get('news_item_cls') for item in news_item_cls.objects.unrestricted(): item.state = "private" item.save() HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.editoruser results = news_item_cls.objects.all() count = len(results) # Any Editor has required view permission even in private state self.assertEqual(2, count) HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.contributoruser results = news_item_cls.objects.all() # Although in private state, contributor user has no views access but in case of `[email protected]` # she is owner of first news item and has local role editor of second news item # ultimately should have two news items in result count = len(results) self.assertEqual(2, count) HACS_ACCESS_CONTROL_LOCAL.current_user = get_user_model().objects.get_by_natural_key("*****@*****.**") results = news_item_cls.objects.all() count = len(results) # In Private state contributor has no view permissions! self.assertEqual(0, count) attach_system_user() # Restore to original State for item in news_item_cls.objects.unrestricted(): item.state = "draft" item.save() release_system_user() # Now Second contributor user also should have view permission results = news_item_cls.objects.all() count = len(results) self.assertEqual(2, count)
def test_delete(self): """ :return: """ news_item_cls = model_fixture.models.get('news_item_cls') date_folder_cls = model_fixture.models.get('date_folder_cls') news_item_1 = news_item_cls.objects.get_by_natural_key('news-one') news_item_1_copy = copy.copy(news_item_1) news_item_2 = news_item_cls.objects.get_by_natural_key( 'news-two-with-local-roles') news_item_2_copy = copy.copy(news_item_2) date_folder1 = date_folder_cls.objects.get_by_natural_key('2016-10-10') date_folder1_copy = copy.copy(date_folder1) contributor2 = get_user_model().objects.get_by_natural_key( '*****@*****.**') # As we have one record self.assertGreater(news_item_cls.objects.count(), 0) self.assertGreater(date_folder_cls.objects.count(), 0) # Test delete security guard HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.memberuser try: news_item_1_copy.delete() raise AssertionError( "Code should not come here as member user don't have permission to delete any content" ) except PermissionDenied: pass HACS_ACCESS_CONTROL_LOCAL.current_user = contributor2 try: news_item_1_copy.delete() raise AssertionError( "Code should not come here as contributor user also don't has permission to " "delete any content") except PermissionDenied: pass HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.contributoruser try: news_item_1_copy.delete() # re-insert for further test attach_system_user() news_item_1.save() release_system_user() news_item_1_copy = copy.copy(news_item_1) except PermissionDenied: raise AssertionError( "Code should not come here as although contributor user don't has permission to " "delete any content but this certain contributor owner of this content" ) HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.editoruser try: news_item_1_copy.delete() # re-insert for further test attach_system_user() news_item_1.save() release_system_user() news_item_1_copy = copy.copy(news_item_1) except PermissionDenied: raise AssertionError( "Code should not come here as editor user has permission to " "delete any content") HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.superuser try: news_item_1_copy.delete() # re-insert for further test attach_system_user() news_item_1.save() release_system_user() news_item_1_copy = copy.copy(news_item_1) except PermissionDenied: raise AssertionError( "Code should not come here as super user can perform any action" ) # Test with local roles # Contributor user has local role Editor on news_item2 HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.contributoruser try: news_item_2_copy.delete() attach_system_user() news_item_2.save() release_system_user() news_item_2_copy = copy.copy(news_item_2) except PermissionDenied: raise AssertionError( "Code should not come here, because contributor user has local role editor" ) # Test By changing workflow state HACS_ACCESS_CONTROL_LOCAL.current_user = model_fixture.editoruser try: date_folder1_copy.delete() attach_system_user() date_folder1.save() release_system_user() except PermissionDenied: raise AssertionError( "Code should not come here, as editor user should have permission to delete." ) date_folder1.state = 'published' attach_system_user() date_folder1.save() release_system_user() date_folder1_copy = copy.copy(date_folder1) try: date_folder1_copy.delete() raise AssertionError( "Code should not come here, as state changed to published, not" " `hacs.ManagePortal` permission holder can delete") except PermissionDenied: pass date_folder1_copy.owner = model_fixture.editoruser attach_system_user() date_folder1_copy.save() release_system_user() try: date_folder1_copy.delete() attach_system_user() date_folder1.save() release_system_user() date_folder1_copy = copy.copy(date_folder1) except PermissionDenied: raise AssertionError( "Code should not come here, as owner changed to editor user," "can delete") # Testing Children removed before parent container moved HACS_ACCESS_CONTROL_LOCAL.__release_local__() news_folder_cls = model_fixture.models.get('news_folder_cls') news_folder = news_folder_cls.objects.all().first() news_folder.delete() # No records should be, as cascade applied self.assertEqual(news_item_cls.objects.count(), 0) self.assertEqual(date_folder_cls.objects.count(), 0)