class TestPermissionsLoading(TestMemcacheBase): """Test user permissions loading.""" def setUp(self): super(TestPermissionsLoading, self).setUp() self.api = Api() self.generator = generator.ObjectGenerator() self.control_id = factories.ControlFactory().id _, user = self.generator.generate_person(user_role="Creator") self.api.set_user(user) def test_permissions_loading(self): """Test if permissions created only once for GET requests.""" with mock.patch( "ggrc_basic_permissions.store_results_into_memcache", side_effect=ggrc_basic_permissions.store_results_into_memcache ) as store_perm: self.api.get(all_models.Control, self.control_id) store_perm.assert_called_once() store_perm.call_count = 0 # On second GET permissions should be loaded from memcache # but not created from scratch. self.api.get(all_models.Control, self.control_id) store_perm.assert_not_called()
class TestAssigneeRBAC(TestRBAC): """TestAssigneeRBAC tests if users get correct permissions on objects where he is has assignee role""" def setUp(self): super(TestAssigneeRBAC, self).setUp() self.api = Api() self.set_up_people() self.assignee_roles = { role_name: role_id for role_id, role_name in get_custom_roles_for("Assessment").items() if role_name in ["Assignees", "Creators", "Verifiers"] } def test_mapped_regulations_read(self): """Test if creators can CRUD mapped Regulations and Objective snapshots.""" self.api.set_user(self.people.get("Editor")) with factories.single_commit(): audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) factories.AccessControlPersonFactory( ac_list=assessment.acr_name_acl_map["Creators"], person=self.people.get("Editor"), ) factories.AccessControlPersonFactory( ac_list=assessment.acr_name_acl_map["Assignees"], person=self.people.get("Creator"), ) factories.RelationshipFactory(source=audit, destination=assessment) control = factories.ControlFactory() objective = factories.ObjectiveFactory() regulation = factories.RegulationFactory() snapshots = self._create_snapshots( audit, [control, objective, regulation] ) for snapshot in snapshots: factories.RelationshipFactory(source=audit, destination=snapshot) factories.RelationshipFactory( source=snapshots[0], destination=snapshots[1] ) factories.RelationshipFactory( source=snapshots[2], destination=snapshots[0] ) factories.RelationshipFactory( source=assessment, destination=snapshots[0] ) self.api.set_user(self.people.get("Creator")) for snapshot in snapshots: db.session.add(snapshot) response = self.api.get(type(snapshot), snapshot.id) self.assertEqual( response.status_code, 200, "Cannot GET mapped object. Received {}".format(response.status) ) db.session.add(snapshot) response = self.api.delete(snapshot) self.assertEqual( response.status_code, 403, "Can DELETE mapped object. Received {}".format(response.status) )
class TestAccessControlRBAC(TestRBAC): """TestAccessControlRBAC tests if users get correct permissions on objects from the access control table""" def setUp(self): super(TestAccessControlRBAC, self).setUp() self.api = Api() self.set_up_people() self.set_up_acl_object() @ddt.data("Creator", "Reader", "Editor") def test_acl_object_cru(self, name): """Test if {0} can CRUD an object with all permissions""" control_id = self.control.id person = self.people.get(name) role_id = self.all_acr.id db.session.add(person) self.api.set_user(person) response = self.api.get(all_models.Control, control_id) assert response.status_code == 200, \ "{} cannot GET object from acl. Received {}".format( name, response.status) acl = response.json["control"]["access_control_list"] assert len(response.json["control"]["access_control_list"]) == 3, \ "ACL in control does not include all people {}".format(acl) assert acl[0].get("ac_role_id", None) == role_id, \ "ACL list does not include role id {}".format(acl)
class TestPersonProfilePermissions(TestCase): """Test PersonProfile.""" def setUp(self): super(TestPersonProfilePermissions, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """Init user with different roles.""" users = [("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role ) self.users[name] = user @ddt.data("reader", "editor", "admin", "creator") def test_permissions(self, name): """Test permissions for user roles.""" user = all_models.Person.query.get(self.users[name].id) profile = all_models.PersonProfile.query.join( all_models.PersonProfile.person ).filter_by( email=user.email ).one() self.api.set_user(self.users[name]) response = self.api.get(all_models.PersonProfile, profile.id) self.assert200(response) new_date = "2018-05-20 22:05:17" response = self.api.put(profile, { "people_profiles": { "id": profile.id, "last_seen_whats_new": new_date, }, }) self.assert200(response) response = self.api.delete(profile) if name == "admin": self.assert200(response) else: self.assert403(response)
class TestReader(TestCase): """Test Assignable RBAC""" def setUp(self): super(TestReader, self).setUp() self.audit_id = factories.AuditFactory().id self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_assignable() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def init_assignable(self): """Creates the assignable object used by all the tests""" self.api.set_user(self.users["editor"]) response = self.api.post(all_models.Assessment, { "assessment": { "title": "Assessment", "context": None, "audit": { "id": self.audit_id, "type": "Audit" } } }) obj_id = response.json.get("assessment").get("id") self.assertEqual(response.status_code, 201, "Error setting up Assessment") self.obj_json = response.json self.obj = all_models.Assessment.query.get(obj_id) def _add_creator(self, asmnt, user): """Helper method for creating assignees on an object""" acr = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.object_type == "Assessment", all_models.AccessControlRole.name == "Creators", ).first() return self.api.put(asmnt, { "access_control_list": [acl_helper.get_acl_json(acr.id, user.id)] }) def test_basic_with_no_assignee(self): """Editor creates an Assessment, but doesn't assign Reader/Creator as assignee. Reader should have Read access, Creator should have no access """ # Reader should have read access, but shouldn't be allowed to edit or # create another assingee self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, self.obj_json) self.assertEqual(response.status_code, 403) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 403) # Creator should have no access. We skip the put request because we can't # get the object etag. self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 403) def test_basic_with_assignee(self): """Test if Reader/Creator have CRUD access once they become assignees""" # Admin adds reader as an assignee self.api.set_user(self.users["admin"]) response = self._add_creator(self.obj, self.users["reader"]) self.assertEqual(response.status_code, 200) # Reader is now allowed to update the object self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) self.assertEqual(response.status_code, 200) # Reader adds creator as an assignee response = self._add_creator(self.obj, self.users["creator"]) self.assertEqual(response.status_code, 200) # Creator now has CRUD access self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) # Creator should even be allowed to add new assignees response = self._add_creator(self.obj, self.users["admin"]) self.assertEqual(response.status_code, 200) def test_read_of_mapped_objects(self): """Test if assignees get Read access on all mapped objects""" # Editor creates a System object and maps it to the assignable object self.api.set_user(self.users["editor"]) response = self.api.post(all_models.System, { "system": { "title": "System", "context": None, } }) system_id = response.json.get("system").get("id") system = all_models.System.query.get(system_id) self.api.post(all_models.Relationship, { "relationship": {"source": { "id": self.obj.id, "type": "Assessment" }, "destination": { "id": system_id, "type": "System" }, "context": None}, }) # Since creator is not an assignee she should not have access to any of the # two objects self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 403) # Editor adds creator as an assignee self.api.set_user(self.users["editor"]) response = self._add_creator(self.obj, self.users["creator"]) self.assertEqual(response.status_code, 200) # Creator should now have read access on the mapped object self.api.set_user(self.users["creator"]) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 403) # But he should still not be allowed to update response = self.api.put(system, response.json) self.assertEqual(response.status_code, 403)
class TestPermissionsOnAssessmentTemplate(TestCase): """ Test check permissions for ProgramEditor on get and post assessment_temaplte action""" def setUp(self): super(TestPermissionsOnAssessmentTemplate, self).setUp() self.api = Api() self.generator = ObjectGenerator() _, program = self.generator.generate_object(all_models.Program) program_id = program.id _, self.editor = self.generator.generate_person( user_role="Creator" ) role = perms.all_models.Role.query.filter( perms.all_models.Role.name == "ProgramEditor" ).first() self.generator.generate_user_role( self.editor, role, all_models.Program.query.get(program_id) ) _, audit = self.generator.generate_object( all_models.Audit, { "title": "Audit", "program": {"id": program_id}, "status": "Planned" }, ) audit_id = audit.id generated_at = self.generator.generate_object( all_models.AssessmentTemplate, { "title": "Template", "_NON_RELEVANT_OBJ_TYPES": {}, "_objectTypes": {}, "audit": {"id": audit.id}, "audit_title": audit.title, "people_value": [], "default_people": { "assessors": "Object Owners", "verifiers": "Object Owners", }, "context": {"id": audit.context.id}, } ) self.assessment_template_resp, assessment_template = generated_at assessment_template_id = assessment_template.id self.api.set_user(self.editor) self.perms_data = self.api.client.get("/permissions").json self.audit = all_models.Audit.query.get(audit_id) self.assessment_template = all_models.AssessmentTemplate.query.get( assessment_template_id) def test_post_action(self): """Test create action on AssessmentTemplate created by api""" data = [{ "assessment_template": { "_NON_RELEVANT_OBJ_TYPES": {}, "_objectTypes": {}, "audit": {"id": self.audit.id}, "audit_title": self.audit.title, "people_value": [], "default_people": { "assessors": "Object Owners", "verifiers": "Object Owners", }, "context": {"id": self.audit.context.id}, "title": "123", } }] self.api.set_user(self.editor) resp = self.api.post(all_models.AssessmentTemplate, data) self.assert200(resp) def test_get_action(self): """Test read action on AssessmentTemplate created by api""" resp = self.api.get(all_models.AssessmentTemplate, self.assessment_template.id) self.assert200(resp) def test_put_action(self): """Test update action on AssessmentTemplate created by api""" to_update = copy.deepcopy(self.assessment_template_resp.json) new_title = "new_{}".format(self.assessment_template.title) to_update['assessment_template']['title'] = new_title resp = self.api.put(self.assessment_template, to_update) self.assert200(resp) assessment_tmpl = all_models.AssessmentTemplate.query.get( self.assessment_template.id ) self.assertEqual(new_title, assessment_tmpl.title) def test_delete_action(self): """Test delete action on AssessmentTemplate created by api""" resp = self.api.delete(self.assessment_template) self.assert200(resp) self.assertFalse(all_models.AssessmentTemplate.query.filter( all_models.AssessmentTemplate == self.assessment_template.id).all())
class TestAuditRBAC(TestCase): """Test audit RBAC""" CSV_DIR = join(abspath(dirname(__file__)), "test_csvs") @classmethod def setUpClass(cls): TestCase.clear_data() cls.response = cls._import_file("audit_rbac.csv") cls.people = all_models.Person.eager_query().all() cls.audit = all_models.Audit.eager_query().first() sources = set(r.source for r in cls.audit.related_sources) destinations = set(r.destination for r in cls.audit.related_destinations) related = [obj for obj in sources.union(destinations) if not isinstance(obj, all_models.Person)] cls.related_objects = related def setUp(self): """Imports test_csvs/audit_rbac.csv needed by the tests""" self._check_csv_response(self.response, {}) self.api = Api() self.client.get("/login") def read(self, objects): """Attempt to do a GET request for every object in the objects list""" responses = [] for obj in objects: status_code = self.api.get(obj.__class__, obj.id).status_code responses.append((obj.type, status_code)) return responses def update(self, objects): """Attempt to do a PUT request for every object in the objects list""" responses = [] for obj in objects: response = self.api.get(obj.__class__, obj.id) status_code = response.status_code if response.status_code == 200: status_code = self.api.put(obj, response.json).status_code responses.append((obj.type, status_code)) return responses def call_api(self, method, expected_statuses): """Calls the REST api with a given method and returns a list of status_codes that do not match the expected_statuses dict""" all_errors = [] for person in self.people: self.api.set_user(person) responses = method(self.related_objects + [self.audit]) for type_, code in responses: if code != expected_statuses[person.email]: all_errors.append("{} does not have {} access to {} ({})".format( person.email, method.__name__, type_, code)) return all_errors def test_read_access_on_mapped(self): """Test if people have read access to mapped objects. All users except [email protected] should have read access.""" expected_statuses = defaultdict(lambda: 200) for exception in ("*****@*****.**",): expected_statuses[exception] = 403 errors = self.call_api(self.read, expected_statuses) assert not errors, "\n".join(errors) def test_update_access_on_mapped(self): """Test if people have upate access to mapped objects. All users except [email protected], [email protected], [email protected], [email protected] should have update access.""" expected_statuses = defaultdict(lambda: 200) for exception in ("*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**"): expected_statuses[exception] = 403 errors = self.call_api(self.update, expected_statuses) assert not errors, "\n".join(errors)
class TestReviewApi(TestCase): """Base TestCase class proposal api tests.""" def setUp(self): super(TestReviewApi, self).setUp() self.api = Api() self.api.client.get("/login") self.generator = generator.ObjectGenerator() def test_simple_get(self): """Test simple get""" with factories.single_commit(): risk = factories.RiskFactory() review = factories.ReviewFactory( email_message="test email message", notification_type="email", reviewable=risk, status=all_models.Review.STATES.UNREVIEWED, ) resp = self.api.get(all_models.Review, review.id) self.assert200(resp) self.assertIn("review", resp.json) resp_review = resp.json["review"] self.assertEqual(all_models.Review.STATES.UNREVIEWED, resp_review["status"]) self.assertEqual(all_models.Review.NotificationTypes.EMAIL_TYPE, resp_review["notification_type"]) self.assertEqual("test email message", resp_review["email_message"]) def test_collection_get(self): """Test simple collection get""" with factories.single_commit(): review1 = factories.ReviewFactory( status=all_models.Review.STATES.UNREVIEWED ) review2 = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED ) resp = self.api.get_collection(all_models.Review, [review1.id, review2.id]) self.assert200(resp) self.assertIn("reviews_collection", resp.json) self.assertIn("reviews", resp.json["reviews_collection"]) self.assertEquals(2, len(resp.json["reviews_collection"]["reviews"])) def test_create_review(self): """Create review via API, check that single relationship is created""" program = factories.ProgramFactory() program_id = program.id resp = self.api.post( all_models.Review, { "review": { "reviewable": { "type": program.type, "id": program.id, }, "context": None, "notification_type": "email", "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl() }, }, ) self.assertEqual(201, resp.status_code) review_id = resp.json["review"]["id"] review = all_models.Review.query.get(review_id) self.assertEqual(all_models.Review.STATES.UNREVIEWED, review.status) self.assertEqual(program.type, review.reviewable_type) self.assertEqual(program_id, review.reviewable_id) control_review_rel_count = all_models.Relationship.query.filter( all_models.Relationship.source_id == review.id, all_models.Relationship.source_type == review.type, all_models.Relationship.destination_id == program_id, all_models.Relationship.destination_type == program.type, ).union( all_models.Relationship.query.filter( all_models.Relationship.destination_id == review.id, all_models.Relationship.destination_type == review.type, all_models.Relationship.source_id == program_id, all_models.Relationship.source_type == program.type, ) ).count() self.assertEqual(1, control_review_rel_count) def test_delete_review(self): """Test delete review via API""" with factories.single_commit(): risk = factories.RiskFactory() risk_id = risk.id review = factories.ReviewFactory(reviewable=risk) review_id = review.id resp = self.api.delete(review) self.assert200(resp) review = all_models.Review.query.get(review_id) risk = all_models.Risk.query.get(risk_id) self.assertIsNone(review) self.assertEquals(0, len(risk.related_objects(_types=["Review"]))) def test_last_reviewed(self): """last_reviewed_by, last_reviewed_by should be set if reviewed""" risk = factories.RiskFactory() resp, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": risk.type, "id": risk.id, }, "context": None, "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl(), "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE }, ) review_id = review.id resp = self.api.put( review, { "status": all_models.Review.STATES.REVIEWED, }, ) self.assert200(resp) self.assertIsNotNone(resp.json["review"]["last_reviewed_by"]) self.assertIsNotNone(resp.json["review"]["last_reviewed_at"]) review = all_models.Review.query.get(review_id) self.assertIsNotNone(review.last_reviewed_by) self.assertIsNotNone(review.last_reviewed_at) def test_reviewable_revisions(self): """Check that proper revisions are created""" program = factories.ProgramFactory() resp, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": program.type, "id": program.id, }, "context": None, "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl(), "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE }, ) program_id = program.id reviewable = review.reviewable program_revisions = all_models.Revision.query.filter_by( resource_id=program_id, resource_type=program.type ).order_by( all_models.Revision.id, ).all() self.assertEquals(2, len(program_revisions)) self.assertEquals(all_models.Review.STATES.UNREVIEWED, program_revisions[0].content["review_status"]) self.assertEquals(all_models.Review.STATES.UNREVIEWED, program_revisions[1].content["review_status"]) resp = self.api.put( review, { "status": all_models.Review.STATES.REVIEWED, }, ) self.assert200(resp) program_revisions = all_models.Revision.query.filter_by( resource_id=program_id, resource_type=program.type ).order_by( all_models.Revision.id, ).all() self.assertEquals(3, len(program_revisions)) self.assertEquals(all_models.Review.STATES.REVIEWED, program_revisions[2].content["review_status"]) resp = self.api.put( reviewable, { "description": "some new description" } ) self.assert200(resp) program_revisions = all_models.Revision.query.filter_by( resource_id=program_id, resource_type=program.type ).order_by( all_models.Revision.id, ).all() self.assertEquals(4, len(program_revisions)) self.assertEquals(all_models.Review.STATES.UNREVIEWED, program_revisions[3].content["review_status"])
class TestCreatorProgram(TestCase): """Set up necessary objects and test Creator role with Program roles""" def setUp(self): super(TestCreatorProgram, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """ Create a dict of all possible test cases """ self.test_cases = { "notmapped": { "objects": { "program": { "get": 403, "put": 403, "delete": 403 }, "mapped_object": { "get": 403, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } }, }, "mapped": { "objects": { "program": { "get": 403, "put": 403, "delete": 403 }, "mapped_object": { "get": 403, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramReader": { "program_role": "ProgramReader", "objects": { "program": { "get": 200, "put": 403, "delete": 403 }, "mapped_object": { "get": 200, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramOwner": { "program_role": "ProgramOwner", "objects": { "program": { "get": 200, "put": 200, "delete": 200 }, "mapped_object": { "get": 200, "put": 200, "delete": 200, }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramEditor": { "program_role": "ProgramEditor", "objects": { "program": { "get": 200, "put": 200, "delete": 200 }, "mapped_object": { "get": 200, "put": 200, "delete": 200 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """ Create a delete request for the given object """ response = self.api.get_query(all_models.Role, "") self.roles = {} for role in response.json.get("roles_collection").get("roles"): self.roles[role.get("name")] = role def init_users(self): """ Create users used by test cases """ users = [ ("creator", "Creator"), ("notmapped", "Creator"), ("mapped", "Creator"), ("ProgramReader", "Creator"), ("ProgramEditor", "Creator"), ("ProgramOwner", "Creator")] self.people = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.people[name] = user def delete(self, obj): """ Create a delete request for the given object """ return self.api.delete(obj).status_code def get(self, obj): """ Create a get request for the given object """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """ Create a put request for the given object """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """ Map src to dest """ response = self.api.post(all_models.Relationship, { "relationship": {"source": { "id": self.objects["program"].id, "type": self.objects["program"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None}, }) return response.status_code def init_objects(self, test_case_name): """ Create a Program and a Mapped object for a given test case """ # Create a program test_case = self.test_cases[test_case_name] creator = self.people.get('creator') self.api.set_user(creator) random_title = factories.random_str() response = self.api.post(all_models.Program, { "program": {"title": random_title, "context": None}, }) self.assertEqual(response.status_code, 201) context_id = response.json.get("program").get("context").get("id") program_id = response.json.get("program").get("id") # Use admin owner role to map it with system acr_id = all_models.AccessControlRole.query.filter_by( object_type="System", name="Admin" ).first().id self.objects["program"] = all_models.Program.query.get(program_id) # Create an object: for obj in ("mapped_object", "unrelated"): random_title = factories.random_str() response = self.api.post(all_models.System, { "system": { "title": random_title, "context": None, "access_control_list": [{ "person": { "id": creator.id, "type": "Person", }, "ac_role_id": acr_id, "context": None }], }, }) self.assertEqual(response.status_code, 201) system_id = response.json.get("system").get("id") self.objects[obj] = all_models.System.query.get(system_id) # Map Object to Program response = self.api.post(all_models.Relationship, { "relationship": {"source": { "id": program_id, "type": "Program" }, "destination": { "id": self.objects["mapped_object"].id, "type": "System" }, "context": None}, }) self.assertEqual(response.status_code, 201) # Map people to Program: if test_case_name != "notmapped": person = self.people.get(test_case_name) response = self.api.post(all_models.ObjectPerson, {"object_person": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "personable": { "type": "Program", "href": "/api/programs/{}".format(program_id), "id": program_id, }, "context": { "type": "Context", "id": context_id, "href": "/api/contexts/{}".format(context_id) }}}) # Add roles to mapped users: if "program_role" in test_case: person = self.people.get(test_case_name) role = self.roles[test_case["program_role"]] response = self.api.post(all_models.UserRole, {"user_role": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "role": { "type": "Role", "href": "/api/roles/{}".format(role["id"]), "id": role["id"], }, "context": { "type": "Context", "id": context_id, "href": "/api/contexts/{}".format(context_id) }}}) self.assertEqual(response.status_code, 201) def test_creator_program_roles(self): """ Test creator role with all program scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj in ("unrelated", "mapped_object", "program"): actions = objects[obj] for action in ("map", "get", "put", "delete"): # reset sesion: db.session.commit() if action not in actions: continue func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}".format( test_case, action, obj, res, actions[action])) # Try mapping self.assertEqual(errors, [])
class TestCreatorAudit(TestCase): """Set up necessary objects and test Creator role with Audit roles""" def setUp(self): super(TestCreatorAudit, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """Create a dict of all possible test cases.""" self.test_cases = { "Auditor": { "audit_role": "Auditor", "objects": { "audit": { "get": 200, "put": 403, "delete": 403 }, "mapped_Issue": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Issue": { "get": 403, "put": 403, "delete": 403, "map": 403, }, "mapped_Assessment": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Assessment": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """Create a delete request for the given object.""" response = self.api.get_query(all_models.Role, "") self.roles = {} for role in response.json.get("roles_collection").get("roles"): self.roles[role.get("name")] = role def init_users(self): """Create users used by test cases.""" self.people = {} for name in ["creator", "notmapped", "mapped", "Auditor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role="Creator") self.people[name] = user _, user = self.object_generator.generate_person( data={"name": "editor"}, user_role="Editor") self.people["editor"] = user def delete(self, obj): """Create a delete request for the given object. Args: obj (model instance): target object to delete Returns: int: http response status code """ return self.api.delete(obj).status_code def get(self, obj): """Create a get request for the given object. Args: obj (model instance): target object to get Returns: int: http response status code """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """Create a put request for the given object. Args: obj (model instance): target object to put Returns: int: http response status code """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """Map audit to dest. Args: dest (model instance): target object to map to the audit Returns: int: http response status code """ response = self.api.post(all_models.Relationship, { "relationship": {"source": { "id": self.objects["audit"].id, "type": self.objects["audit"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None}, }) return response.status_code def init_objects(self, test_case_name): """Create a Program, an Audit, and a Mapped object for the test case. Args: test_case_name (string): test case to init for """ # Create a program dummy_audit = factories.AuditFactory() unrelated_audit = { "type": "Audit", "context_id": dummy_audit.context.id, "id": dummy_audit.id, } test_case = self.test_cases[test_case_name] editor = self.people.get('editor') self.api.set_user(editor) random_title = factories.random_str() response = self.api.post(all_models.Program, { "program": {"title": random_title, "context": None}, }) self.assertEqual(response.status_code, 201) program_id = response.json.get("program").get("id") self.objects["program"] = all_models.Program.query.get(program_id) response = self.api.post(all_models.Audit, { "audit": { "title": random_title + " audit", 'program': {'id': program_id}, "status": "Planned", "context": None } }) self.assertEqual(response.status_code, 201) context = response.json.get("audit").get("context") audit_id = response.json.get("audit").get("id") self.objects["audit"] = all_models.Audit.query.get(audit_id) audits = { "mapped": { "type": "Audit", "context_id": context["id"], "id": audit_id, }, "unrelated": unrelated_audit, } for prefix, audit_dict in audits.items(): random_title = factories.random_str() response = self.api.post(all_models.Issue, { "issue": { "title": random_title, "context": { "type": "Context", "id": audit_dict["context_id"], }, "audit": audit_dict, }, }) self.assertEqual(response.status_code, 201) issue_id = response.json.get("issue").get("id") self.objects[prefix + "_Issue"] = all_models.Issue.query.get(issue_id) response = self.api.post(all_models.Assessment, { "assessment": { "title": random_title, "context": { "type": "Context", "id": audit_dict["context_id"], }, "audit": audit_dict, }, }) self.assertEqual(response.status_code, 201) assessment_id = response.json.get("assessment").get("id") self.objects[prefix + "_Assessment"] = \ all_models.Assessment.query.get(assessment_id) self.assertEqual(self.map(self.objects["mapped_Issue"]), 201) self.assertEqual(self.map(self.objects["mapped_Assessment"]), 201) # Add roles to mapped users: if "audit_role" in test_case: person = self.people.get(test_case_name) role = self.roles[test_case["audit_role"]] response = self.api.post(all_models.UserRole, {"user_role": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "role": { "type": "Role", "href": "/api/roles/{}".format(role["id"]), "id": role["id"], }, "context": { "type": "Context", "id": context.get("id"), "href": "/api/contexts/{}".format(context.get("id")) }}}) self.assertEqual(response.status_code, 201) def test_creator_audit_roles(self): """ Test creator role with all audit scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj, actions in objects.iteritems(): for action in ("map", "get", "put", "delete"): if action not in actions: continue # reset sesion: db.session.commit() func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}".format( test_case, action, obj, res, actions[action])) self.assertEqual(errors, [])
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): """Only admin can use admin requirement""" for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup", "Metric", "TechnologyEnvironment", "ProductGroup", ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post( model, { table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # ignored except for Document "contact": { "type": "Person", "id": self.users["reader"].id, }, }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": { "title": "reader Policy", "context": None }, }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): """Check if reader can't create mappings""" self.generator.api.set_user(self.users["admin"]) _, control = self.generator.generate(all_models.Control, "control", { "control": { "title": "Test Control", "context": None }, }) self.generator.api.set_user(self.users['reader']) _, program = self.generator.generate(all_models.Program, "program", { "program": { "title": "Test Program", "context": None }, }) response, _ = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "destination": { "id": program.id, "type": "Program" }, "source": { "id": control.id, "type": "Control" }, "context": { "id": program.context.id, "type": "context" } }, }) self.assertEqual(response.status_code, 403) @ddt.data("creator", "reader") def test_unmap_people(self, user_role): """Test that global reader/creator can't unmap people from program""" user = self.users[user_role] with factories.single_commit(): program = factories.ProgramFactory() mapped_person = factories.ObjectPersonFactory( personable=program, person=user, context=program.context) self.api.set_user(user) db.session.add(mapped_person) response = self.api.delete(mapped_person) self.assertEqual(response.status_code, 403) def test_read_evidence_revision(self): """Global Read can read Evidence revision content""" user = self.users["reader"] link = "google.com" evidence = factories.EvidenceUrlFactory(link=link) evidence_id = evidence.id self.api.set_user(user) resp = self.api.client.get( "/api/revisions?resource_type={}&resource_id={}".format( evidence.type, evidence_id)) rev_content = resp.json["revisions_collection"]["revisions"][0][ "content"] self.assertTrue(rev_content) self.assertEquals(link, rev_content["link"])
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) creator_id = self.users["creator"].id audit_id = factories.AuditFactory().id all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": creator_id, }, "audit": { # this is ignored on everything but Issues "id": audit_id, "type": "Audit", } }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format( model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) != 0: all_errors.append( "{} can retrieve object if not owner (collection)". format(model_singular)) continue # Test GET when owner acr = all_models.AccessControlRole.query.filter_by( object_type=model_singular, name="Admin").first() factories.AccessControlListFactory(object_id=obj_id, object_type=model_singular, ac_role=acr, person_id=creator_id) response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['creator']) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Policy", name="Admin").first().id response = self.api.post( all_models.Policy, { "policy": { "title": "Creator Policy", "context": None, "access_control_list": [{ "person": { "id": self.users["creator"].id, "type": "Person", }, "ac_role_id": acr_id, "context": None }], }, }) response.json.get("policy").get("id") response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title, extra_data=None): section_content = {"title": title, "context": None} section_content.update(**extra_data) if extra_data else None return self.generator.generate(all_models.Section, "section", {"section": section_content})[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id)) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Section 1") self.api.set_user(self.users["creator"]) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Section", name="Admin").first().id linked_acl = { "access_control_list": [{ "person": { "id": self.users["creator"].id, "type": "Person", }, "ac_role_id": acr_id, "context": None }] } check(obj_1, 0) obj_2 = gen("Test Section 2", linked_acl) obj2_acl = obj_2.access_control_list[0] check(obj_2, 1) check(obj2_acl, 1) @ddt.data("creator", "admin") def test_count_type_in_accordion(self, glob_role): """Return count of Persons in DB for side accordion.""" self.api.set_user(self.users[glob_role]) ocordion_api_person_count_link = ( "/search?" "q=&types=Program%2CWorkflow_All%2C" "Audit%2CAssessment%2CIssue%2CRegulation%2C" "Policy%2CStandard%2CContract%2CClause%2CSection%2CControl%2C" "Objective%2CPerson%2COrgGroup%2CVendor%2CAccessGroup%2CSystem%2C" "Process%2CDataAsset%2CProduct%2CProject%2CFacility%2C" "Market%2CRisk%2CThreat&counts_only=true&" "extra_columns=Workflow_All%3DWorkflow%2C" "Workflow_Active%3DWorkflow%2CWorkflow_Draft%3D" "Workflow%2CWorkflow_Inactive%3DWorkflow&contact_id=1&" "extra_params=Workflow%3Astatus%3DActive%3BWorkflow_Active" "%3Astatus%3DActive%3BWorkflow_Inactive%3Astatus%3D" "Inactive%3BWorkflow_Draft%3Astatus%3DDraft") resp = self.api.client.get(ocordion_api_person_count_link) self.assertIn("Person", resp.json["results"]["counts"]) self.assertEqual(all_models.Person.query.count(), resp.json["results"]["counts"]["Person"])
class TestCreatorProgram(TestCase): """Set up necessary objects and test Creator role with Program roles""" def setUp(self): TestCase.setUp(self) self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """ Create a dict of all possible test cases """ self.test_cases = { "notmapped": { "objects": { "program": { "get": 403, "put": 403, "delete": 403 }, "mapped_object": { "get": 403, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } }, }, "mapped": { "objects": { "program": { "get": 403, "put": 403, "delete": 403 }, "mapped_object": { "get": 403, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramReader": { "program_role": "ProgramReader", "objects": { "program": { "get": 200, "put": 403, "delete": 403 }, "mapped_object": { "get": 200, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramOwner": { "program_role": "ProgramOwner", "objects": { "program": { "get": 200, "put": 200, "delete": 200 }, "mapped_object": { "get": 200, "put": 200, "delete": 200, }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramEditor": { "program_role": "ProgramEditor", "objects": { "program": { "get": 200, "put": 200, "delete": 200 }, "mapped_object": { "get": 200, "put": 200, "delete": 200 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """ Create a delete request for the given object """ response = self.api.get_query(all_models.Role, "") self.roles = {} for role in response.json.get("roles_collection").get("roles"): self.roles[role.get("name")] = role def init_users(self): """ Create users used by test cases """ users = [ ("creator", "Creator"), ("notmapped", "Creator"), ("mapped", "Creator"), ("ProgramReader", "Creator"), ("ProgramEditor", "Creator"), ("ProgramOwner", "Creator")] self.people = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.people[name] = user def delete(self, obj): """ Create a delete request for the given object """ return self.api.delete(obj).status_code def get(self, obj): """ Create a get request for the given object """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """ Create a put request for the given object """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """ Map src to dest """ response = self.api.post(all_models.Relationship, { "relationship": {"source": { "id": self.objects["program"].id, "type": self.objects["program"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None}, }) return response.status_code def init_objects(self, test_case_name): """ Create a Program and a Mapped object for a given test case """ # Create a program test_case = self.test_cases[test_case_name] creator = self.people.get('creator') self.api.set_user(creator) random_title = self.object_generator.random_str() response = self.api.post(all_models.Program, { "program": {"title": random_title, "context": None}, }) self.assertEqual(response.status_code, 201) context_id = response.json.get("program").get("context").get("id") program_id = response.json.get("program").get("id") self.objects["program"] = all_models.Program.query.get(program_id) # Create an object: for obj in ("mapped_object", "unrelated"): random_title = self.object_generator.random_str() response = self.api.post(all_models.System, { "system": {"title": random_title, "context": None}, }) self.assertEqual(response.status_code, 201) system_id = response.json.get("system").get("id") self.objects[obj] = all_models.System.query.get(system_id) # Become the owner response = self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": creator.id, "type": "Person", }, "ownable": { "id": system_id, "type": "System" }, "context": None}}) # Map Object to Program response = self.api.post(all_models.Relationship, { "relationship": {"source": { "id": program_id, "type": "Program" }, "destination": { "id": self.objects["mapped_object"].id, "type": "System" }, "context": None}, }) self.assertEqual(response.status_code, 201) # Map people to Program: if test_case_name != "notmapped": person = self.people.get(test_case_name) response = self.api.post(all_models.ObjectPerson, {"object_person": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "personable": { "type": "Program", "href": "/api/programs/{}".format(program_id), "id": program_id, }, "context": { "type": "Context", "id": context_id, "href": "/api/contexts/{}".format(context_id) }}}) # Add roles to mapped users: if "program_role" in test_case: person = self.people.get(test_case_name) role = self.roles[test_case["program_role"]] response = self.api.post(all_models.UserRole, {"user_role": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "role": { "type": "Role", "href": "/api/roles/{}".format(role["id"]), "id": role["id"], }, "context": { "type": "Context", "id": context_id, "href": "/api/contexts/{}".format(context_id) }}}) self.assertEqual(response.status_code, 201) def test_creator_program_roles(self): """ Test creator role with all program scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj in ("unrelated", "mapped_object", "program"): actions = objects[obj] for action in ("map", "get", "put", "delete"): # reset sesion: db.session.commit() if action not in actions: continue func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}".format( test_case, action, obj, res, actions[action])) # Try mapping self.assertEqual(errors, []) def test_creator_audit_request_creation(self): self.init_objects("ProgramOwner") program = self.objects.get("program") creator = self.people.get("creator") # Create an audit response = self.api.post(all_models.Audit, { "audit": { "title": "Audit for program", "status": "Planned", "context": { "id": program.context_id, "type": "Context" }, "program": { "context_id": program.context_id, "id": program.id, "type": "Program", }, "contact": { "id": creator.id, "type": "Person" } }, }) self.assertEqual(response.status_code, 201) audit_id = response.json.get("audit").get("id") audit_context_id = response.json.get("audit").get("context").get("id") # Create a request response = self.api.post(all_models.Request, { "request": { "title": "Request for audit", "status": "In Progress", "context": { "id": audit_context_id, "type": "Context" }, "audit": { "id": audit_id, "type": "Audit", }, "end_date": "2015-12-08", "start_date": "2015-12-01", "request_type": "documentation" }, }) self.assertEqual(response.status_code, 201) request_id = response.json.get("request").get("id") # Create assignee/requester relationships assignee = self.people.get("notmapped") response = self.api.post(all_models.Relationship, { "relationship": { "attrs": { "AssigneeType": "Assignee" }, "context": { "id": audit_context_id, "type": "Context", }, "destination": { "id": request_id, "type": "Request", }, "source": { "id": assignee.id, "type": "Person" } }, }) self.assertEqual(response.status_code, 201) relationship_id = response.json.get("relationship").get("id") response = self.api.get_collection(all_models.Relationship, relationship_id) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 2)
class TestCreatorAudit(TestCase): """Set up necessary objects and test Creator role with Audit roles""" def setUp(self): super(TestCreatorAudit, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """Create a dict of all possible test cases.""" self.test_cases = { "Auditor": { "audit_role": "Auditor", "objects": { "audit": { "get": 200, "put": 200, "delete": 403 }, "mapped_Issue": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Issue": { "get": 403, "put": 403, "delete": 403, "map": 403, }, "mapped_Assessment": { "get": 200, "put": 200, "delete": 200 }, "unrelated_Assessment": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """Create a delete request for the given object.""" response = self.api.get_query(all_models.Role, "") self.roles = {} for role in response.json.get("roles_collection").get("roles"): self.roles[role.get("name")] = role def init_users(self): """Create users used by test cases.""" self.people = {} for name in ["creator", "notmapped", "mapped", "Auditor"]: _, user = self.object_generator.generate_person( data={"name": name}, user_role="Creator") self.people[name] = user _, user = self.object_generator.generate_person( data={"name": "editor"}, user_role="Editor") self.people["editor"] = user def delete(self, obj): """Create a delete request for the given object. Args: obj (model instance): target object to delete Returns: int: http response status code """ return self.api.delete(obj).status_code def get(self, obj): """Create a get request for the given object. Args: obj (model instance): target object to get Returns: int: http response status code """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """Create a put request for the given object. Args: obj (model instance): target object to put Returns: int: http response status code """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """Map audit to dest. Args: dest (model instance): target object to map to the audit Returns: int: http response status code """ response = self.api.post( all_models.Relationship, { "relationship": { "source": { "id": self.objects["audit"].id, "type": self.objects["audit"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None }, }) return response.status_code def init_objects(self, test_case_name): """Create a Program, an Audit, and a Mapped object for the test case. Args: test_case_name (string): test case to init for """ # Create a program test_case = self.test_cases[test_case_name] editor = self.people.get('editor') self.api.set_user(editor) random_title = factories.random_str() response = self.api.post(all_models.Program, { "program": { "title": random_title, "context": None }, }) self.assertEqual(response.status_code, 201) program_id = response.json.get("program").get("id") self.objects["program"] = all_models.Program.query.get(program_id) response = self.api.post( all_models.Audit, { "audit": { "title": random_title + " audit", 'program': { 'id': program_id }, "status": "Planned", "context": None } }) self.assertEqual(response.status_code, 201) context_id = response.json.get("audit").get("context").get("id") audit_id = response.json.get("audit").get("id") self.objects["audit"] = all_models.Audit.query.get(audit_id) for prefix in ("mapped", "unrelated"): random_title = factories.random_str() response = self.api.post(all_models.Issue, { "issue": { "title": random_title, "context": None }, }) self.assertEqual(response.status_code, 201) issue_id = response.json.get("issue").get("id") self.objects[prefix + "_Issue"] = all_models.Issue.query.get(issue_id) response = self.api.post(all_models.Assessment, { "assessment": { "title": random_title, "context": None }, }) self.assertEqual(response.status_code, 201) assessment_id = response.json.get("assessment").get("id") self.objects[prefix + "_Assessment"] = \ all_models.Assessment.query.get(assessment_id) self.assertEqual(self.map(self.objects["mapped_Issue"]), 201) self.assertEqual(self.map(self.objects["mapped_Assessment"]), 201) # Add roles to mapped users: if "audit_role" in test_case: person = self.people.get(test_case_name) role = self.roles[test_case["audit_role"]] response = self.api.post( all_models.UserRole, { "user_role": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "role": { "type": "Role", "href": "/api/roles/{}".format(role["id"]), "id": role["id"], }, "context": { "type": "Context", "id": context_id, "href": "/api/contexts/{}".format(context_id) } } }) self.assertEqual(response.status_code, 201) def test_creator_audit_roles(self): """ Test creator role with all audit scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj, actions in objects.iteritems(): for action in ("map", "get", "put", "delete"): if action not in actions: continue # reset sesion: db.session.commit() func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}" .format(test_case, action, obj, res, actions[action])) self.assertEqual(errors, [])
class TestReviewApi(TestCase): """Base TestCase class proposal api tests.""" def setUp(self): super(TestReviewApi, self).setUp() self.api = Api() self.api.client.get("/login") self.generator = generator.ObjectGenerator() def test_simple_get(self): """Test simple get""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( email_message="test email message", notification_type="email", reviewable=control, status=all_models.Review.STATES.UNREVIEWED, ) resp = self.api.get(all_models.Review, review.id) self.assert200(resp) self.assertIn("review", resp.json) resp_review = resp.json["review"] self.assertEqual(all_models.Review.STATES.UNREVIEWED, resp_review["status"]) self.assertEqual(all_models.Review.NotificationTypes.EMAIL_TYPE, resp_review["notification_type"]) self.assertEqual("test email message", resp_review["email_message"]) def test_collection_get(self): """Test simple collection get""" with factories.single_commit(): review1 = factories.ReviewFactory( status=all_models.Review.STATES.UNREVIEWED ) review2 = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED ) resp = self.api.get_collection(all_models.Review, [review1.id, review2.id]) self.assert200(resp) self.assertIn("reviews_collection", resp.json) self.assertIn("reviews", resp.json["reviews_collection"]) self.assertEquals(2, len(resp.json["reviews_collection"]["reviews"])) def test_create_review(self): """Create review via API, check that single relationship is created""" control = factories.ControlFactory() control_id = control.id resp = self.api.post( all_models.Review, { "review": { "reviewable": { "type": control.type, "id": control.id, }, "context": None, "notification_type": "email", "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl() }, }, ) self.assertEqual(201, resp.status_code) review_id = resp.json["review"]["id"] review = all_models.Review.query.get(review_id) self.assertEqual(all_models.Review.STATES.UNREVIEWED, review.status) self.assertEqual(control.type, review.reviewable_type) self.assertEqual(control_id, review.reviewable_id) control_review_rel_count = all_models.Relationship.query.filter( all_models.Relationship.source_id == review.id, all_models.Relationship.source_type == review.type, all_models.Relationship.destination_id == control_id, all_models.Relationship.destination_type == control.type, ).union( all_models.Relationship.query.filter( all_models.Relationship.destination_id == review.id, all_models.Relationship.destination_type == review.type, all_models.Relationship.source_id == control_id, all_models.Relationship.source_type == control.type, ) ).count() self.assertEqual(1, control_review_rel_count) def test_delete_review(self): """Test delete review via API""" with factories.single_commit(): control = factories.ControlFactory() control_id = control.id review = factories.ReviewFactory(reviewable=control) review_id = review.id resp = self.api.delete(review) self.assert200(resp) review = all_models.Review.query.get(review_id) control = all_models.Control.query.get(control_id) self.assertIsNone(review) self.assertEquals(0, len(control.related_objects(_types=["Review"]))) def test_last_reviewed(self): """last_reviewed_by, last_reviewed_by should be set if reviewed""" control = factories.ControlFactory() resp, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": control.type, "id": control.id, }, "context": None, "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl(), "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE }, ) review_id = review.id resp = self.api.put( review, { "status": all_models.Review.STATES.REVIEWED, }, ) self.assert200(resp) self.assertIsNotNone(resp.json["review"]["last_reviewed_by"]) self.assertIsNotNone(resp.json["review"]["last_reviewed_at"]) review = all_models.Review.query.get(review_id) self.assertIsNotNone(review.last_reviewed_by) self.assertIsNotNone(review.last_reviewed_at) def test_reviewable_revisions(self): """Check that proper revisions are created""" control = factories.ControlFactory() resp, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": control.type, "id": control.id, }, "context": None, "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl(), "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE }, ) control_id = control.id reviewable = review.reviewable control_revisions = all_models.Revision.query.filter_by( resource_id=control_id, resource_type=control.type ).order_by( all_models.Revision.id, ).all() self.assertEquals(2, len(control_revisions)) self.assertEquals(all_models.Review.STATES.UNREVIEWED, control_revisions[0].content["review_status"]) self.assertEquals(all_models.Review.STATES.UNREVIEWED, control_revisions[1].content["review_status"]) resp = self.api.put( review, { "status": all_models.Review.STATES.REVIEWED, }, ) self.assert200(resp) control_revisions = all_models.Revision.query.filter_by( resource_id=control_id, resource_type=control.type ).order_by( all_models.Revision.id, ).all() self.assertEquals(3, len(control_revisions)) self.assertEquals(all_models.Review.STATES.REVIEWED, control_revisions[2].content["review_status"]) resp = self.api.put( reviewable, { "description": "some new description" } ) self.assert200(resp) control_revisions = all_models.Revision.query.filter_by( resource_id=control_id, resource_type=control.type ).order_by( all_models.Revision.id, ).all() self.assertEquals(4, len(control_revisions)) self.assertEquals(all_models.Review.STATES.UNREVIEWED, control_revisions[3].content["review_status"])
class TestAuditRBAC(TestCase): """Test audit RBAC""" CSV_DIR = join(abspath(dirname(__file__)), "test_csvs") @classmethod def setUpClass(cls): """Base setup for entire test suite.""" TestCase.clear_data() cls.response = cls._import_file("audit_rbac.csv") cls.people = all_models.Person.eager_query().all() cls.audit = all_models.Audit.eager_query().first() sources = set(r.source for r in cls.audit.related_sources) destinations = set(r.destination for r in cls.audit.related_destinations) related = [ obj for obj in sources.union(destinations) if not isinstance(obj, all_models.Person) ] cls.related_objects = related def setUp(self): """Imports test_csvs/audit_rbac.csv needed by the tests""" self._check_csv_response(self.response, {}) self.api = Api() self.client.get("/login") def read(self, objects): """Attempt to do a GET request for every object in the objects list""" responses = [] for obj in objects: status_code = self.api.get(obj.__class__, obj.id).status_code responses.append((obj.type, status_code)) return responses def update(self, objects): """Attempt to do a PUT request for every object in the objects list""" responses = [] for obj in objects: response = self.api.get(obj.__class__, obj.id) status_code = response.status_code if response.status_code == 200: status_code = self.api.put(obj, response.json).status_code responses.append((obj.type, status_code)) return responses def call_api(self, method, expected_statuses): """Calls the REST api with a given method and returns a list of status_codes that do not match the expected_statuses dict""" all_errors = [] for person in self.people: self.api.set_user(person) responses = method(self.related_objects + [self.audit]) for type_, code in responses: if code != expected_statuses[person.email]: all_errors.append( "{} does not have {} access to {} ({})".format( person.email, method.__name__, type_, code)) return all_errors def test_read_access_on_mapped(self): """Test if people have read access to mapped objects. All users except [email protected] should have read access.""" expected_statuses = defaultdict(lambda: 200) for exception in ("*****@*****.**", ): expected_statuses[exception] = 403 errors = self.call_api(self.read, expected_statuses) assert not errors, "\n".join(errors) def test_update_access_on_mapped(self): """Test if people have upate access to mapped objects. All users except [email protected], [email protected], [email protected], [email protected] should have update access.""" expected_statuses = defaultdict(lambda: 200) for exception in ("*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**"): expected_statuses[exception] = 403 errors = self.call_api(self.update, expected_statuses) assert not errors, "\n".join(errors)
class TestPermissionsOnAssessmentTemplate(TestCase): """ Test check permissions for ProgramEditor on get and post assessment_temaplte action""" @classmethod def _get_assessment_template_base(cls, title, audit): return { "title": title, "_NON_RELEVANT_OBJ_TYPES": {}, "_objectTypes": {}, "audit": { "id": audit.id }, "audit_title": audit.title, "people_value": [], "default_people": { "assignees": "Admin", "verifiers": "Admin", }, "context": { "id": audit.context.id }, } def setUp(self): super(TestPermissionsOnAssessmentTemplate, self).setUp() self.api = Api() editor = all_models.AccessControlRole.query.filter( all_models.AccessControlRole.name == "Program Editors").one() self.generator = ObjectGenerator() _, self.editor = self.generator.generate_person(user_role="Creator") _, program = self.generator.generate_object( all_models.Program, { "access_control_list": [acl_helper.get_acl_json(editor.id, self.editor.id)] }) program_id = program.id _, audit = self.generator.generate_object( all_models.Audit, { "title": "Assessment Template test Audit", "program": { "id": program_id }, "status": "Planned" }, ) audit_id = audit.id generated_at = self.generator.generate_object( all_models.AssessmentTemplate, self._get_assessment_template_base("Template", audit)) self.assessment_template_resp, assessment_template = generated_at assessment_template_id = assessment_template.id self.api.set_user(self.editor) self.perms_data = self.api.client.get("/permissions").json self.audit = all_models.Audit.query.get(audit_id) self.assessment_template = all_models.AssessmentTemplate.query.get( assessment_template_id) def test_post_action(self): """Test create action on AssessmentTemplate created by api""" data = [{ "assessment_template": self._get_assessment_template_base("123", self.audit) }] self.api.set_user(self.editor) resp = self.api.post(all_models.AssessmentTemplate, data) self.assert200(resp) def test_get_action(self): """Test read action on AssessmentTemplate created by api""" resp = self.api.get(all_models.AssessmentTemplate, self.assessment_template.id) self.assert200(resp) def test_put_action(self): """Test update action on AssessmentTemplate created by api""" to_update = copy.deepcopy(self.assessment_template_resp.json) new_title = "new_{}".format(self.assessment_template.title) to_update['assessment_template']['title'] = new_title resp = self.api.put(self.assessment_template, to_update) self.assert200(resp) assessment_tmpl = all_models.AssessmentTemplate.query.get( self.assessment_template.id) self.assertEqual(new_title, assessment_tmpl.title) def test_delete_action(self): """Test delete action on AssessmentTemplate created by api""" resp = self.api.delete(self.assessment_template) self.assert200(resp) self.assertFalse( all_models.AssessmentTemplate.query.filter( all_models.AssessmentTemplate == self.assessment_template.id).all())
class TestPermissions(TestCase): """Test checks permissions for proposals.""" def setUp(self): super(TestPermissions, self).setUp() self.api = Api() roles = {r.name: r for r in all_models.Role.query.all()} factories.AccessControlRoleFactory( name="ACL_Reader", object_type="Risk", update=0 ) factories.AccessControlRoleFactory( name="ACL_Editor", object_type="Risk" ) factories.AccessControlRoleFactory( name="ACL_Nobody", object_type="Risk", read=0, update=0, delete=0, ) with factories.single_commit(): self.risk = factories.RiskFactory() self.program = factories.ProgramFactory() self.program.context.related_object = self.program self.relationship = factories.RelationshipFactory( source=self.program, destination=self.risk, context=self.program.context, ) self.people = { "Creator": factories.PersonFactory(), "Reader": factories.PersonFactory(), "Editor": factories.PersonFactory(), "Administrator": factories.PersonFactory(), "ACL_Reader": factories.PersonFactory(), "ACL_Editor": factories.PersonFactory(), "ACL_Nobody": factories.PersonFactory(), "Program Editors": factories.PersonFactory(), "Program Managers": factories.PersonFactory(), "Program Readers": factories.PersonFactory(), } for role_name in ["Creator", "Reader", "Editor", "Administrator"]: rbac_factories.UserRoleFactory(role=roles[role_name], person=self.people[role_name]) for role_name in ["Program Editors", "Program Managers", "Program Readers"]: person = self.people[role_name] rbac_factories.UserRoleFactory(role=roles["Creator"], person=person) factories.AccessControlPersonFactory( ac_list=self.program.acr_name_acl_map[role_name], person=person, ) self.proposal = factories.ProposalFactory( instance=self.risk, content={ "access_control_list": {}, "custom_attribute_values": {}, "fields": {}, "mapping_fields": {}, "mapping_list_fields": {}, } ) factories.RelationshipFactory( source=self.risk, destination=self.proposal, ) for role_name in ["ACL_Reader", "ACL_Editor", "ACL_Nobody"]: person = self.people[role_name] rbac_factories.UserRoleFactory(role=roles["Creator"], person=person) factories.AccessControlPersonFactory( ac_list=self.risk.acr_name_acl_map[role_name], person=person, ) @ddt.data( ("Creator", 403), ("Reader", 200), ("Editor", 200), ("ACL_Reader", 200), ("ACL_Editor", 200), ("ACL_Nobody", 403), ("Administrator", 200), ("Program Editors", 200), ("Program Managers", 200), ("Program Readers", 200), ) @ddt.unpack def test_permissions_on_get(self, role_name, status): """Test get proposals for {0}.""" proposal_id = self.proposal.id self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api.get(all_models.Proposal, proposal_id) self.assertEqual(status, resp.status_code) def api_proposal_status_change(self, proposal_id, status): return self.api.put(all_models.Proposal.query.get(proposal_id), {"status": status}) @ddt.data( ("Creator", 403), ("Reader", 403), ("Editor", 200), ("Administrator", 200), ("ACL_Reader", 403), ("ACL_Editor", 200), ("ACL_Nobody", 403), ("Program Editors", 200), ("Program Managers", 200), ("Program Readers", 403) ) @ddt.unpack def test_permissions_on_apply(self, role_name, status): """Test apply proposals for {0}.""" proposal_id = self.proposal.id self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api_proposal_status_change(proposal_id, all_models.Proposal.STATES.APPLIED) self.assertEqual(status, resp.status_code) @ddt.data( ("Creator", 403), ("Reader", 403), ("Editor", 200), ("ACL_Reader", 403), ("ACL_Editor", 200), ("ACL_Nobody", 403), ("Administrator", 200), ("Program Editors", 200), ("Program Managers", 200), ("Program Readers", 403), ) @ddt.unpack def test_permissions_on_decline(self, role_name, status): """Test decline proposals for {0}.""" proposal_id = self.proposal.id self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api_proposal_status_change(proposal_id, all_models.Proposal.STATES.DECLINED) self.assertEqual(status, resp.status_code) @ddt.data( ("Creator", 403), ("Reader", 201), ("Editor", 201), ("ACL_Reader", 201), ("ACL_Editor", 201), ("ACL_Nobody", 403), ("Administrator", 201), ("Program Editors", 201), ("Program Managers", 201), ("Program Readers", 201), ) @ddt.unpack def test_permissions_on_create(self, role_name, status): """Test create proposal for {0}.""" data = { "proposal": { "instance": { "id": self.risk.id, "type": self.risk.type, }, "full_instance_content": {"title": "new_title"}, "agenda": "update cav", "context": None, } } self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api.post(all_models.Proposal, data) self.assertEqual(status, resp.status_code) @ddt.data( ("Creator", 0), ("Reader", 1), ("Editor", 1), # Following two tests have been commented out as the functionality for # custom role propagation has been temporarily removed This test should # be enabled back in scope of ticket GGRC-4991 # ("ACL_Reader", 1), # ("ACL_Editor", 1), ("ACL_Nobody", 0), ("Administrator", 1), ("Program Editors", 1), ("Program Managers", 1), ("Program Readers", 1), ) @ddt.unpack def test_query_filter(self, role_name, expected_count): """Test query proposals for {0}. Args: role_name: string, unique key, shows the position of user in generated infrustructure expected_count: int, number of proposals, that should be filtered by query """ risk_id = self.risk.id data = [{ "limit": [0, 5], "object_name": all_models.Proposal.__name__, "order_by":[ {"name": "status", "desc": True}, {"name": "created_at", "desc": True}, ], "filters": { "expression": { "left": { "left": "instance_type", "op": {"name": "="}, "right": self.risk.type, }, "op": {"name": "AND"}, "right": { "left": "instance_id", "op": {"name": "="}, "right": risk_id, }, }, }, }] self.api.set_user(self.people[role_name]) self.client.get("/login") headers = {"Content-Type": "application/json", } resp = self.api.client.post("/query", data=json.dumps(data), headers=headers).json self.assertEqual(1, len(resp)) self.assertEqual(expected_count, resp[0]["Proposal"]["count"])
class TestAccessControlList(TestCase): """TestAccessControlList""" def setUp(self): super(TestAccessControlList, self).setUp() self.api = Api() self.person = factories.PersonFactory(name="My Person") self.control = factories.ControlFactory() self.acr = factories.AccessControlRoleFactory( object_type="Control", read=True ) self.second_acr = factories.AccessControlRoleFactory( object_type="Control", read=True ) self.acl = factories.AccessControlListFactory( object=self.control, ac_role_id=self.acr.id, person=self.person ) def _post_control(self, id_, person_id, collection=False): """Helper function for posting a control""" title = random_str(prefix="Control - ") control = { "control": { "title": title, "type": "Control", "context": None, "access_control_list": [ _acl_json(id_, person_id) ] }, } response = self.api.post( all_models.Control, [control] if collection else control) assert response.status_code == 200 or response.status_code == 201, \ "Control with acl not created successfully {}".format(response.status) if collection: return response.json[0][1] return response.json def test_object_roles(self): """Test if roles are fetched with the object""" id_, person_id = self.acr.id, self.person.id response = self.api.get(all_models.Control, self.control.id) assert response.status_code == 200, \ "Failed to fetch created control {}".format(response.status) assert "access_control_list" in response.json["control"], \ "Access Control List not a property in {}".format( response.json["control"].keys()) ac_list = response.json["control"]["access_control_list"] assert len(ac_list) == 1, "{}".format(len(ac_list)) assert ac_list[0]["ac_role_id"] == id_, \ "ac_role_id not properly set {}".format(ac_list[0].get("ac_role_id")) assert ac_list[0]["person"]["id"] == person_id, \ "Person stub not properly set {}".format(ac_list[0]["person"]) def test_post_object_roles(self): """Test if roles are stored correctly when POSTed with the object""" id_, person_id = self.acr.id, self.person.id response = self._post_control(id_, person_id) acl = response["control"]["access_control_list"] _acl_asserts(acl, id_, person_id) def test_acl_revision_content(self): """Test if the access control list is added to revisions""" id_, person_id = self.acr.id, self.person.id response = self._post_control(id_, person_id) control_id = response["control"]["id"] rev = all_models.Revision.query.filter( all_models.Revision.resource_id == control_id, all_models.Revision.resource_type == "Control" ).first() acl = rev.content["access_control_list"] _acl_asserts(acl, id_, person_id) def test_put_object_roles(self): """Test if PUTing object roles saves them correctly""" id_2, person_id = self.second_acr.id, self.person.id response = self.api.get(all_models.Control, self.control.id) assert response.status_code == 200, \ "Failed to fetch created control {}".format(response.status) control = response.json['control'] control['access_control_list'].append(_acl_json(id_2, person_id)) response = self.api.put(self.control, {"control": control}) assert response.status_code == 200, \ "PUTing control failed {}".format(response.status) acl = response.json['control']['access_control_list'] assert len(acl) == 2, \ "Access control list not correctly updated {}".format(acl) def test_put_removing_roles(self): """Test if PUTing an empty list removes object roles correct""" response = self.api.get(all_models.Control, self.control.id) assert response.status_code == 200, \ "Failed to fetch created control {}".format(response.status) control = response.json['control'] control['access_control_list'] = [] response = self.api.put(self.control, {"control": control}) assert response.status_code == 200, \ "PUTing control failed {}".format(response.status) acl = response.json['control']['access_control_list'] assert len(acl) == 0, \ "Access control list not empty {}".format(acl) def test_acl_indexing_on_post(self): """Test if roles are stored correctly when POSTed with the object""" id_, person_id = self.acr.id, self.person.id response = self._post_control(id_, person_id, True) control = response["control"] res = mysql.MysqlRecordProperty.query.filter( mysql.MysqlRecordProperty.type == "Control", mysql.MysqlRecordProperty.key == control["id"], mysql.MysqlRecordProperty.property == self.acr.name ).all() assert len(res) > 0, \ "Full text record index not created for {}".format(self.acr.name) # email is presented in __sort__ subproperty as well assert len([r for r in res if r.content == self.person.email]) == 2, \ "Person email not indexed {}".format(self.person.email) assert len([r for r in res if r.content == self.person.name]) == 1, \ "Person name not indexed {}".format(self.person.name) def test_acl_revision_count(self): """Test if acl revision is created when object POSTed and PUTed""" id_, person_id = self.acr.id, self.person.id response = self._post_control(id_, person_id) # One ACL and Control created in setUp and on by POST self.assertEqual( all_models.Revision.query.filter_by( resource_type="AccessControlList" ).count(), 2 ) self.assertEqual( all_models.Revision.query.filter_by( resource_type="Control" ).count(), 2 ) # If content of "access_control_list" is changed, # new revision should be created for ACL control = response["control"] control["access_control_list"] = [] self.api.put( all_models.Control.query.get(control["id"]), {"control": control} ) self.assertEqual( all_models.Revision.query.filter_by( resource_type="AccessControlList" ).count(), 3 ) self.assertEqual( all_models.Revision.query.filter_by( resource_type="Control" ).count(), 3 )
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator"), ("creator", "Creator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user self.users["external"] = self.object_generator.generate_person( data={"email": "*****@*****.**"})[1] def test_admin_page_access(self): """Only admin can use admin requirement""" for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "System", "Process", "Project", "AccessGroup", "Metric", "TechnologyEnvironment", "ProductGroup", "KeyReport", "AccountBalance", ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response, _ = self.object_generator.generate_object( model, data={ table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # only for Document "contact": { "type": "Person", "id": self.users["reader"].id, } }, } ) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)".format( model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": {"title": "reader Policy", "context": None}, }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, first_regulation = self.object_generator.generate_object( all_models.Regulation, data={"regulation": {"title": "Test regulation", "context": None}} ) _, second_regulation = self.object_generator.generate_object( all_models.Regulation, data={"regulation": {"title": "Test regulation 2", "context": None}} ) response, rel = self.object_generator.generate_relationship( first_regulation, second_regulation ) self.assertStatus(response, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, rel.id) self.assert200(response) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): """Check if reader can't create mappings""" self.object_generator.api.set_user(self.users["external"]) _, control = self.object_generator.generate_object( all_models.Control, data={"control": {"title": "Test Control", "context": None}} ) self.object_generator.api.set_user(self.users['reader']) _, program = self.object_generator.generate_object( all_models.Program, data={"program": {"title": "Test Program", "context": None}} ) response, _ = self.object_generator.generate_relationship( control, program, program.context ) self.assert403(response) @ddt.data("creator", "reader") def test_unmap_people(self, user_role): """Test that global reader/creator can't unmap people from program""" user = self.users[user_role] with factories.single_commit(): program = factories.ProgramFactory() mapped_person = factories.ObjectPersonFactory( personable=program, person=user, context=program.context ) self.api.set_user(user) db.session.add(mapped_person) response = self.api.delete(mapped_person) self.assert403(response) def test_read_evidence_revision(self): """Global Read can read Evidence revision content""" user = self.users["reader"] link = "google.com" evidence = factories.EvidenceUrlFactory(link=link) evidence_id = evidence.id self.api.set_user(user) resp = self.api.client.get( "/api/revisions?resource_type={}&resource_id={}".format(evidence.type, evidence_id)) rev_content = resp.json["revisions_collection"]["revisions"][0]["content"] self.assertTrue(rev_content) self.assertEquals(link, rev_content["link"])
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) audit_id = factories.AuditFactory().id all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": self.users["creator"].id, }, "audit": { # this is ignored on everything but Issues "id": audit_id, "type": "Audit", } }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format(model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) != 0: all_errors.append( "{} can retrieve object if not owner (collection)" .format(model_singular)) continue # Become an owner response = self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": model_singular, "id": obj_id }, "context": None}}) if response.status_code != 201: all_errors.append("{} can't create owner {}.".format( model_singular, response.status)) continue # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)" .format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['creator']) response = self.api.post(all_models.Policy, { "policy": {"title": "Creator Policy", "context": None}, }) obj_id = response.json.get("policy").get("id") self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Policy", "id": obj_id, }, "context": None}}) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual( response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_creator_cannot_be_owner(self): """Test if creator cannot become owner of the object he has not created""" self.api.set_user(self.users['admin']) _, obj = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) self.api.set_user(self.users['creator']) response = self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Regulation", "id": obj.id, }, "context": None}}) self.assertEqual(response.status_code, 403) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) _, obj_1 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation 2", "context": None}, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": {"source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None}, } ) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title): return self.generator.generate(all_models.Section, "section", { "section": {"title": title, "context": None}, })[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id) ) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected ) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Section 1") obj_2 = gen("Test Section 2") self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['creator'].id, "type": "Person", }, "ownable": { "type": "Section", "id": obj_2.id, }, "context": None}}) self.api.set_user(self.users["creator"]) check(obj_1, 0) check(obj_2, 2)
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): return for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): return """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "Control", "Assessment", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Issue", "Project", "AccessGroup", "Request" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post( model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": self.users["reader"].id, }, }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)". format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): return """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": { "title": "Admin regulation", "context": None }, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": { "title": "reader Policy", "context": None }, }) obj_id = response.json.get("policy").get("id") self.api.post( all_models.ObjectOwner, { "object_owner": { "person": { "id": self.users['reader'].id, "type": "Person", }, "ownable": { "type": "Policy", "id": obj_id, }, "context": None } }) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_reader_cannot_be_owner(self): """ Test if reader cannot become owner of the object he has not created """ self.api.set_user(self.users['admin']) _, obj = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) self.api.set_user(self.users['reader']) response = self.api.post( all_models.ObjectOwner, { "object_owner": { "person": { "id": self.users['reader'].id, "type": "Person", }, "ownable": { "type": "Regulation", "id": obj.id, }, "context": None } }) self.assertEqual(response.status_code, 403) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation", "context": None }, }) _, obj_1 = self.generator.generate( all_models.Regulation, "regulation", { "regulation": { "title": "Test regulation 2", "context": None }, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None }, }) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): self.generator.api.set_user(self.users["admin"]) _, control = self.generator.generate(all_models.Control, "control", { "control": { "title": "Test Control", "context": None }, }) self.generator.api.set_user(self.users['reader']) _, program = self.generator.generate(all_models.Program, "program", { "program": { "title": "Test Program", "context": None }, }) response, _ = self.generator.generate( all_models.Relationship, "relationship", { "relationship": { "destination": { "id": program.id, "type": "Program" }, "source": { "id": control.id, "type": "Control" }, "context": { "id": program.context.id, "type": "context" } }, }) self.assertEqual(response.status_code, 403)
class TestCreatorProgram(TestCase): """Set up necessary objects and test Creator role with Program roles""" def setUp(self): super(TestCreatorProgram, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_roles() self.init_test_cases() self.objects = {} def init_test_cases(self): """ Create a dict of all possible test cases """ self.test_cases = { "notmapped": { "objects": { "program": { "get": 403, "put": 403, "delete": 403 }, "mapped_object": { "get": 403, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } }, }, "mapped": { "objects": { "program": { "get": 403, "put": 403, "delete": 403 }, "mapped_object": { "get": 403, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramReader": { "program_role": "Program Readers", "objects": { "program": { "get": 200, "put": 403, "delete": 403 }, "mapped_object": { "get": 200, "put": 403, "delete": 403 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramManager": { "program_role": "Program Managers", "objects": { "program": { "get": 200, "put": 200, "delete": 200 }, "mapped_object": { "get": 200, "put": 200, "delete": 200, }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, "ProgramEditor": { "program_role": "Program Editors", "objects": { "program": { "get": 200, "put": 200, "delete": 200 }, "mapped_object": { "get": 200, "put": 200, "delete": 200 }, "unrelated": { "get": 403, "put": 403, "delete": 403, "map": 403, } } }, } def init_roles(self): """ Create a delete request for the given object """ ac_roles = all_models.AccessControlRole.query.all() self.ac_roles = {} for ac_role in ac_roles: self.ac_roles[ac_role.name] = ac_role.id def init_users(self): """ Create users used by test cases """ users = [("creator", "Creator"), ("notmapped", "Creator"), ("mapped", "Creator"), ("ProgramReader", "Creator"), ("ProgramEditor", "Creator"), ("ProgramManager", "Creator")] self.people = {} for (name, role) in users: _, user = self.object_generator.generate_person(data={ "name": name, "email": name + "@example.com" }, user_role=role) self.people[name] = user def delete(self, obj): """ Create a delete request for the given object """ return self.api.delete(obj).status_code def get(self, obj): """ Create a get request for the given object """ return self.api.get(obj.__class__, obj.id).status_code def put(self, obj): """ Create a put request for the given object """ response = self.api.get(obj.__class__, obj.id) if response.status_code == 200: return self.api.put(obj, response.json).status_code else: return response.status_code def map(self, dest): """ Map src to dest """ response = self.api.post( all_models.Relationship, { "relationship": { "source": { "id": self.objects["program"].id, "type": self.objects["program"].type, }, "destination": { "id": dest.id, "type": dest.type }, "context": None }, }) return response.status_code def init_objects(self, test_case_name): """ Create a Program and a Mapped object for a given test case """ # Create a program test_case = self.test_cases[test_case_name] creator = self.people.get('creator') self.api.set_user(creator) random_title = factories.random_str() person = self.people.get(test_case_name) acl = [ acl_helper.get_acl_json(self.ac_roles["Program Managers"], creator.id) ] if "program_role" in test_case: ac_role_id = self.ac_roles[test_case["program_role"]] acl.append(acl_helper.get_acl_json(ac_role_id, person.id)) response = self.api.post( all_models.Program, { "program": { "title": random_title, "context": None, "access_control_list": acl }, }) self.assertEqual(response.status_code, 201, "Creator can't create program") context_id = response.json.get("program").get("context").get("id") program_id = response.json.get("program").get("id") # Use admin owner role to map it with system acr_id = all_models.AccessControlRole.query.filter_by( object_type="System", name="Admin").first().id self.objects["program"] = all_models.Program.query.get(program_id) # Create an object: for obj in ("mapped_object", "unrelated"): random_title = factories.random_str() response = self.api.post( all_models.System, { "system": { "title": random_title, "context": None, "access_control_list": [acl_helper.get_acl_json(acr_id, creator.id)], }, }) self.assertEqual(response.status_code, 201, "Creator can't create object") system_id = response.json.get("system").get("id") self.objects[obj] = all_models.System.query.get(system_id) # Map Object to Program response = self.api.post( all_models.Relationship, { "relationship": { "source": { "id": program_id, "type": "Program" }, "destination": { "id": self.objects["mapped_object"].id, "type": "System" }, "context": None }, }) self.assertEqual(response.status_code, 201, "Creator can't map object to program") # Map people to Program: if test_case_name != "notmapped": person = self.people.get(test_case_name) response = self.api.post( all_models.ObjectPerson, { "object_person": { "person": { "id": person.id, "type": "Person", "href": "/api/people/{}".format(person.id), }, "personable": { "type": "Program", "href": "/api/programs/{}".format(program_id), "id": program_id, }, "context": { "type": "Context", "id": context_id, "href": "/api/contexts/{}".format(context_id) } } }) def test_creator_program_roles(self): """ Test creator role with all program scoped roles """ # Check permissions based on test_cases: errors = [] for test_case in self.test_cases: self.init_objects(test_case) person = self.people.get(test_case) objects = self.test_cases.get(test_case).get('objects') self.api.set_user(person) for obj in ("unrelated", "mapped_object", "program"): actions = objects[obj] for action in ("map", "get", "put", "delete"): # reset sesion: db.session.commit() if action not in actions: continue func = getattr(self, action) res = func(self.objects[obj]) if res != actions[action]: errors.append( "{}: Tried {} on {}, but received {} instead of {}" .format(test_case, action, obj, res, actions[action])) # Try mapping self.assertEqual(errors, [])
class TestReader(TestCase): """Test Assignable RBAC""" def setUp(self): super(TestReader, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() self.init_assignable() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("reader", "Reader"), ("editor", "Editor"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def init_assignable(self): """Creates the assignable object used by all the tests""" self.api.set_user(self.users["editor"]) response = self.api.post( all_models.Assessment, {"assessment": { "title": "Assessment", "context": None, }}) obj_id = response.json.get("assessment").get("id") self.assertEqual(response.status_code, 201, "Error setting up Assessment") self.obj_json = response.json self.obj = all_models.Assessment.query.get(obj_id) def _post_relationship(self, user, obj_id): """Helper method for creating assignees on an object""" return self.api.post( all_models.Relationship, { "relationship": { "source": { "id": obj_id, "type": "Assessment" }, "destination": { "id": user.id, "type": "Person" }, "attrs": { "AssigneeType": "Creator" }, "context": None }, }) def test_basic_operations_with_no_assignee(self): """Editor creates an Assessment, but doesn't assign Reader/Creator as assignee. Reader should have Read access, Creator should have no access """ # Reader should have read access, but shouldn't be allowed to edit or # create another assingee self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, self.obj_json) self.assertEqual(response.status_code, 403) response = self._post_relationship(self.users["reader"], self.obj.id) self.assertEqual(response.status_code, 403) # Creator should have no access. We skip the put request because we can't # get the object etag. self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self._post_relationship(self.users["reader"], self.obj.id) self.assertEqual(response.status_code, 403) def test_basic_operations_with_assignee(self): """Test if Reader/Creator have CRUD access once they become assignees""" # Admin adds reader as an assignee self.api.set_user(self.users["admin"]) response = self._post_relationship(self.users["reader"], self.obj.id) self.assertEqual(response.status_code, 201) # Reader is now allowed to update the object self.api.set_user(self.users["reader"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) self.assertEqual(response.status_code, 200) # Reader adds creator as an assignee response = self._post_relationship(self.users["creator"], self.obj.id) self.assertEqual(response.status_code, 201) # Creator now has CRUD access self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 200) response = self.api.put(self.obj, response.json) # Creator should even be allowed to add new assignees response = self._post_relationship(self.users["admin"], self.obj.id) self.assertEqual(response.status_code, 201) def test_readability_of_mapped_objects(self): """Test if assignees get Read access on all mapped objects""" # Editor creates a System object and maps it to the assignable object self.api.set_user(self.users["editor"]) response = self.api.post( all_models.System, {"system": { "title": "System", "context": None, }}) system_id = response.json.get("system").get("id") system = all_models.System.query.get(system_id) self.api.post( all_models.Relationship, { "relationship": { "source": { "id": self.obj.id, "type": "Assessment" }, "destination": { "id": system_id, "type": "System" }, "context": None }, }) # Since creator is not an assignee she should not have access to any of the # two objects self.api.set_user(self.users["creator"]) response = self.api.get(all_models.Assessment, self.obj.id) self.assertEqual(response.status_code, 403) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 403) # Editor adds creator as an assignee self.api.set_user(self.users["editor"]) response = self._post_relationship(self.users["creator"], self.obj.id) # Creator should now have read access on the mapped object self.api.set_user(self.users["creator"]) response = self.api.get(all_models.System, system_id) self.assertEqual(response.status_code, 200) # But he should still not be allowed to update response = self.api.put(system, response.json) self.assertEqual(response.status_code, 403)
class TestCreator(TestCase): """ TestCreator """ def setUp(self): super(TestCreator, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("creator", "Creator"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): """Permissions to admin page.""" for role, code in (("creator", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_creator_can_crud(self): """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["creator"]) creator_id = self.users["creator"].id audit_id = factories.AuditFactory().id all_errors = [] base_models = set([ "Control", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Project", "AccessGroup", "Metric" ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "documents_reference_url": "ref", "link": "https://example.com", # ignored except for Document "contact": { "type": "Person", "id": creator_id, }, "audit": { # this is ignored on everything but Issues "id": audit_id, "type": "Audit", } }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue # Test GET when not owner obj_id = response.json.get(table_singular).get("id") response = self.api.get(model, obj_id) if response.status_code != 403: # we are not onwers yet all_errors.append( "{} can retrieve object if not owner".format(model_singular)) continue response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if collection: all_errors.append( "{} can retrieve object if not owner (collection)" .format(model_singular)) continue # Test GET when owner acr = all_models.AccessControlRole.query.filter_by( object_type=model_singular, name="Admin" ).first() factories.AccessControlListFactory( object_id=obj_id, object_type=model_singular, ac_role=acr, person_id=creator_id ) response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if not collection: all_errors.append( "{} cannot retrieve object even if owner (collection)" .format(model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_creator_search(self): """Test if creator can see the correct object while using the search api""" self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['creator']) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Policy", name="Admin" ).first().id response = self.api.post(all_models.Policy, { "policy": { "title": "Creator Policy", "context": None, "access_control_list": [ acl_helper.get_acl_json(acr_id, self.users["creator"].id)], }, }) response.json.get("policy").get("id") response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["type"], "Policy") response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual( response.json["results"]["counts"].get("Regulation"), None) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_creator_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['creator']) creator_count = self._get_count("Person") self.assertEqual(admin_count, creator_count) def test_relationships_access(self): """Check if creator cannot access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) _, obj_1 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation 2", "context": None}, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": {"source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None}, } ) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['creator']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 0) def test_revision_access(self): """Check if creator can access the right revision objects.""" def gen(title, extra_data=None): """Generates section.""" section_content = {"title": title, "context": None} if extra_data: section_content.update(**extra_data) return self.generator.generate(all_models.Section, "section", { "section": section_content })[1] def check(obj, expected): """Check that how many revisions of an object current user can see.""" response = self.api.get_query( all_models.Revision, "resource_type={}&resource_id={}".format(obj.type, obj.id) ) self.assertEqual(response.status_code, 200) self.assertEqual( len(response.json['revisions_collection']['revisions']), expected ) self.api.set_user(self.users["admin"]) obj_1 = gen("Test Section 1") self.api.set_user(self.users["creator"]) acr_id = all_models.AccessControlRole.query.filter_by( object_type="Section", name="Admin" ).first().id linked_acl = { "access_control_list": [ acl_helper.get_acl_json(acr_id, self.users["creator"].id)], } check(obj_1, 0) obj_2 = gen("Test Section 2", linked_acl) obj2_acl = obj_2.access_control_list[0] check(obj_2, 1) check(obj2_acl, 1) @ddt.data("creator", "admin") def test_count_type_in_accordion(self, glob_role): """Return count of Persons in DB for side accordion.""" self.api.set_user(self.users[glob_role]) ocordion_api_person_count_link = ( "/search?" "q=&types=Program%2CWorkflow_All%2C" "Audit%2CAssessment%2CIssue%2CRegulation%2C" "Policy%2CStandard%2CContract%2CClause%2CSection%2CControl%2C" "Objective%2CPerson%2COrgGroup%2CVendor%2CAccessGroup%2CSystem%2C" "Process%2CDataAsset%2CProduct%2CProject%2CFacility%2C" "Market%2CRisk%2CThreat&counts_only=true&" "extra_columns=Workflow_All%3DWorkflow%2C" "Workflow_Active%3DWorkflow%2CWorkflow_Draft%3D" "Workflow%2CWorkflow_Inactive%3DWorkflow&contact_id=1&" "extra_params=Workflow%3Astatus%3DActive%3BWorkflow_Active" "%3Astatus%3DActive%3BWorkflow_Inactive%3Astatus%3D" "Inactive%3BWorkflow_Draft%3Astatus%3DDraft" ) resp = self.api.client.get(ocordion_api_person_count_link) self.assertIn("Person", resp.json["results"]["counts"]) self.assertEqual(all_models.Person.query.count(), resp.json["results"]["counts"]["Person"]) @ddt.data( ("/api/revisions?resource_type={}&resource_id={}", 1), ("/api/revisions?source_type={}&source_id={}", 0), ("/api/revisions?destination_type={}&destination_id={}", 1), ) @ddt.unpack def test_changelog_access(self, link, revision_count): """Test accessing changelog under GC user who is assigned to object""" with factories.single_commit(): audit = factories.AuditFactory() asmnt = factories.AssessmentFactory(audit=audit) asmnt_id = asmnt.id factories.RelationshipFactory(source=audit, destination=asmnt) verifier_role = all_models.AccessControlRole.query.filter_by( object_type="Assessment", name="Verifiers", ).first() factories.AccessControlListFactory( person=self.users["creator"], ac_role=verifier_role, object=asmnt, ) self.api.set_user(self.users["creator"]) response = self.api.client.get(link.format("Assessment", asmnt_id)) self.assert200(response) self.assertEqual( len(response.json.get("revisions_collection", {}).get("revisions")), revision_count ) @ddt.data(all_models.ControlCategory, all_models.ControlAssertion) def test_permissions_for_categories(self, category_model): """Test get collection for {0}.""" self.api.set_user(self.users["creator"]) resp = self.api.get_collection(category_model, None) plural_name = category_model._inflector.table_plural key_name = "{}_collection".format(plural_name) self.assertIn(key_name, resp.json) self.assertIn(plural_name, resp.json[key_name]) collection = resp.json[key_name][plural_name] self.assertTrue(collection, "Collection shouldn't be empty")
class TestReader(TestCase): """ Test reader role """ def setUp(self): super(TestReader, self).setUp() self.generator = Generator() self.api = Api() self.object_generator = ObjectGenerator() self.init_users() def init_users(self): """ Init users needed by the test cases """ users = [("reader", "Reader"), ("admin", "Administrator")] self.users = {} for (name, role) in users: _, user = self.object_generator.generate_person( data={"name": name}, user_role=role) self.users[name] = user def test_admin_page_access(self): return for role, code in (("reader", 403), ("admin", 200)): self.api.set_user(self.users[role]) self.assertEqual(self.api.client.get("/admin").status_code, code) def test_reader_can_crud(self): return """ Test Basic create/read,update/delete operations """ self.api.set_user(self.users["reader"]) all_errors = [] base_models = set([ "Control", "Assessment", "DataAsset", "Contract", "Policy", "Regulation", "Standard", "Document", "Facility", "Market", "Objective", "OrgGroup", "Vendor", "Product", "Clause", "System", "Process", "Issue", "Project", "AccessGroup", ]) for model_singular in base_models: try: model = get_model(model_singular) table_singular = model._inflector.table_singular table_plural = model._inflector.table_plural # Test POST creation response = self.api.post(model, { table_singular: { "title": model_singular, "context": None, "reference_url": "ref", "contact": { "type": "Person", "id": self.users["reader"].id, }, }, }) if response.status_code != 201: all_errors.append("{} post creation failed {} {}".format( model_singular, response.status, response.data)) continue obj_id = response.json.get(table_singular).get("id") # Test GET when owner response = self.api.get(model, obj_id) if response.status_code != 200: all_errors.append("{} can't GET object {}".format( model_singular, response.status)) continue # Test GET collection when owner response = self.api.get_collection(model, obj_id) collection = response.json.get( "{}_collection".format(table_plural)).get(table_plural) if len(collection) == 0: all_errors.append( "{} cannot retrieve object even if owner (collection)".format( model_singular)) continue except: all_errors.append("{} exception thrown".format(model_singular)) raise self.assertEqual(all_errors, []) def test_reader_search(self): return """ Test if reader can see the correct object while using search api """ self.api.set_user(self.users['admin']) self.api.post(all_models.Regulation, { "regulation": {"title": "Admin regulation", "context": None}, }) self.api.set_user(self.users['reader']) response = self.api.post(all_models.Policy, { "policy": {"title": "reader Policy", "context": None}, }) obj_id = response.json.get("policy").get("id") self.api.post(all_models.ObjectOwner, {"object_owner": { "person": { "id": self.users['reader'].id, "type": "Person", }, "ownable": { "type": "Policy", "id": obj_id, }, "context": None}}) response, _ = self.api.search("Regulation,Policy") entries = response.json["results"]["entries"] self.assertEqual(len(entries), 2) response, _ = self.api.search("Regulation,Policy", counts=True) self.assertEqual(response.json["results"]["counts"]["Policy"], 1) self.assertEqual(response.json["results"]["counts"]["Regulation"], 1) def _get_count(self, obj): """ Return the number of counts for the given object from search """ response, _ = self.api.search(obj, counts=True) return response.json["results"]["counts"].get(obj) def test_reader_should_see_users(self): """ Test if creator can see all the users in the system """ self.api.set_user(self.users['admin']) admin_count = self._get_count("Person") self.api.set_user(self.users['reader']) reader_count = self._get_count("Person") self.assertEqual(admin_count, reader_count) def test_relationships_access(self): """Check if reader can access relationship objects""" self.api.set_user(self.users['admin']) _, obj_0 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation", "context": None}, }) _, obj_1 = self.generator.generate(all_models.Regulation, "regulation", { "regulation": {"title": "Test regulation 2", "context": None}, }) response, rel = self.generator.generate( all_models.Relationship, "relationship", { "relationship": {"source": { "id": obj_0.id, "type": "Regulation" }, "destination": { "id": obj_1.id, "type": "Regulation" }, "context": None}, } ) relationship_id = rel.id self.assertEqual(response.status_code, 201) self.api.set_user(self.users['reader']) response = self.api.get_collection(all_models.Relationship, relationship_id) self.assertEqual(response.status_code, 200) num = len(response.json["relationships_collection"]["relationships"]) self.assertEqual(num, 1) def test_creation_of_mappings(self): self.generator.api.set_user(self.users["admin"]) _, control = self.generator.generate(all_models.Control, "control", { "control": {"title": "Test Control", "context": None}, }) self.generator.api.set_user(self.users['reader']) _, program = self.generator.generate(all_models.Program, "program", { "program": {"title": "Test Program", "context": None}, }) response, _ = self.generator.generate( all_models.Relationship, "relationship", { "relationship": {"destination": { "id": program.id, "type": "Program" }, "source": { "id": control.id, "type": "Control" }, "context": { "id": program.context.id, "type": "context" }}, }) self.assertEqual(response.status_code, 403)
class TestAuditRBAC(TestCase): """Test audit RBAC""" # pylint: disable=too-many-instance-attributes CSV_DIR = join(abspath(dirname(__file__)), "test_csvs") def setUp(self): """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests""" TestCase.clear_data() self.api = Api() self.objgen = integration.ggrc.generator.ObjectGenerator() self.csv_files = itertools.cycle([ "audit_rbac_snapshot_create.csv", "audit_rbac_snapshot_update.csv" ]) self._import_file(next(self.csv_files)) self.people = all_models.Person.eager_query().all() self.program = db.session.query(all_models.Program).filter( all_models.Program.slug == "PMRBACPROGRAM-1" ).one() sources = set(r.source for r in self.program.related_sources) destinations = set(r.destination for r in self.program.related_destinations) related = [obj for obj in sources.union(destinations) if not isinstance(obj, all_models.Person)] self.related_objects = related self.api = Api() self.client.get("/login") self.audit = self.create_audit() self.snapshots = all_models.Snapshot.eager_query().all() self.sanity_check() def create_audit(self): """Create default audit for audit snapshot RBAC tests""" _, audit = self.objgen.generate_object(all_models.Audit, { "title": "Snapshotable audit", "program": {"id": self.program.id}, "status": "Planned", "snapshots": { "operation": "create", }, "context": { "type": "Context", "id": self.program.context_id, "href": "/api/contexts/{}".format(self.program.context_id) } }) self.add_auditors(audit) return audit def add_auditors(self, audit): """Add auditors to audits via POST user_role call""" auditor_emails = [ "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**", ] program_reader_emails = [ "*****@*****.**", ] auditor_role = db.session.query(all_models.Role).filter( all_models.Role.name == "Auditor" ).one() program_reader_role = db.session.query(all_models.Role).filter( all_models.Role.name == "ProgramReader" ).one() program = db.session.query(all_models.Program).filter( all_models.Program.slug == "PMRBACPROGRAM-1" ).one() user_roles = [ (auditor_emails, auditor_role, audit.context), (program_reader_emails, program_reader_role, program.context) ] for emails, role, context in user_roles: for email in emails: auditor = all_models.Person.query.filter( all_models.Person.email == email).one() self.objgen.generate_user_role(auditor, role, context) def update_audit(self): """Update default audit""" self._import_file(next(self.csv_files)) audit = all_models.Audit.query.filter( all_models.Audit.title == "Snapshotable audit" ).one() self.audit = audit self.api.modify_object(self.audit, { "snapshots": { "operation": "upsert" } }) def sanity_check(self): """Sanity check if the audit_rbac.csv was imported correctly""" assert len(self.people) == 21, \ "Expecting 21 people not {}.".format(len(self.people)) assert len(self.related_objects) == 19, \ "Expecting 19 objects mapped to program not {}.".format( len(self.related_objects)) assert len(self.snapshots) == 19, \ "Expecting 19 snapshots for default audit not {}.".format( len(self.snapshots)) assert all(ss.parent_id == self.audit.id for ss in self.snapshots), \ "All snapshots should be in default audit scope!" def read(self, objects): """Attempt to do a GET request for every object in the objects list""" responses = [] for obj in objects: status_code = self.api.get(obj.__class__, obj.id).status_code responses.append((obj.type, status_code)) return responses def update(self, objects): """Attempt to do a PUT request for every object in the objects list""" scope_response = self.api.get(self.audit.__class__, self.audit.id) if scope_response.status_code == 200: self.update_audit() responses = [] for obj in objects: response = self.api.get(obj.__class__, obj.id) status_code = response.status_code if response.status_code == 200: data = response.json if obj.type == "Snapshot": data.update({ "update_revision": "latest" }) put_call = self.api.put(obj, data) status_code = put_call.status_code responses.append((obj.type, status_code)) return responses def call_api(self, method, expected_statuses): """Calls the REST api with a given method and returns a list of status_codes that do not match the expected_statuses dict""" all_errors = [] for person in self.people: self.api.set_user(person) responses = method(self.snapshots + [self.audit]) for type_, code in responses: if code != expected_statuses[person.email][type_]: all_errors.append("{} does not have {} access to {} ({})".format( person.email, method.__name__, type_, code)) return all_errors def test_read_access_on_mapped(self): """Test READ access to snapshotted objects of default audit""" expected_statuses = defaultdict(lambda: defaultdict(lambda: 200)) exceptional_users = ( ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ) for user, exceptions in exceptional_users: for type_, status_code in exceptions.items(): expected_statuses[user][type_] = status_code errors = self.call_api(self.read, expected_statuses) assert not errors, "\n".join(errors) def test_update_access_on_mapped(self): """Test UPDATE access to snapshotted objects of default audit""" expected_statuses = defaultdict(lambda: defaultdict(lambda: 200)) exceptional_users = ( ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS), # Auditor roles ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS), ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS) ) for user, exceptions in exceptional_users: for type_, status_code in exceptions.items(): expected_statuses[user][type_] = status_code errors = self.call_api(self.update, expected_statuses) assert not errors, "\n".join(errors)
class TestPermissions(TestCase): """Test checks permissions for proposals.""" def setUp(self): super(TestPermissions, self).setUp() self.api = Api() roles = {r.name: r for r in all_models.Role.query.all()} ac_roles = { r.name: r for r in all_models.AccessControlRole.query.all() } with factories.single_commit(): self.control = factories.ControlFactory() acrs = { "ACL_Reader": factories.AccessControlRoleFactory(name="ACL_Reader", object_type="Control", update=0), "ACL_Editor": factories.AccessControlRoleFactory(name="ACL_Editor", object_type="Control"), "ACL_Nobody": factories.AccessControlRoleFactory( name="ACL_Nobody", object_type="Control", read=0, update=0, delete=0, ), } self.program = factories.ProgramFactory() self.program.context.related_object = self.program self.relationship = factories.RelationshipFactory( source=self.program, destination=self.control, context=self.program.context, ) self.people = { "Creator": factories.PersonFactory(), "Reader": factories.PersonFactory(), "Editor": factories.PersonFactory(), "Administrator": factories.PersonFactory(), "ACL_Reader": factories.PersonFactory(), "ACL_Editor": factories.PersonFactory(), "ACL_Nobody": factories.PersonFactory(), "Program Editors": factories.PersonFactory(), "Program Managers": factories.PersonFactory(), "Program Readers": factories.PersonFactory(), } for role_name in ["Creator", "Reader", "Editor", "Administrator"]: rbac_factories.UserRoleFactory(role=roles[role_name], person=self.people[role_name]) for role_name in [ "Program Editors", "Program Managers", "Program Readers" ]: person = self.people[role_name] rbac_factories.UserRoleFactory(role=roles["Creator"], person=person) factories.AccessControlListFactory( ac_role=ac_roles[role_name], object=self.program, person=person, ) self.proposal = factories.ProposalFactory( instance=self.control, content={ "access_control_list": {}, "custom_attribute_values": {}, "fields": {}, "mapping_fields": {}, "mapping_list_fields": {}, }) factories.RelationshipFactory( source=self.control, destination=self.proposal, ) for role_name in ["ACL_Reader", "ACL_Editor", "ACL_Nobody"]: person = self.people[role_name] rbac_factories.UserRoleFactory(role=roles["Creator"], person=person) factories.AccessControlListFactory( ac_role=acrs[role_name], object=self.control, person=person, ) @ddt.data( ("Creator", 403), ("Reader", 200), ("Editor", 200), ("ACL_Reader", 200), ("ACL_Editor", 200), ("ACL_Nobody", 403), ("Administrator", 200), ("Program Editors", 200), ("Program Managers", 200), ("Program Readers", 200), ) @ddt.unpack def test_permissions_on_get(self, role_name, status): """Test get proposals for {0}.""" proposal_id = self.proposal.id self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api.get(all_models.Proposal, proposal_id) self.assertEqual(status, resp.status_code) def api_proposal_status_change(self, proposal_id, status): return self.api.put(all_models.Proposal.query.get(proposal_id), {"proposal": { "status": status }}) @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200), ("Administrator", 200), ("ACL_Reader", 403), ("ACL_Editor", 200), ("ACL_Nobody", 403), ("Program Editors", 200), ("Program Managers", 200), ("Program Readers", 403)) @ddt.unpack def test_permissions_on_apply(self, role_name, status): """Test apply proposals for {0}.""" proposal_id = self.proposal.id self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api_proposal_status_change( proposal_id, all_models.Proposal.STATES.APPLIED) self.assertEqual(status, resp.status_code) @ddt.data( ("Creator", 403), ("Reader", 403), ("Editor", 200), ("ACL_Reader", 403), ("ACL_Editor", 200), ("ACL_Nobody", 403), ("Administrator", 200), ("Program Editors", 200), ("Program Managers", 200), ("Program Readers", 403), ) @ddt.unpack def test_permissions_on_decline(self, role_name, status): """Test decline proposals for {0}.""" proposal_id = self.proposal.id self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api_proposal_status_change( proposal_id, all_models.Proposal.STATES.DECLINED) self.assertEqual(status, resp.status_code) @ddt.data( ("Creator", 403), ("Reader", 201), ("Editor", 201), ("ACL_Reader", 201), ("ACL_Editor", 201), ("ACL_Nobody", 403), ("Administrator", 201), ("Program Editors", 201), ("Program Managers", 201), ("Program Readers", 201), ) @ddt.unpack def test_permissions_on_create(self, role_name, status): """Test create proposal for {0}.""" data = { "proposal": { "instance": { "id": self.control.id, "type": self.control.type, }, "full_instance_content": { "title": "new_title" }, "agenda": "update cav", "context": None, } } self.api.set_user(self.people[role_name]) self.client.get("/login") resp = self.api.post(all_models.Proposal, data) self.assertEqual(status, resp.status_code) @ddt.data( ("Creator", 0), ("Reader", 1), ("Editor", 1), # Following two tests have been commented out as the functionality for # custom role propagation has been temporarily removed This test should # be enabled back in scope of ticket GGRC-4991 # ("ACL_Reader", 1), # ("ACL_Editor", 1), ("ACL_Nobody", 0), ("Administrator", 1), ("Program Editors", 1), ("Program Managers", 1), ("Program Readers", 1), ) @ddt.unpack def test_query_filter(self, role_name, expected_count): """Test query proposals for {0}. Args: role_name: string, unique key, shows the position of user in generated infrustructure expected_count: int, number of proposals, that should be filtered by query """ control_id = self.control.id data = [{ "limit": [0, 5], "object_name": all_models.Proposal.__name__, "order_by": [ { "name": "status", "desc": True }, { "name": "created_at", "desc": True }, ], "filters": { "expression": { "left": { "left": "instance_type", "op": { "name": "=" }, "right": self.control.type, }, "op": { "name": "AND" }, "right": { "left": "instance_id", "op": { "name": "=" }, "right": control_id, }, }, }, }] self.api.set_user(self.people[role_name]) self.client.get("/login") headers = { "Content-Type": "application/json", } resp = self.api.client.post("/query", data=json.dumps(data), headers=headers).json self.assertEqual(1, len(resp)) self.assertEqual(expected_count, resp[0]["Proposal"]["count"])