Ejemplo n.º 1
0
class TestReader(TestCase):
    """Test that some objects cannot be deleted by anyone."""
    def setUp(self):
        TestCase.setUp(self)
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()
        self.init_objects()

    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_objects(self):
        """Creates the objects used by all the tests"""
        self.api.set_user(self.users["admin"])
        _, person = self.object_generator.generate_person()

        self.objects = [person]

    def test_undeletable_objects(self):
        """No user shoud be allowed to delete these objects."""
        for role, user in self.users.iteritems():
            self.api.set_user(user)
            for obj in self.objects:
                response = self.api.delete(obj)
                self.assertEqual(response.status_code, 403,
                                 "{} can delete {}".format(role, obj.type))
Ejemplo n.º 2
0
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)
      )
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
class TestFilteringByRequest(TestCase):
  """Test filter query by request"""

  def setUp(self):
    super(TestFilteringByRequest, self).setUp()
    self.object_generator = ObjectGenerator()
    self.api = Api()
    self.init_users()

  def init_users(self):
    """ Init users needed by the test cases """
    users = (
        ("creator", "Creator"),
        ("admin", "Administrator"),
        ("john", None),
    )
    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_no_role_users_filtering(self):
    """Test 'No Role' users filtering"""
    self.api.set_user(self.users['admin'])
    response = self.api.get_query(all_models.Person, "__no_role=true")

    self.assertEqual(response.status_code, 200)
    self.assertEqual(len(response.json['people_collection']['people']), 1)
    self.assertEqual(
        response.json['people_collection']['people'][0]['name'],
        'john'
    )
Ejemplo n.º 7
0
class TestReader(TestCase):
  """Test that some objects cannot be deleted by anyone."""

  def setUp(self):
    super(TestReader, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()
    self.init_objects()

  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_objects(self):
    """Creates the objects used by all the tests"""
    self.api.set_user(self.users["admin"])
    _, person = self.object_generator.generate_person()

    self.objects = [person]

  def test_undeletable_objects(self):
    """No user shoud be allowed to delete these objects."""
    for role, user in self.users.iteritems():
      self.api.set_user(user)
      for obj in self.objects:
        response = self.api.delete(obj)
        self.assertEqual(response.status_code, 403,
                         "{} can delete {}".format(role, obj.type))
Ejemplo n.º 8
0
class TestPermissionsLoading(TestCase):
  """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."""
    import ggrc_basic_permissions
    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()
Ejemplo n.º 9
0
class TestFilteringByRequest(TestCase):
    """Test filter query by request"""
    def setUp(self):
        super(TestFilteringByRequest, self).setUp()
        self.object_generator = ObjectGenerator()
        self.api = Api()
        self.init_users()

    def init_users(self):
        """ Init users needed by the test cases """
        users = (
            ("creator", "Creator"),
            ("admin", "Administrator"),
            ("john", None),
        )
        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_no_role_users_filtering(self):
        """Test 'No Role' users filtering"""
        self.api.set_user(self.users['admin'])
        response = self.api.get_query(all_models.Person, "__no_role=true")

        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.json['people_collection']['people']), 1)
        self.assertEqual(
            response.json['people_collection']['people'][0]['name'], 'john')
Ejemplo n.º 10
0
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))
Ejemplo n.º 11
0
class TestCollection(TestCase, WithQueryApi):
    """Test for collection assessment objects."""
    def setUp(self):
        super(TestCollection, self).setUp()
        self.client.get("/login")
        self.clear_data()
        self.expected_ids = []
        self.api = Api()
        self.generator = ObjectGenerator()
        assessments = [factories.AssessmentFactory() for _ in range(10)]
        random.shuffle(assessments)
        for idx, assessment in enumerate(assessments):
            comment = factories.CommentFactory(description=str(idx))
            factories.RelationshipFactory(source=assessment,
                                          destination=comment)
            self.expected_ids.append(assessment.id)

    @data(True, False)
    def test_order_by_test(self, desc):
        """Order by fultext attr"""
        query = self._make_query_dict("Assessment",
                                      order_by=[{
                                          "name": "comment",
                                          "desc": desc
                                      }])
        expected_ids = self.expected_ids
        if desc:
            expected_ids = expected_ids[::-1]
        results = self._get_first_result_set(query, "Assessment", "values")
        self.assertEqual(expected_ids, [i['id'] for i in results])

    @data("Assessor", "Creator", "Verifier")
    def test_delete_assessment_by_role(self, role_name):
        """Delete assessment not allowed for based on Assignee Type."""
        with factories.single_commit():
            assessment = factories.AssessmentFactory()
            context = factories.ContextFactory(related_object=assessment)
            assessment.context = context
            person = factories.PersonFactory()
            object_person_rel = factories.RelationshipFactory(
                source=assessment, destination=person)
            factories.RelationshipAttrFactory(
                relationship_id=object_person_rel.id,
                attr_name="AssigneeType",
                attr_value=role_name,
            )
        assessment_id = assessment.id
        role = all_models.Role.query.filter(
            all_models.Role.name == "Creator").first()
        self.generator.generate_user_role(person, role, context)
        self.api.set_user(person)
        assessment = all_models.Assessment.query.get(assessment_id)
        resp = self.api.delete(assessment)
        self.assert403(resp)
        self.assertTrue(
            all_models.Assessment.query.filter(
                all_models.Assessment.id == assessment_id).one())
Ejemplo n.º 12
0
class TestCollection(TestCase, WithQueryApi):

  """Test for collection assessment objects."""

  def setUp(self):
    super(TestCollection, self).setUp()
    self.client.get("/login")
    self.clear_data()
    self.expected_ids = []
    self.api = Api()
    self.generator = ObjectGenerator()
    assessments = [factories.AssessmentFactory() for _ in range(10)]
    random.shuffle(assessments)
    for idx, assessment in enumerate(assessments):
      comment = factories.CommentFactory(description=str(idx))
      factories.RelationshipFactory(source=assessment, destination=comment)
      self.expected_ids.append(assessment.id)

  @data(True, False)
  def test_order_by_test(self, desc):
    """Order by fultext attr"""
    query = self._make_query_dict(
        "Assessment", order_by=[{"name": "comment", "desc": desc}]
    )
    expected_ids = self.expected_ids
    if desc:
      expected_ids = expected_ids[::-1]
    results = self._get_first_result_set(query, "Assessment", "values")
    self.assertEqual(expected_ids, [i['id'] for i in results])

  @data("Assessor", "Creator", "Verifier")
  def test_delete_assessment_by_role(self, role_name):
    """Delete assessment not allowed for based on Assignee Type."""
    with factories.single_commit():
      assessment = factories.AssessmentFactory()
      context = factories.ContextFactory(related_object=assessment)
      assessment.context = context
      person = factories.PersonFactory()
      object_person_rel = factories.RelationshipFactory(
          source=assessment, destination=person)
      factories.RelationshipAttrFactory(
          relationship_id=object_person_rel.id,
          attr_name="AssigneeType",
          attr_value=role_name,
      )
    assessment_id = assessment.id
    role = all_models.Role.query.filter(
        all_models.Role.name == "Creator"
    ).first()
    self.generator.generate_user_role(person, role, context)
    self.api.set_user(person)
    assessment = all_models.Assessment.query.get(assessment_id)
    resp = self.api.delete(assessment)
    self.assert403(resp)
    self.assertTrue(all_models.Assessment.query.filter(
        all_models.Assessment.id == assessment_id).one())
Ejemplo n.º 13
0
class TestAccessControlRBAC(TestCase):
  """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()

  def set_up_people(self):
    """Set up people with different roles needed by the tests"""
    self.people = {}
    object_generator = ObjectGenerator()

    for name in ["Creator", "Reader", "Editor"]:
      _, user = object_generator.generate_person(
          data={"name": name}, user_role=name)
      self.people[name] = user

  def set_up_acl_object(self):
    """Set up a control with an access control role that grants RUD"""
    self.control = factories.ControlFactory()
    self.all_acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True,
        update=True,
        delete=True
    )
    for name in ["Creator", "Reader", "Editor"]:
      factories.AccessControlListFactory(
          object=self.control,
          ac_role_id=self.all_acr.id,
          person=self.people.get(name)
      )

  def test_acl_object_cru(self):
    """Test if readers/creators can CRUD an object with all permissions"""
    control_id = self.control.id
    # role_id = self.all_acr.id
    for name in ("Creator", "Reader", "Editor"):
      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_id = user.profile.id
        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(
            user.profile, {
                "people_profiles": {
                    "id": profile_id,
                    "last_seen_whats_new": new_date,
                },
            })
        self.assert200(response)

        response = self.api.delete(user.profile, profile_id)
        if name == "admin":
            self.assert200(response)
        else:
            self.assert403(response)

        res = self.api.get(all_models.PersonProfile, None)
        api_profiles = res.json["people_profiles_collection"][
            "people_profiles"]
        api_profile_id = api_profiles[0]["id"]

        if name == "admin":
            self.assertEqual(len(api_profiles), 4)
        else:
            self.assertEqual(len(api_profiles), 1)
            self.assertEqual(profile_id, api_profile_id)
Ejemplo n.º 15
0
 def send_import_request(data, dry_run=False, person=None):
   """Sending import post request."""
   headers = {
       "X-test-only": "true" if dry_run else "false",
       "X-requested-by": "GGRC",
   }
   api = Api()
   api.set_user(person)  # Ok if person is None
   response = api.client.post("/_service/import_csv",
                              data=data, headers=headers)
   return json.loads(response.data)
Ejemplo n.º 16
0
 def send_import_request(cls, data, dry_run=False, person=None):
   """Sending import post request."""
   cls.init_taskqueue()
   headers = {
       "X-test-only": "true" if dry_run else "false",
       "X-requested-by": "GGRC",
   }
   api = Api()
   api.set_user(person)  # Ok if person is None
   response = api.client.post("/_service/import_csv",
                              data=data, headers=headers)
   return json.loads(response.data)
Ejemplo n.º 17
0
  def _import_file(cls, filename, dry_run=False, person=None):
    """Function that handle sending file to import_csv service"""
    data = {"file": (open(os.path.join(cls.CSV_DIR, filename)), filename)}
    headers = {
        "X-test-only": "true" if dry_run else "false",
        "X-requested-by": "GGRC",
    }
    api = Api()
    api.set_user(person)  # Ok if person is None
    response = api.tc.post("/_service/import_csv", data=data, headers=headers)

    return json.loads(response.data)
Ejemplo n.º 18
0
 def _import_file(cls, filename, dry_run=False, person=None):
   """Function that handle sending file to import_csv service"""
   data = {"file": (open(os.path.join(cls.CSV_DIR, filename)), filename)}
   headers = {
       "X-test-only": "true" if dry_run else "false",
       "X-requested-by": "GGRC",
   }
   api = Api()
   api.set_user(person)  # Ok if person is None
   response = api.client.post("/_service/import_csv",
                              data=data, headers=headers)
   return json.loads(response.data)
class TestAccessControlRole(TestCase):
    """TestAccessControlRole"""
    def setUp(self):
        super(TestAccessControlRole, self).setUp()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.people = {}
        for name in ["Creator", "Reader", "Editor"]:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=name)
            self.people[name] = user

    def _post_role(self):
        """Helper function for POSTing roles"""
        name = random_str(prefix="Access Control Role - ")
        return self.api.post(
            AccessControlRole, {
                "access_control_role": {
                    "name": name,
                    "object_type": "Control",
                    "context": None,
                    "read": True
                },
            })

    def test_create(self):
        """Test Access Control Role creation"""
        response = self._post_role()
        assert response.status_code == 201, \
            "Failed to create a new access control role, response was {}".format(
                response.status)

        id_ = response.json['access_control_role']['id']
        role = AccessControlRole.query.filter(
            AccessControlRole.id == id_).first()
        assert role.read == 1, \
            "Read permission not correctly saved {}".format(role.read)
        assert role.update == 1, \
            "Update permission not correctly saved {}".format(role.update)
        assert role.delete == 1, \
            "Update permission not correctly saved {}".format(role.delete)

    def test_only_admin_can_post(self):
        """Only admin users should be able to POST access control roles"""
        for name in ("Creator", "Reader", "Editor"):
            person = self.people.get(name)
            self.api.set_user(person)
            response = self._post_role()
            assert response.status_code == 403, \
                "Non admins should get forbidden error when POSTing role. {}".format(
                    response.status)
Ejemplo n.º 20
0
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)
Ejemplo n.º 21
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
  """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assessor, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """
  def setUp(self):
    super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()

    _, self.reader = self.generator.generate_person(
        user_role="Reader"
    )
    audit = factories.AuditFactory()
    assessment = factories.AssessmentFactory(audit=audit)
    object_person_rel = factories.RelationshipFactory(
        source=assessment,
        destination=self.reader
    )
    factories.RelationshipAttrFactory(
        relationship_id=object_person_rel.id,
        attr_name="AssigneeType",
        attr_value="Assessor"
    )

    factories.RelationshipFactory(source=audit, destination=assessment)
    document = factories.DocumentFactory()
    document_id = document.id
    doc_rel = factories.RelationshipFactory(source=assessment,
                                            destination=document)
    doc_rel_id = doc_rel.id

    self.api.set_user(self.reader)
    self.document = all_models.Document.query.get(document_id)
    self.doc_relationship = all_models.Relationship.query.get(doc_rel_id)

  def test_delete_action(self):
    """Test permissions for delete action on Document"""
    resp = self.api.delete(self.document)
    self.assert200(resp)
    self.assertFalse(all_models.Document.query.filter(
        all_models.Document.id == self.document.id).all())

  def test_unmap_action(self):
    """Test permissions for unmap action on Document"""
    resp = self.api.delete(self.doc_relationship)
    self.assert200(resp)
    self.assertFalse(all_models.Relationship.query.filter(
        all_models.Relationship.id == self.doc_relationship.id).all())
Ejemplo n.º 22
0
class TestFilteringByRequest(TestCase):
  """Test filter query by request"""

  def setUp(self):
    super(TestFilteringByRequest, self).setUp()
    self.object_generator = ObjectGenerator()
    self.api = Api()
    self.init_users()

  def init_users(self):
    """ Init users needed by the test cases """
    users = (
        ("creator", "Creator"),
        ("admin", "Administrator"),
        ("john", "WorkflowOwner")
    )
    self.users = {}
    for (name, role) in users:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=role)
      self.users[name] = user
    context = (
        db.session.query(all_models.Context).filter(
            all_models.Context.id != 0
        ).first()
    )
    user_role = (
        db.session.query(all_models.UserRole).join(all_models.Person).
        filter(
            and_(
                all_models.UserRole.person_id == all_models.Person.id,
                all_models.Person.name == "john"
            )
        ).first()
    )
    user_role.context_id = context.id
    db.session.commit()
    db.session.flush()

  def test_no_role_users_filtering(self):
    """Test 'No Role' users filtering"""
    self.api.set_user(self.users['admin'])
    response = self.api.get_query(all_models.Person, "__no_role=true")

    self.assertEqual(response.status_code, 200)
    self.assertEqual(len(response.json['people_collection']['people']), 1)
    self.assertEqual(
        response.json['people_collection']['people'][0]['name'],
        'john'
    )
Ejemplo n.º 23
0
class TestFilteringByRequest(TestCase):
  """Test filter query by request"""

  def setUp(self):
    super(TestFilteringByRequest, self).setUp()
    self.object_generator = ObjectGenerator()
    self.api = Api()
    self.init_users()

  def init_users(self):
    """ Init users needed by the test cases """
    users = (
        ("creator", "Creator"),
        ("admin", "Administrator"),
        ("john", "WorkflowOwner")
    )
    self.users = {}
    for (name, role) in users:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=role)
      self.users[name] = user
    context = (
        db.session.query(all_models.Context).filter(
            all_models.Context.id != 0
        ).first()
    )
    user_role = (
        db.session.query(all_models.UserRole).join(all_models.Person).
        filter(
            and_(
                all_models.UserRole.person_id == all_models.Person.id,
                all_models.Person.name == "john"
            )
        ).first()
    )
    user_role.context_id = context.id
    db.session.commit()
    db.session.flush()

  def test_no_role_users_filtering(self):
    """Test 'No Role' users filtering"""
    self.api.set_user(self.users['admin'])
    response = self.api.get_query(all_models.Person, "__no_role=true")

    self.assertEqual(response.status_code, 200)
    self.assertEqual(len(response.json['people_collection']['people']), 1)
    self.assertEqual(
        response.json['people_collection']['people'][0]['name'],
        'john'
    )
Ejemplo n.º 24
0
class TestAccessControlRole(TestCase):
  """TestAccessControlRole"""

  def setUp(self):
    super(TestAccessControlRole, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.people = {}
    for name in ["Creator", "Reader", "Editor"]:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=name)
      self.people[name] = user

  def _post_role(self):
    """Helper function for POSTing roles"""
    name = random_str(prefix="Access Control Role - ")
    return self.api.post(AccessControlRole, {
        "access_control_role": {
            "name": name,
            "object_type": "Control",
            "context": None,
            "read": True
        },
    })

  def test_create(self):
    """Test Access Control Role creation"""
    response = self._post_role()
    assert response.status_code == 201, \
        "Failed to create a new access control role, response was {}".format(
            response.status)

    id_ = response.json['access_control_role']['id']
    role = AccessControlRole.query.filter(AccessControlRole.id == id_).first()
    assert role.read == 1, \
        "Read permission not correctly saved {}".format(role.read)
    assert role.update == 1, \
        "Update permission not correctly saved {}".format(role.update)
    assert role.delete == 1, \
        "Update permission not correctly saved {}".format(role.delete)

  def test_only_admin_can_post(self):
    """Only admin users should be able to POST access control roles"""
    for name in ("Creator", "Reader", "Editor"):
      person = self.people.get(name)
      self.api.set_user(person)
      response = self._post_role()
      assert response.status_code == 403, \
          "Non admins should get forbidden error when POSTing role. {}".format(
              response.status)
Ejemplo n.º 25
0
    def _import_file(cls, filename, dry_run=False, person=None):
        data = {"file": (open(join(cls.CSV_DIR, filename)), filename)}
        headers = {
            "X-test-only": "true" if dry_run else "false",
            "X-requested-by": "gGRC",
        }
        if hasattr(g, "cache"):
            delattr(g, "cache")
        api = Api()
        api.set_user(person)  # Ok if person is None
        response = api.tc.post("/_service/import_csv",
                               data=data,
                               headers=headers)

        return json.loads(response.data)
Ejemplo n.º 26
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
    """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assessor, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """
    def setUp(self):
        super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
        self.api = Api()
        self.generator = ObjectGenerator()

        _, self.reader = self.generator.generate_person(user_role="Reader")
        audit = factories.AuditFactory()
        assessment = factories.AssessmentFactory(audit=audit)
        object_person_rel = factories.RelationshipFactory(
            source=assessment, destination=self.reader)
        factories.RelationshipAttrFactory(relationship_id=object_person_rel.id,
                                          attr_name="AssigneeType",
                                          attr_value="Assessor")

        factories.RelationshipFactory(source=audit, destination=assessment)
        document = factories.DocumentFactory()
        document_id = document.id
        doc_rel = factories.RelationshipFactory(source=assessment,
                                                destination=document)
        doc_rel_id = doc_rel.id

        self.api.set_user(self.reader)
        self.document = all_models.Document.query.get(document_id)
        self.doc_relationship = all_models.Relationship.query.get(doc_rel_id)

    def test_delete_action(self):
        """Test permissions for delete action on Document"""
        resp = self.api.delete(self.document)
        self.assert200(resp)
        self.assertFalse(
            all_models.Document.query.filter(
                all_models.Document.id == self.document.id).all())

    def test_unmap_action(self):
        """Test permissions for unmap action on Document"""
        resp = self.api.delete(self.doc_relationship)
        self.assert200(resp)
        self.assertFalse(
            all_models.Relationship.query.filter(
                all_models.Relationship.id == self.doc_relationship.id).all())
Ejemplo n.º 27
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
  """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assignee, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """

  def setUp(self):
    super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()

    _, self.reader = self.generator.generate_person(
        user_role="Reader"
    )
    audit = factories.AuditFactory()
    assessment = factories.AssessmentFactory(audit=audit)
    ac_role = all_models.AccessControlRole.query.filter_by(
        object_type=assessment.type, name="Assignees"
    ).first()
    factories.AccessControlListFactory(
        ac_role=ac_role,
        object=assessment,
        person=self.reader
    )
    factories.RelationshipFactory(source=audit, destination=assessment)
    evidence = factories.EvidenceUrlFactory()
    evidence_id = evidence.id
    evid_rel = factories.RelationshipFactory(source=assessment,
                                             destination=evidence)
    evid_rel_id = evid_rel.id

    self.api.set_user(self.reader)
    self.evidence = all_models.Evidence.query.get(evidence_id)
    self.evid_relationship = all_models.Relationship.query.get(evid_rel_id)

  def test_delete_action(self):
    """Test permissions for delete action on Evidence

    Allow only Global Admin to delete Documents.
    """
    resp = self.api.delete(self.evidence)
    self.assert403(resp)
    self.assertEquals(len(all_models.Evidence.query.filter(
        all_models.Evidence.id == self.evidence.id).all()), 1)
Ejemplo n.º 28
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
  """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assignee, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """

  def setUp(self):
    super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()

    _, self.reader = self.generator.generate_person(
        user_role="Reader"
    )
    audit = factories.AuditFactory()
    assessment = factories.AssessmentFactory(audit=audit)
    factories.AccessControlPersonFactory(
        ac_list=assessment.acr_name_acl_map["Assignees"],
        person=self.reader,
    )
    factories.RelationshipFactory(source=audit, destination=assessment)
    evidence = factories.EvidenceUrlFactory()
    evidence_id = evidence.id
    evid_rel = factories.RelationshipFactory(source=assessment,
                                             destination=evidence)
    evid_rel_id = evid_rel.id

    self.api.set_user(self.reader)
    self.evidence = all_models.Evidence.query.get(evidence_id)
    self.evid_relationship = all_models.Relationship.query.get(evid_rel_id)

  def test_delete_action(self):
    """Test permissions for delete action on Evidence

    Allow only Global Admin to delete Documents.
    """
    resp = self.api.delete(self.evidence)
    self.assert200(resp)
    self.assertEquals(len(all_models.Evidence.query.filter(
        all_models.Evidence.id == self.evidence.id).all()), 0)
Ejemplo n.º 29
0
class TestCADPermissions(TestCase):
  """TestCase permissions for CAD model."""

  def setUp(self):
    super(TestCADPermissions, self).setUp()
    self.api = Api()
    self.client.get("/login")
    self.definition_type = "control"
    self.generator = generator.ObjectGenerator()
    roles = {r.name: r for r in all_models.Role.query.all()}
    with factories.single_commit():
      self.people = {
          "Creator": factories.PersonFactory(),
          "Reader": factories.PersonFactory(),
          "Editor": factories.PersonFactory(),
          "Administrator": factories.PersonFactory(),
      }
      for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
        rbac_factories.UserRoleFactory(role=roles[role_name],
                                       person=self.people[role_name])
      self.fake_cad = factories.CustomAttributeDefinitionFactory(
          definition_type=self.definition_type
      )

  @ddt.data("Creator", "Reader", "Editor", "Administrator")
  def test_get_cads(self, role):
    """Test get CADs for {}"""
    fake_cad_id = self.fake_cad.id
    filter_params = "ids={}&definition_type={}".format(
        fake_cad_id, self.fake_cad.definition_type)
    self.api.set_user(self.people[role])
    self.client.get("/login")
    resp = self.generator.api.get_query(all_models.CustomAttributeDefinition,
                                        filter_params)
    self.assert200(resp)
    cad_collection = resp.json["custom_attribute_definitions_collection"]
    resp_cad_ids = [
        i["id"] for i in cad_collection["custom_attribute_definitions"]
    ]
    self.assertEqual([self.fake_cad.id], resp_cad_ids)
Ejemplo n.º 30
0
class TestACRPermissions(TestCase):
    """TestCase permissions for ACR model."""
    def setUp(self):
        super(TestACRPermissions, self).setUp()
        self.api = Api()
        self.client.get("/login")
        self.obj_type = "Control"
        roles = {r.name: r for r in all_models.Role.query.all()}
        with factories.single_commit():
            self.people = {
                "Creator": factories.PersonFactory(),
                "Reader": factories.PersonFactory(),
                "Editor": factories.PersonFactory(),
                "Administrator": factories.PersonFactory(),
            }
            for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
                rbac_factories.UserRoleFactory(role=roles[role_name],
                                               person=self.people[role_name])
            self.fake_role = factories.AccessControlRoleFactory(
                name="ACL_Reader", object_type=self.obj_type)

    @ddt.data("Creator", "Reader", "Editor", "Administrator")
    def test_get_acr(self, role):
        """Test get access_control_roles for {}"""
        fake_role_id = self.fake_role.id
        self.api.set_user(self.people[role])
        self.client.get("/login")
        headers = {
            "Content-Type": "application/json",
        }
        resp = self.api.client.get(
            "/api/access_control_roles?object_type={}".format(self.obj_type),
            headers=headers)
        self.assert200(resp)
        self.assertIn("access_control_roles_collection", resp.json)
        acrs = resp.json["access_control_roles_collection"][
            "access_control_roles"]
        self.assertIn(fake_role_id, [i["id"] for i in acrs])
Ejemplo n.º 31
0
class TestCADPermissions(TestCase):
    """TestCase permissions for CAD model."""
    def setUp(self):
        super(TestCADPermissions, self).setUp()
        self.api = Api()
        self.client.get("/login")
        self.definition_type = "control"
        self.generator = generator.ObjectGenerator()
        roles = {r.name: r for r in all_models.Role.query.all()}
        with factories.single_commit():
            self.people = {
                "Creator": factories.PersonFactory(),
                "Reader": factories.PersonFactory(),
                "Editor": factories.PersonFactory(),
                "Administrator": factories.PersonFactory(),
            }
            for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
                rbac_factories.UserRoleFactory(role=roles[role_name],
                                               person=self.people[role_name])
            self.fake_cad = factories.CustomAttributeDefinitionFactory(
                definition_type=self.definition_type)

    @ddt.data("Creator", "Reader", "Editor", "Administrator")
    def test_get_cads(self, role):
        """Test get CADs for {}"""
        fake_cad_id = self.fake_cad.id
        filter_params = "ids={}&definition_type={}".format(
            fake_cad_id, self.fake_cad.definition_type)
        self.api.set_user(self.people[role])
        self.client.get("/login")
        resp = self.generator.api.get_query(
            all_models.CustomAttributeDefinition, filter_params)
        self.assert200(resp)
        cad_collection = resp.json["custom_attribute_definitions_collection"]
        resp_cad_ids = [
            i["id"] for i in cad_collection["custom_attribute_definitions"]
        ]
        self.assertEqual([self.fake_cad.id], resp_cad_ids)
Ejemplo n.º 32
0
class TestACRPermissions(TestCase):
  """TestCase permissions for ACR model."""

  def setUp(self):
    super(TestACRPermissions, self).setUp()
    self.api = Api()
    self.client.get("/login")
    self.obj_type = "Control"
    roles = {r.name: r for r in all_models.Role.query.all()}
    with factories.single_commit():
      self.people = {
          "Creator": factories.PersonFactory(),
          "Reader": factories.PersonFactory(),
          "Editor": factories.PersonFactory(),
          "Administrator": factories.PersonFactory(),
      }
      for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
        rbac_factories.UserRoleFactory(role=roles[role_name],
                                       person=self.people[role_name])
      self.fake_role = factories.AccessControlRoleFactory(
          name="ACL_Reader",
          object_type=self.obj_type)

  @ddt.data("Creator", "Reader", "Editor", "Administrator")
  def test_get_acr(self, role):
    """Test get access_control_roles for {}"""
    fake_role_id = self.fake_role.id
    self.api.set_user(self.people[role])
    self.client.get("/login")
    headers = {"Content-Type": "application/json", }
    resp = self.api.client.get(
        "/api/access_control_roles?object_type={}".format(self.obj_type),
        headers=headers)
    self.assert200(resp)
    self.assertIn("access_control_roles_collection", resp.json)
    acrs = resp.json["access_control_roles_collection"]["access_control_roles"]
    self.assertIn(fake_role_id, [i["id"] for i in acrs])
Ejemplo n.º 33
0
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 = {
            "Control", "DataAsset", "Contract", "Policy", "Regulation",
            "Standard", "Document", "Facility", "Market", "Objective",
            "OrgGroup", "Vendor", "Product", "Clause", "System", "Process",
            "Project", "AccessGroup", "Metric", "ProductGroup",
            "TechnologyEnvironment"
        }
        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 requirement."""
            requirement_content = {"title": title, "context": None}
            if extra_data:
                requirement_content.update(**extra_data)
            return self.generator.generate(
                all_models.Requirement, "requirement",
                {"requirement": requirement_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 Requirement 1")

        self.api.set_user(self.users["creator"])
        acr_id = all_models.AccessControlRole.query.filter_by(
            object_type="Requirement", 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 Requirement 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%2CRequirement%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")
Ejemplo n.º 34
0
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, [])
Ejemplo n.º 35
0
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": 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": {
                            "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, [])
Ejemplo n.º 36
0
class TestFilterByAuditor(TestCase):
  """ Test for filter by Auditor. """

  def setUp(self):
    super(TestFilterByAuditor, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()
    _, self.auditor = self.generator.generate_person(user_role="Creator")
    auditor_role = all_models.AccessControlRole.query.filter_by(
        name="Auditors").one()
    with factories.single_commit():
      self.audit = factories.AuditFactory(status="In Progress")
      self.audit_id = self.audit.id
      audit_context = factories.ContextFactory()
      self.audit.context = audit_context
      factories.AccessControlListFactory(
          ac_role=auditor_role,
          object=self.audit,
          person=self.auditor
      )
    self.api.set_user(self.auditor)

  def test_query_audits_by_auditor(self):
    """test get audit as query get"""
    objects = self.api.get_query(all_models.Audit, "")
    self.assertEqual(1, len(objects.json["audits_collection"]["audits"]))
    audit_dict = objects.json["audits_collection"]["audits"][0]
    self.assertEqual(self.audit_id, audit_dict["id"])

  def test_filter_audits_by_auditor(self):
    """Test query on audit Global Search.

    This query is the fact query that frontend is sending in global search.
    """
    query_request_data = [
        {
            u'fields': [],
            u'filters': {
                u'expression': {
                    u'left': {
                        u'left': u'status',
                        u'op': {u'name': u'='},
                        u'right': u'Planned'
                    },
                    u'op': {u'name': u'OR'},
                    u'right': {
                        u'left': {
                            u'left': u'status',
                            u'op': {u'name': u'='},
                            u'right': u'In Progress'
                        },
                        u'op': {u'name': u'OR'},
                        u'right': {
                            u'left': {
                                u'left': u'status',
                                u'op': {u'name': u'='},
                                u'right': u'Manager Review'
                            },
                            u'op': {u'name': u'OR'},
                            u'right': {
                                u'left': {
                                    u'left': u'status',
                                    u'op': {u'name': u'='},
                                    u'right': u'Ready for External Review',
                                },
                                u'op': {u'name': u'OR'},
                                u'right': {
                                    u'left': u'status',
                                    u'op': {u'name': u'='},
                                    u'right': u'Completed',
                                }
                            },
                        },
                    },
                },
                u'keys': [u'status'],
                u'order_by': {
                    u'compare': None,
                    u'keys': [],
                    u'order': u'',
                }
            },
            u'limit': [0, 5],
            u'object_name': u'Audit',
            u'permissions': u'read',
            u'type': u'values',
        },
        {
            u'filters': {
                u'expression': {
                    u'ids': [u'150'],
                    u'object_name': u'undefined',
                    u'op': {u'name': u'relevant'}
                },
                u'keys': [],
                u'order_by': {u'compare': None, u'keys': [], u'order': u''}
            },
            u'object_name': u'Audit',
            u'type': u'ids',
        },
    ]
    resp = self.api.send_request(self.api.client.post,
                                 data=query_request_data,
                                 api_link="/query")
    self.assertEqual(1, resp.json[0]["Audit"]["count"])
    self.assertEqual(self.audit_id, resp.json[0]["Audit"]["values"][0]["id"])
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)
Ejemplo n.º 38
0
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": {},
                })
            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)
        with factories.single_commit():
            proposal_model.set_acl_to_all_proposals_for(self.control)

    @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),
        ("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"])
Ejemplo n.º 39
0
class TestIssueIntegration(ggrc.TestCase):
    """Test set for IssueTracker integration functionality."""
    DEFAULT_ISSUE_ATTRS = {
        "title": "title1",
        "context": None,
        "status": "Draft",
        "enabled": True,
        "component_id": 1234,
        "hotlist_id": 4321,
        "issue_id": TICKET_ID,
        "issue_type": "Default Issue Type",
        "issue_priority": "P2",
        "issue_severity": "S1",
    }

    DEFAULT_TICKET_ATTRS = {
        "component_id": 1234,
        "hotlist_id": 4321,
        "issue_id": TICKET_ID,
        "status": "new",
        "issue_type": "Default Issue type",
        "issue_priority": "P1",
        "issue_severity": "S2",
        "title": "test title",
        "verifier": "*****@*****.**",
        "assignee": "*****@*****.**",
        "ccs": ["*****@*****.**"],
    }

    # pylint: disable=invalid-name

    def setUp(self):
        # pylint: disable=super-on-old-class
        super(TestIssueIntegration, self).setUp()
        self.api = Api()
        self.client.get("/login")

    @mock.patch("ggrc.integrations.issues.Client.create_issue",
                return_value={"issueId": "issueId"})
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_create_issue_tracker_info(self, mock_create_issue):
        """Test creation issue tracker issue for Issue object."""
        component_id = "1234"
        hotlist_id = "4321"
        issue_type = "Default Issue type"
        issue_priority = "P2"
        issue_severity = "S1"
        title = "test title"

        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": title,
                        "context": None,
                        "issue_tracker": {
                            "enabled": True,
                            "component_id": int(component_id),
                            "hotlist_id": int(hotlist_id),
                            "issue_type": issue_type,
                            "issue_priority": issue_priority,
                            "issue_severity": issue_severity,
                        }
                    },
                })
            mock_create_issue.assert_called_once()
            self.assertEqual(response.status_code, 201)
            issue_id = response.json.get("issue").get("id")
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertTrue(issue_tracker_issue.enabled)
            self.assertEqual(issue_tracker_issue.title, title)
            self.assertEqual(issue_tracker_issue.component_id, component_id)
            self.assertEqual(issue_tracker_issue.hotlist_id, hotlist_id)
            self.assertEqual(issue_tracker_issue.issue_type, issue_type)
            self.assertEqual(issue_tracker_issue.issue_priority,
                             issue_priority)
            self.assertEqual(issue_tracker_issue.issue_severity,
                             issue_severity)

    def test_exclude_auditor(self):
        """Test 'exclude_auditor_emails' util."""
        audit = factories.AuditFactory()
        person = factories.PersonFactory(email="*****@*****.**")
        audit.add_person_with_role_name(person, "Auditors")
        db.session.commit()

        result = integration_utils.exclude_auditor_emails(
            ["*****@*****.**", "*****@*****.**"])
        self.assertEqual(result, {
            "*****@*****.**",
        })

    @ddt.data(
        ({
            "description": "new description"
        }, {
            "comment": "Issue Description has been updated.\nnew description"
        }),
        ({
            "test_plan": "new test plan"
        }, {
            "comment":
            "Issue Remediation Plan has been updated.\nnew test plan"
        }),
        ({
            "issue_tracker": {
                "component_id": "123",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "component_id": 123
        }),
        ({
            "issue_tracker": {
                "hotlist_id": "321",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "hotlist_ids": [
                321,
            ]
        }),
        ({
            "issue_tracker": {
                "issue_priority": "P2",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "priority": "P2"
        }),
        ({
            "issue_tracker": {
                "issue_severity": "S2",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "severity": "S2"
        }),
        ({
            "issue_tracker": {
                "enabled": False,
                "hotlist_ids": [
                    999,
                ],
                "issue_id": TICKET_ID
            }
        }, {
            "comment":
            "Changes to this GGRC object will no longer be "
            "tracked within this bug."
        }),
        ({
            "issue_tracker": {
                "title": "test_iti_title",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "title": "test_iti_title"
        }),
    )
    @ddt.unpack
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue(self, issue_attrs, expected_query,
                          mock_update_issue):
        """Test updating issue tracker issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())

        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_called_with(iti.issue_id, expected_query)

    @ddt.data(
        {"notes": "new notes"},
        {"end_date": "2018-07-15"},
        {"start_date": "2018-07-15"},
    )
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue_with_untracked_fields(self, issue_attrs,
                                                mock_update_issue):
        """Test updating issue with fields which shouldn't be sync."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_not_called()

    def request_payload_builder(self, issue_attrs):
        """Build payload for POST request to Issue Tracker"""
        payload_attrs = dict(self.DEFAULT_ISSUE_ATTRS, **issue_attrs)
        payload = {
            "issue": {
                "title": payload_attrs["title"],
                "context": payload_attrs["context"],
                "status": payload_attrs["status"],
                "issue_tracker": {
                    "enabled": payload_attrs["enabled"],
                    "component_id": payload_attrs["component_id"],
                    "hotlist_id": payload_attrs["hotlist_id"],
                    "issue_id": payload_attrs["issue_id"],
                    "issue_type": payload_attrs["issue_type"],
                    "issue_priority": payload_attrs["issue_priority"],
                    "issue_severity": payload_attrs["issue_severity"],
                    "title": payload_attrs["title"],
                }
            }
        }
        return payload

    def put_request_payload_builder(self, issue_attrs):
        """Build payload for PUT request to Issue Tracker"""
        payload_attrs = dict(self.DEFAULT_ISSUE_ATTRS, **issue_attrs)
        payload = {
            "issue_tracker": {
                "enabled": payload_attrs["enabled"],
                "component_id": payload_attrs["component_id"],
                "hotlist_id": payload_attrs["hotlist_id"],
                "issue_id": payload_attrs["issue_id"],
                "issue_type": payload_attrs["issue_type"],
                "issue_priority": payload_attrs["issue_priority"],
                "issue_severity": payload_attrs["issue_severity"],
                "title": payload_attrs["title"],
            }
        }
        return payload

    def response_payload_builder(self, ticket_attrs):
        """Build payload for response from Issue Tracker via get_issue method"""
        payload_attrs = dict(self.DEFAULT_TICKET_ATTRS, **ticket_attrs)
        payload = {
            "issueState": {
                "component_id": payload_attrs["component_id"],
                "hotlist_id": payload_attrs["hotlist_id"],
                "issue_id": payload_attrs["issue_id"],
                "status": payload_attrs["status"],
                "issue_type": payload_attrs["issue_type"],
                "issue_priority": payload_attrs["issue_priority"],
                "issue_severity": payload_attrs["issue_severity"],
                "title": payload_attrs["title"],
                "verifier": payload_attrs["verifier"],
                "assignee": payload_attrs["assignee"],
                "ccs": payload_attrs["ccs"],
            }
        }
        return payload

    def check_issuetracker_issue_fields(self, obj, issue_tracker_issue,
                                        issue_attrs,
                                        issue_tracker_ticket_attrs):
        """Checks issuetracker_issue were updated correctly.

    Make assertions to check if issue tracker fields were updated according
    our business logic.
    For Issue model we should get title, component_id, hotlist_id,
    priority, severity, issue_id and issue_type from GGRC and status from
    Issue Tracker.
    """

        self.assertTrue(issue_tracker_issue.enabled)

        # According to our business logic these attributes should be taken
        # from issue information
        self.assertEqual(issue_tracker_issue.title,
                         issue_attrs["issue"]["title"])
        self.assertEqual(int(issue_tracker_issue.component_id),
                         issue_attrs["issue"]["issue_tracker"]["component_id"])
        self.assertEqual(int(issue_tracker_issue.hotlist_id),
                         issue_attrs["issue"]["issue_tracker"]["hotlist_id"])
        self.assertEqual(
            issue_tracker_issue.issue_priority,
            issue_attrs["issue"]["issue_tracker"]["issue_priority"])
        self.assertEqual(
            issue_tracker_issue.issue_severity,
            issue_attrs["issue"]["issue_tracker"]["issue_severity"])
        self.assertEqual(int(issue_tracker_issue.issue_id),
                         issue_attrs["issue"]["issue_tracker"]["issue_id"])
        self.assertEqual(issue_tracker_issue.issue_type,
                         issue_attrs["issue"]["issue_tracker"]["issue_type"])

        # These attributes should be taken from ticket information
        ticket_status = issue_tracker_ticket_attrs["issueState"]["status"]
        ticket_mapped_status = ISSUE_STATUS_MAPPING[ticket_status]
        self.assertEqual(obj.status, ticket_mapped_status)

    @ddt.data(
        ({
            "title": "first_title"
        }, {
            "title": "other_title"
        }),
        ({
            "issue_type": "type1"
        }, {
            "issue_type": "process"
        }),
        ({
            "issue_severity": "S0"
        }, {
            "issue_severity": "S1"
        }),
        ({
            "issue_priority": "P0"
        }, {
            "issue_priority": "P1"
        }),
        ({
            "hotlist_id": 1234
        }, {
            "hotlist_id": 4321
        }),
        ({
            "component_id": 1234
        }, {
            "component_id": 4321
        }),
        ({
            "status": "Draft"
        }, {
            "status": "fixed"
        }),
    )
    @ddt.unpack
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_new_issue_linking(self, issue_attrs, ticket_attrs, update_mock):
        """Test linking new Issue to IssueTracker ticket sets correct fields"""
        issue_request_payload = self.request_payload_builder(issue_attrs)
        response_payload = self.response_payload_builder(ticket_attrs)
        with mock.patch("ggrc.integrations.issues.Client.get_issue",
                        return_value=response_payload) as get_mock:
            with mock.patch.object(integration_utils,
                                   "exclude_auditor_emails",
                                   return_value={
                                       u"*****@*****.**",
                                   }):
                response = self.api.post(all_models.Issue,
                                         issue_request_payload)
            get_mock.assert_called_once()
        update_mock.assert_called_once()

        self.assertEqual(response.status_code, 201)
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        issue = all_models.Issue.query.filter_by(id=issue_id).first()
        self.check_issuetracker_issue_fields(issue, issue_tracker_issue,
                                             issue_request_payload,
                                             response_payload)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_people_merge_after_linking(self, update_mock):
        """Test people roles were updated while linking new ticket"""
        ticket_attrs = {
            "verifier": "*****@*****.**",
            "assignee": "*****@*****.**",
            "ccs": ["*****@*****.**", "*****@*****.**"],
        }
        with factories.single_commit():
            factories.PersonFactory(email="*****@*****.**")
            factories.PersonFactory(email="*****@*****.**")
            for email in ["*****@*****.**", "*****@*****.**"]:
                factories.PersonFactory(email=email)

        issue_request_payload = self.request_payload_builder({})
        response_payload = self.response_payload_builder(ticket_attrs)
        with mock.patch("ggrc.integrations.issues.Client.get_issue",
                        return_value=response_payload) as get_mock:
            with mock.patch.object(integration_utils,
                                   "exclude_auditor_emails",
                                   return_value={
                                       u"*****@*****.**",
                                   }):
                response = self.api.post(all_models.Issue,
                                         issue_request_payload)
            get_mock.assert_called_once()
        update_mock.assert_called_once()

        self.assertEqual(response.status_code, 201)
        issue_id = response.json.get("issue").get("id")
        issue = all_models.Issue.query.filter_by(id=issue_id).first()

        admins = [
            person.email for person in issue.get_persons_for_rolename("Admin")
        ]
        primary = [
            person.email
            for person in issue.get_persons_for_rolename("Primary Contacts")
        ]
        secondary = [
            person.email
            for person in issue.get_persons_for_rolename("Secondary Contacts")
        ]
        # assert ticket roles were added to Issue
        self.assertIn("*****@*****.**", admins)
        self.assertIn("*****@*****.**", primary)
        for person in ["*****@*****.**", "*****@*****.**"]:
            self.assertIn(person, secondary)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_existing_issue_link(self, update_mock):
        """Test Issue link to another ticket """
        iti = factories.IssueTrackerIssueFactory(
            enabled=True,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())
        new_ticket_id = TICKET_ID + 1
        new_data = {"issue_id": new_ticket_id}
        issue_request_payload = self.put_request_payload_builder(new_data)
        response_payload = self.response_payload_builder(new_data)

        with mock.patch("ggrc.integrations.issues.Client.get_issue",
                        return_value=response_payload) as get_mock:
            with mock.patch.object(integration_utils,
                                   "exclude_auditor_emails",
                                   return_value={
                                       u"*****@*****.**",
                                   }):
                response = self.api.put(iti.issue_tracked_obj,
                                        issue_request_payload)
            get_mock.assert_called_once()

        self.assert200(response)

        # check if data was changed in our DB
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertEqual(int(issue_tracker_issue.issue_id), new_ticket_id)

        # check detach comment was sent
        detach_comment_template = params_builder.IssueParamsBuilder.DETACH_TMPL
        comment = detach_comment_template.format(new_ticket_id=new_ticket_id)
        expected_args = (TICKET_ID, {"status": "OBSOLETE", "comment": comment})
        self.assertEqual(expected_args, update_mock.call_args[0])

    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_already_linked_ticket(self):
        """Test Issue without IT couldn't be linked to already linked ticket"""
        with factories.single_commit():
            factories.IssueTrackerIssueFactory(
                enabled=True,
                issue_id=TICKET_ID,
                issue_tracked_obj=factories.IssueFactory())
            new_issue = factories.IssueFactory()

        issue_data = {"issue_id": TICKET_ID}
        issue_request_payload = self.put_request_payload_builder(issue_data)

        response = self.api.put(new_issue, issue_request_payload)
        self.assert200(response)
        self.assertTrue(response.json["issue"]["issue_tracker"]["_warnings"])
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertFalse(issue_tracker_issue)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_creating_new_ticket_for_linked_issue(self, update_mock):
        """Test create new ticket for already linked issue"""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())
        new_data = {"issue_id": ''}
        issue_request_payload = self.put_request_payload_builder(new_data)

        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):
            with mock.patch("ggrc.integrations.issues.Client.create_issue",
                            return_value={"issueId":
                                          TICKET_ID + 1}) as create_mock:
                response = self.api.put(iti.issue_tracked_obj,
                                        issue_request_payload)

        self.assert200(response)

        # Detach comment should be sent to previous ticket
        update_mock.assert_called_once()
        self.assertEqual(TICKET_ID, update_mock.call_args[0][0])
        create_mock.assert_called_once()

        # check if data was changed in our DB
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertNotEqual(int(issue_tracker_issue.issue_id), TICKET_ID)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_issue_tracker_error(self, update_issue_mock):
        """Test issue tracker errors.

    Issue in Issue tracker doesn't change state
    in case receiving an error.
    """
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        update_issue_mock.side_effect = integrations_errors.HttpError("data")
        issue_attrs = {
            "issue_tracker": {
                "enabled": True,
                "hotlist_id": "123",
                "issue_id": iti.issue_id,
            }
        }
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True),\
            mock.patch.object(all_models.IssuetrackerIssue,
                              "create_or_update_from_dict") as update_info_mock:
            self.api.put(iti.issue_tracked_obj, issue_attrs)

        # Check that "enabled" flag hasn't been changed.
        self.assertTrue("enabled" not in update_info_mock.call_args[0][1])

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_delete_issue(self, mock_update_issue):
        """Test updating issue tracker issue when issue in GGRC has been deleted"""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        expected_query = {
            "comment":
            "GGRC object has been deleted. GGRC changes "
            "will no longer be tracked within this bug."
        }
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.delete(iti.issue_tracked_obj)
        mock_update_issue.assert_called_with(iti.issue_id, expected_query)

    @ddt.data("test comment", "  \n\ntest comment\n\n" "  \n\n  \n\n")
    @mock.patch.object(params_builder.BaseIssueTrackerParamsBuilder,
                       "get_ggrc_object_url",
                       return_value="http://issue_url.com")
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_adding_comment_to_issue(self, desc, update_issue_mock,
                                     url_builder_mock):
        """Test adding comment to issue."""
        role = all_models.Role.query.filter(
            all_models.Role.name == "Administrator").one()
        with factories.single_commit():
            client_user = factories.PersonFactory(name="Test User")
            rbac_factories.UserRoleFactory(role=role, person=client_user)
        self.api.set_user(client_user)
        self.client.get("/login")
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        comment = factories.CommentFactory(description=desc)
        builder_class = params_builder.BaseIssueTrackerParamsBuilder
        expected_result = {
            "comment":
            builder_class.COMMENT_TMPL.format(
                author=client_user.name,
                comment="test comment",
                model="Issue",
                link="http://issue_url.com",
            )
        }

        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.post(
                all_models.Relationship, {
                    "relationship": {
                        "source": {
                            "id": iti.issue_tracked_obj.id,
                            "type": "Issue"
                        },
                        "destination": {
                            "id": comment.id,
                            "type": "comment"
                        },
                        "context": None
                    },
                })
        url_builder_mock.assert_called_once()
        update_issue_mock.assert_called_with(iti.issue_id, expected_result)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_mapping_document(self, update_issue_mock):
        """Test map document action on issue.

    Issue in Issue tracker shouldn't be updated when reference url has been
    added to issue.
    """
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        document = factories.DocumentFactory()
        response = self.api.put(
            iti.issue_tracked_obj, {
                "actions": {
                    "add_related": [
                        {
                            "id": document.id,
                            "type": "Document",
                        },
                    ]
                }
            })
        self.assert200(response)

        relationship = all_models.Relationship.query.filter(
            all_models.Relationship.source_type == "Issue",
            all_models.Relationship.source_id == response.json["issue"]["id"],
        ).order_by(all_models.Relationship.id.desc()).first()

        self.assertEqual(relationship.destination_id, document.id)
        self.assertEqual(relationship.source_id, iti.issue_tracked_obj.id)

        # Check that issue in Issue Tracker hasn't been updated.
        update_issue_mock.assert_not_called()
Ejemplo n.º 40
0
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 section"""
        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"
        ])
        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"])
Ejemplo n.º 41
0
class TestAccessControlRole(TestCase):
  """TestAccessControlRole"""

  def setUp(self):
    self.clear_data()
    super(TestAccessControlRole, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.people = {}
    for name in ["Creator", "Reader", "Editor"]:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=name)
      self.people[name] = user

  def _post_role(self, name=None, object_type="Control"):
    """Helper function for POSTing roles"""
    if name is None:
      name = random_str(prefix="Access Control Role - ")
    return self.api.post(AccessControlRole, {
        "access_control_role": {
            "name": name,
            "object_type": object_type,
            "context": None,
            "read": True
        },
    })

  def test_create_after_objects(self):
    """Test eager creation of ACLs on existing objects with new ACR."""
    risk_id = factories.RiskFactory().id
    role_name = "New Custom Role"
    self._post_role(name=role_name, object_type="Risk")
    risk = all_models.Risk.query.get(risk_id)
    self.assertIn(role_name, risk.acr_name_acl_map.keys())
    self.assertIsNotNone(risk.acr_name_acl_map[role_name])

  def test_create(self):
    """Test Access Control Role creation"""
    response = self._post_role(object_type="Risk")
    assert response.status_code == 201, \
        "Failed to create a new access control role, response was {}".format(
            response.status)

    id_ = response.json['access_control_role']['id']
    role = AccessControlRole.query.filter(AccessControlRole.id == id_).first()
    assert role.read == 1, \
        "Read permission not correctly saved {}".format(role.read)
    assert role.update == 1, \
        "Update permission not correctly saved {}".format(role.update)
    assert role.delete == 1, \
        "Update permission not correctly saved {}".format(role.delete)

  @ddt.data(
      {"mandatory": True, "exp_response": MANDATORY_ROLE_RESPONSE},
      {"mandatory": False, "exp_response": NON_MANDATORY_ROLE_RESPONSE},
  )
  @ddt.unpack
  def test_mandatory_delete(self, mandatory, exp_response):
    """Test set empty field via import if acr mandatory is {mandatory}"""
    role = factories.AccessControlRoleFactory(
        name=ROLE_NAME,
        object_type="Risk",
        mandatory=mandatory,
    )
    with factories.single_commit():
      user = factories.PersonFactory()
      risk = factories.RiskFactory()
      role_id = role.id
      factories.AccessControlPersonFactory(
          ac_list=risk.acr_name_acl_map[ROLE_NAME],
          person=user,
      )
    response = self.import_data(OrderedDict([
        ("object_type", "Risk"),
        ("Code*", risk.slug),
        (ROLE_NAME, "--"),
    ]))
    self._check_csv_response(response, exp_response)
    db_data = defaultdict(set)
    risk = all_models.Risk.query.get(risk.id)
    for person, acl in risk.access_control_list:
      db_data[acl.ac_role_id].add(person.id)
    if mandatory:
      cur_user = all_models.Person.query.filter_by(
          email="*****@*****.**").first()
      self.assertEqual(set([cur_user.id]), db_data[role_id])
    else:
      self.assertFalse(db_data[role_id])

  def test_only_admin_can_post(self):
    """Only admin users should be able to POST access control roles"""
    for name in ("Creator", "Reader", "Editor"):
      person = self.people.get(name)
      self.api.set_user(person)
      response = self._post_role()
      assert response.status_code == 403, \
          "Non admins should get forbidden error when POSTing role. {}".format(
              response.status)

  @ddt.data(
      ("name", "New ACR"),
      ("read", False),
      ("mandatory", False),
      ("non_editable", False),
  )
  @ddt.unpack
  def test_modify_non_editable_role(self, field_name, field_value):
    """Test if user can modify non-editable role"""
    # Primary Contacts role of Control is non-editable
    ac_role = AccessControlRole.query.filter_by(
        object_type="Control",
        name="Control Operators",
    ).first()

    response = self.api.put(ac_role, {field_name: field_value})
    assert response.status_code == 403, \
        "Forbidden error should be thrown when non-editable " \
        "role {} updated.".format(ac_role.name)

  def test_delete_non_editable_role(self):
    """Test if user can delete non-editable role"""
    # Primary Contacts role of Control is non-editable
    ac_role = AccessControlRole.query.filter_by(
        object_type="Control",
        name="Control Operators",
    ).first()

    response = self.api.delete(ac_role)
    assert response.status_code == 403, \
        "Forbidden error should be thrown when non-editable " \
        "role {} deleted.".format(ac_role.name)

  @ddt.data("Control")
  def test_create_from_ggrcq(self, object_type):
    """Test that create action only for GGRCQ."""
    with self.api.as_external():
      response = self._post_role(object_type=object_type)
      self.assertEqual(response.status_code, 201)

  @ddt.data("Control")
  def test_create_from_ggrc(self, object_type):
    """Test create action not allowed for GGRC."""
    response = self._post_role(object_type=object_type)
    self.assertEqual(response.status_code, 405)

  @ddt.data("Control")
  def test_modify_from_ggrcq(self, object_type):
    """Test that modify action only for GGRCQ."""
    with factories.single_commit():
      acr_id = factories.AccessControlRoleFactory(object_type=object_type).id

    with self.api.as_external():
      acr = all_models.AccessControlRole.query.get(acr_id)
      response = self.api.put(acr, {"name": "new acr"})
      self.assertEqual(response.status_code, 200)

  @ddt.data("Control")
  def test_modify_from_ggrc(self, object_type):
    """Test modify action not allowed for GGRC."""
    with factories.single_commit():
      acr = factories.AccessControlRoleFactory(object_type=object_type)

    response = self.api.put(acr, {"name": "new acr"})
    self.assertEqual(response.status_code, 405)

  @ddt.data("Control")
  def test_delete_from_ggrcq(self, object_type):
    """Test that modify action only for GGRCQ."""
    with factories.single_commit():
      acr_id = factories.AccessControlRoleFactory(object_type=object_type).id

    with self.api.as_external():
      acr = all_models.AccessControlRole.query.get(acr_id)
      response = self.api.delete(acr)
      self.assertEqual(response.status_code, 200)

  @ddt.data("Control")
  def test_delete_from_ggrc(self, object_type):
    """Test modify action not allowed for GGRC."""
    with factories.single_commit():
      acr = factories.AccessControlRoleFactory(object_type=object_type)

    response = self.api.delete(acr)
    self.assertEqual(response.status_code, 405)
Ejemplo n.º 42
0
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, [])
Ejemplo n.º 43
0
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)
Ejemplo n.º 44
0
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):
        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",
        ])
        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):
        """ 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)
Ejemplo n.º 45
0
class TestPersonResource(TestCase, WithQueryApi):
  """Tests for special people api endpoints."""

  def setUp(self):
    super(TestPersonResource, self).setUp()
    self.client.get("/login")
    self.api = Api()
    self.generator = WorkflowsGenerator()

  @staticmethod
  def _create_users_names_rbac(users):
    """Create name and Creator role for users, created vid PersonFactory"""
    if not users:
      return
    roles = {r.name: r for r in all_models.Role.query.all()}
    for user in users:
      user.name = user.email.split("@")[0]
      rbac_factories.UserRoleFactory(role=roles["Creator"], person=user)

  def assert_profile_get_successful(self, response, expected_datetime):
    """Verify assertions for successful GET profile method"""
    self.assert200(response)
    response_datetime = date_parser.parse(response.json["last_seen_whats_new"])
    self.assertEqual(expected_datetime, response_datetime)

  @freeze_time("2018-05-20 12:23:17")
  def test_profile_get_successful(self):
    """Test person_profile GET method successfully achieves correct data"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    response = self.api.client.get("/api/people/{}/profile".format(user.id))
    self.assert_profile_get_successful(response, default_date())

  def test_profile_get_no_profile(self):
    """Test person_profile GET method achieves data with missing profile"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    profiles_table = PersonProfile.__table__
    db_request = profiles_table.delete().where(
        profiles_table.c.person_id == user.id)
    db.engine.execute(db_request)
    with freeze_time("2018-05-28 23:30:10"):
      response = self.api.client.get("/api/people/{}/profile".format(user.id))
      self.assert_profile_get_successful(response, default_date())

  def test_profile_get_failed(self):
    """Test person_profiles GET method fails

    Now only logged user can request his profile
    """
    with factories.single_commit():
      valid_user = factories.PersonFactory()
      self._create_users_names_rbac([valid_user])

    response = self.client.get(
        "/api/people/{}/profile".format(valid_user.id))
    # logged with default user during setUp
    self.assert403(response)
    response = self.api.client.get(
        "/api/people/{}/profile".format(valid_user.id))
    # not authorized user
    self.assert403(response)

  def assert_profile_put_successful(self,
                                    response,
                                    correct_response,
                                    user,
                                    new_date):
    """Verify assertions for successful PUT profile method"""
    self.assert200(response)
    self.assertEqual(response.json, correct_response)
    profile = PersonProfile.query.filter_by(person_id=user.id).first()
    self.assertEqual(profile.last_seen_whats_new, date_parser.parse(new_date))

  def test_profile_put_successful(self):
    """Test person_profile PUT method for setting data and correct response"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    new_date = "2018-05-20 16:38:17"
    data = {"last_seen_whats_new": new_date}
    correct_response = {"Person": {"id": user.id, "profile": data}}
    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    self.assert_profile_put_successful(response,
                                       correct_response,
                                       user,
                                       new_date)

  def test_profile_put_no_profile(self):
    """Test person_profile PUT method for setting data for missing profile"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    new_date = "2018-05-20 22:05:17"
    data = {"last_seen_whats_new": new_date}
    correct_response = {"Person": {"id": user.id, "profile": data}}
    profiles_table = PersonProfile.__table__
    db_request = profiles_table.delete().where(
        profiles_table.c.person_id == user.id)
    db.engine.execute(db_request)
    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    self.assert_profile_put_successful(response,
                                       correct_response,
                                       user,
                                       new_date)

  def test_profile_put_unauthorized(self):
    """Test person_profiles PUT method fails for unauthorized user"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])

    new_date = "2018-05-20 22:05:17"
    data = {"last_seen_whats_new": new_date}
    response = self.client.put("/api/people/{}/profile".format(user.id),
                               content_type='application/json',
                               data=json.dumps(data),
                               headers=[('X-Requested-By', 'Tests')])
    # logged with default user during setUp
    self.assert403(response)
    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    # not authorized user
    self.assert403(response)

  @ddt.data({"last_seen_whats_new": "NOT A 123 DAT456A"},
            {"other_key": "2018-05-20 22:05:17", "one_more_key": 42})
  def test_profile_put_corrupted_data(self, data):
    """Test person_profiles PUT method fails via incorrect request data

    If request doesn't have "last_seen_whats_new" key or date is incorrect,
      response is code 400 "Bad Request"
    """
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    # missed key in request
    self.assert400(response)

  def test_task_count_empty(self):
    """Test query count without any workflows and tasks."""
    user = all_models.Person.query.first()
    response = self.client.get("/api/people/{}/task_count".format(user.id))
    self.assertEqual(
        response.json,
        {"open_task_count": 0, "has_overdue": False}
    )

  @ddt.data(
      (True, [
          ("task 1", "Finished", 3, True, 3),
          ("task 1", "Verified", 2, True, 3),
          ("task 2", "Declined", 2, True, 3),
          ("task 2", "Verified", 1, False, 3),
          ("task 2", "Finished", 2, True, 3),
          ("task 3", "Verified", 1, True, 3),
          ("task 2", "Verified", 0, False, 3),
      ]),
      (False, [
          ("task 1", "Finished", 2, True, 3),
          ("task 2", "In Progress", 2, True, 3),
          ("task 2", "Finished", 1, False, 3),
          ("task 3", "Finished", 0, False, 3),
      ]),
  )
  @ddt.unpack
  def test_task_count(self, is_verification_needed, transitions):
    """Test person task counts.

    This tests checks for correct task counts
     - with inactive workflows and
     - with overdue tasks
     - without overdue tasks
     - with finished overdue tasks

    The four checks are done in a single test due to complex differences
    between tests that make ddt cumbersome and the single test also improves
    integration test performance due to slow workflow setup stage.
    """
    # pylint: disable=too-many-locals

    user = all_models.Person.query.first()
    dummy_user = factories.PersonFactory()
    user_id = user.id
    role_id = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.name == "Task Assignees",
        all_models.AccessControlRole.object_type == "TaskGroupTask",
    ).one().id
    secondary_role_id = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.name == "Task Secondary Assignees",
        all_models.AccessControlRole.object_type == "TaskGroupTask",
    ).one().id

    one_time_workflow = {
        "title": "Person resource test workflow",
        "notify_on_change": True,
        "description": "some test workflow",
        "owners": [create_stub(user)],
        "is_verification_needed": is_verification_needed,
        "task_groups": [{
            "title": "one time task group",
            "contact": create_stub(user),
            "task_group_tasks": [{
                "title": "task 1",
                "description": "some task",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id),
                    acl_helper.get_acl_json(secondary_role_id, user.id)
                ],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 8, 15),
            }, {
                "title": "task 2",
                "description": "some task 3",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id),
                    acl_helper.get_acl_json(secondary_role_id, user.id),
                    acl_helper.get_acl_json(secondary_role_id, dummy_user.id)
                ],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 9, 16),
            }, {
                "title": "task 3",
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id),
                    acl_helper.get_acl_json(role_id, dummy_user.id)
                ],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 10, 16),
            }, {
                "title": "dummy task 4",  # task should not counted
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, dummy_user.id)],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 11, 17),
            }, {
                "title": "dummy task 5",  # task should not counted
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, dummy_user.id)],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 11, 18),
            }],
            "task_group_objects": []
        }]
    }

    inactive_workflow = {
        "title": "Activated workflow with archived cycles",
        "notify_on_change": True,
        "description": "Extra test workflow",
        "owners": [create_stub(user)],
        "task_groups": [{
            "title": "Extra task group",
            "contact": create_stub(user),
            "task_group_tasks": [{
                "title": "not counted existing task",
                "description": "",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id)],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 8, 15),
            }],
            "task_group_objects": []
        }]
    }

    with freeze_time("2017-10-16 05:09:10"):
      self.client.get("/login")
      # Activate normal one time workflow
      _, workflow = self.generator.generate_workflow(one_time_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      tasks = {t.title: t for t in cycle.cycle_task_group_object_tasks}
      _, workflow = self.generator.activate_workflow(workflow)

      # Activate and close the inactive workflow
      _, workflow = self.generator.generate_workflow(inactive_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      _, workflow = self.generator.activate_workflow(workflow)
      self.generator.modify_object(cycle, data={"is_current": False})

    with freeze_time("2017-7-16 07:09:10"):
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 3, "has_overdue": False}
      )

    with freeze_time("2017-10-16 08:09:10"):  # same day as task 3 end date
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 3, "has_overdue": True}
      )

      for task, status, count, overdue, my_work_count in transitions:
        self.generator.modify_object(tasks[task], data={"status": status})
        task_count_response = \
            self.client.get("/api/people/{}/task_count".format(user_id))
        my_work_count_response = \
            self.client.get("/api/people/{}/my_work_count".format(user_id))

        self.assertEqual(
            task_count_response.json,
            {"open_task_count": count, "has_overdue": overdue}
        )

        self.assertEqual(
            my_work_count_response.json["CycleTaskGroupObjectTask"],
            my_work_count
        )

  def test_task_count_multiple_wfs(self):
    """Test task count with both verified and non verified workflows.

    This checks task counts with 4 tasks
        2017, 8, 15  - verification needed
        2017, 11, 18  - verification needed
        2017, 8, 15  - No verification needed
        2017, 11, 18  - No verification needed
    """

    user = all_models.Person.query.first()
    user_id = user.id
    role_id = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.name == "Task Assignees",
        all_models.AccessControlRole.object_type == "TaskGroupTask",
    ).one().id
    workflow_template = {
        "title": "verified workflow",
        "owners": [create_stub(user)],
        "is_verification_needed": True,
        "task_groups": [{
            "title": "one time task group",
            "contact": create_stub(user),
            "task_group_tasks": [{
                "title": "task 1",
                "description": "some task",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id)],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 8, 15),
            }, {
                "title": "dummy task 5",
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id)],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 11, 18),
            }],
            "task_group_objects": []
        }]
    }

    with freeze_time("2017-10-16 05:09:10"):
      self.client.get("/login")
      verified_workflow = workflow_template.copy()
      verified_workflow["is_verification_needed"] = True
      _, workflow = self.generator.generate_workflow(verified_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      verified_tasks = {
          task.title: task
          for task in cycle.cycle_task_group_object_tasks
      }
      _, workflow = self.generator.activate_workflow(workflow)

      non_verified_workflow = workflow_template.copy()
      non_verified_workflow["is_verification_needed"] = False
      _, workflow = self.generator.generate_workflow(non_verified_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      non_verified_tasks = {
          task.title: task
          for task in cycle.cycle_task_group_object_tasks
      }
      _, workflow = self.generator.activate_workflow(workflow)

    with freeze_time("2017-7-16 07:09:10"):
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 4, "has_overdue": False}
      )

    with freeze_time("2017-10-16 08:09:10"):
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 4, "has_overdue": True}
      )

      # transition 1, task that needs verification goes to finished state. This
      # transition should not change anything
      self.generator.modify_object(
          verified_tasks["task 1"],
          data={"status": "Finished"}
      )
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 4, "has_overdue": True}
      )

      # transition 2, task that needs verification goes to verified state. This
      # transition should reduce task count.
      self.generator.modify_object(
          verified_tasks["task 1"],
          data={"status": "Verified"}
      )
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 3, "has_overdue": True}
      )

      # transition 3, task that does not need verification goes into Finished
      # state. This transition should reduce task count and remove all overdue
      # tasks
      self.generator.modify_object(
          non_verified_tasks["task 1"],
          data={"status": "Finished"}
      )
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 2, "has_overdue": False}
      )

  @ddt.data(("Creator", 403),
            ("Reader", 403),
            ("Editor", 200),
            ("Administrator", 200))
  @ddt.unpack
  def test_person_editing(self, role_name, status):
    """{0} should receive {1} status code on edit Person."""
    role = all_models.Role.query.filter(
        all_models.Role.name == role_name
    ).one()
    with factories.single_commit():
      client_user = factories.PersonFactory()
      rbac_factories.UserRoleFactory(role=role, person=client_user)
    self.api.set_user(client_user)
    self.client.get("/login")
    base_email = "*****@*****.**"
    person = factories.PersonFactory(email=base_email)
    person_id = person.id
    new_email = "new_{}".format(base_email)
    resp = self.api.put(person, {"email": new_email})
    self.assertEqual(status, resp.status_code)
    person = all_models.Person.query.get(person_id)
    if status == 200:
      self.assertEqual(new_email, person.email)
    else:
      self.assertEqual(base_email, person.email)
Ejemplo n.º 46
0
class TestIssueMapping(TestCase):
  """Test Issue mapping"""

  def setup_roles(self):
    """Setup necessary roles needed by the tests"""
    query = all_models.Role.query
    acr_query = all_models.AccessControlRole.query
    self.roles = {
        'creator': query.filter_by(name="Creator").first(),
        'auditors': acr_query.filter_by(name="Auditors").first(),
        'program_editors': acr_query.filter_by(
            name="Program Editors").first()
    }

  def setup_users(self):
    """Creates two creator users"""
    self.users = {}
    for user_name in ('auditor', 'programeditor'):
      user = factories.PersonFactory()
      rbac_factories.UserRoleFactory(
          role=self.roles['creator'],
          person=user)
      self.users[user_name] = user

  def setup_audits(self):
    """Create an audit and an archived audit"""
    self.audits = {
        False: self.create_audit(archived=False),
        True: self.create_audit(archived=True)
    }

  def setup_snapshots_and_issue(self):
    """Create snapshot & issue objects"""
    self.snapshots = {}
    self.issues = {}
    self.control = factories.ControlFactory()
    for is_archived in (False, True):
      audit = self.audits[is_archived]
      self.snapshots[is_archived] = self._create_snapshots(
          audit,
          [self.control],
      )[0]
      factories.RelationshipFactory(
          source=audit,
          destination=self.snapshots[is_archived],
      )

      # Create an issue
      issue = factories.IssueFactory()
      self.issues[is_archived] = issue
      # Map issue to audit
      factories.RelationshipFactory(
          source=audit,
          destination=issue,
          context=audit.context
      )

  def create_audit(self, archived=False):
    """Create an audit object and fix the it's context"""
    audit = factories.AuditFactory(archived=archived)
    factories.RelationshipFactory(
        source=audit,
        destination=audit.program,
    )
    # Add auditor & program editor roles
    factories.AccessControlListFactory(
        ac_role=self.roles['auditors'],
        object=audit,
        person=self.users['auditor']
    )
    factories.AccessControlListFactory(
        ac_role=self.roles['program_editors'],
        object=audit.program,
        person=self.users['programeditor']
    )

    return audit

  def setUp(self):
    """Prepare data needed to run the tests"""
    super(TestIssueMapping, self).setUp()
    self.api = Api()
    self.setup_roles()
    self.setup_users()
    self.setup_audits()
    self.setup_snapshots_and_issue()

  @data(
      # user_name, is_archived
      ('auditor', True),
      ('programeditor', True),
      ('auditor', False),
      ('programeditor', False),
  )
  @unpack
  def test_mapping_to_issue(self, user_name, is_archived):
    """Test mapping snapshots to issue for {0} ({1})"""
    user = self.users[user_name]
    payload = _get_map_dict(
        self.snapshots[is_archived],
        self.issues[is_archived])
    self.api.set_user(user)

    # Try to map to audit
    response = self.api.post(all_models.Relationship, payload)
    self.assertStatus(response, 201)

    rel_id = response.json['relationship']['id']
    relationship = all_models.Relationship.query.filter_by(id=rel_id).first()
    response = self.api.delete(relationship)
    self.assertStatus(response, 200)
Ejemplo n.º 47
0
class TestCollection(TestCase, WithQueryApi):
    """Test for collection assessment objects."""
    def setUp(self):
        super(TestCollection, self).setUp()
        self.client.get("/login")
        self.clear_data()
        self.api = Api()
        self.generator = ObjectGenerator()

    @ddt.data(True, False)
    def test_order_by_test(self, desc):
        """Order by fultext attr"""
        expected_ids = []
        with factories.single_commit():
            assessments = [factories.AssessmentFactory() for _ in range(10)]
        random.shuffle(assessments)
        with factories.single_commit():
            for idx, assessment in enumerate(assessments):
                comment = factories.CommentFactory(description=str(idx))
                factories.RelationshipFactory(source=assessment,
                                              destination=comment)
                expected_ids.append(assessment.id)
        query = self._make_query_dict("Assessment",
                                      order_by=[{
                                          "name": "comment",
                                          "desc": desc
                                      }])
        if desc:
            expected_ids = expected_ids[::-1]
        results = self._get_first_result_set(query, "Assessment", "values")
        self.assertEqual(expected_ids, [i['id'] for i in results])

    @ddt.data("Assessor", "Creator", "Verifier")
    def test_delete_assessment_by_role(self, role_name):
        """Delete assessment not allowed for based on Assignee Type."""
        with factories.single_commit():
            assessment = factories.AssessmentFactory()
            context = factories.ContextFactory(related_object=assessment)
            assessment.context = context
            person = factories.PersonFactory()
            object_person_rel = factories.RelationshipFactory(
                source=assessment, destination=person)
            factories.RelationshipAttrFactory(
                relationship_id=object_person_rel.id,
                attr_name="AssigneeType",
                attr_value=role_name,
            )
        assessment_id = assessment.id
        role = all_models.Role.query.filter(
            all_models.Role.name == "Creator").first()
        self.generator.generate_user_role(person, role, context)
        self.api.set_user(person)
        assessment = all_models.Assessment.query.get(assessment_id)
        resp = self.api.delete(assessment)
        self.assert403(resp)
        self.assertTrue(
            all_models.Assessment.query.filter(
                all_models.Assessment.id == assessment_id).one())

    @ddt.data(
        (all_models.Assessment.REWORK_NEEDED, True),
        (all_models.Assessment.DONE_STATE, True),
        (all_models.Assessment.FINAL_STATE, True),
        (all_models.Assessment.START_STATE, False),
    )
    @ddt.unpack
    def test_update_status_need_rework(self, status, is_valid):
        """Update assessment state from need rework to valid or invalid states."""
        with factories.single_commit():
            assessment = factories.AssessmentFactory(
                status=all_models.Assessment.REWORK_NEEDED)
        assessment_id = assessment.id
        resp = self.api.put(assessment, {"status": status})
        if is_valid:
            self.assert200(resp)
            check_status = status
        else:
            self.assert400(resp)
            check_status = all_models.Assessment.REWORK_NEEDED
        self.assertEqual(check_status,
                         all_models.Assessment.query.get(assessment_id).status)
Ejemplo n.º 48
0
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)
Ejemplo n.º 49
0
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.tc.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"])
        all_errors = []
        base_models = set([
            "Control", "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["creator"].id,
                            },
                        },
                    })
                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)
Ejemplo n.º 50
0
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)
Ejemplo n.º 51
0
class TestWorkflowsApiPost(TestCase):
  """Test class for ggrc workflow api post action."""

  def setUp(self):
    super(TestWorkflowsApiPost, self).setUp()
    self.api = Api()
    self.generator = wf_generator.WorkflowsGenerator()
    self.wf_admin_id = all_models.Person.query.first().id
    with factories.single_commit():
      self.people_ids = [factories.PersonFactory().id for _ in xrange(6)]

  def tearDown(self):
    pass

  def _delete_and_check_related_acl(self, related_model, exp_acl_count,
                                    is_deleted):
    """Delete related model and check remaining ACL count.

    Args:
        related_model: related model class
        exp_acl_count: expected related ACL count after delete operation
        is_deleted: is related object already deleted
    """
    if is_deleted:
      related_count = related_model.query.count()
      self.assertEqual(related_count, 0)
    else:
      related = related_model.query.one()
      response = self.api.delete(related)
      self.assert200(response)

    related_acl_count = all_models.AccessControlList.query.filter(
        all_models.AccessControlList.object_type == related_model.__name__
    ).count()
    self.assertEqual(related_acl_count, 0)

    bg_task_count = all_models.AccessControlList.query.filter(
        all_models.AccessControlList.object_type == "BackgroundTask"
    ).count()

    all_acl_count = all_models.AccessControlList.query.count()
    self.assertEqual(all_acl_count - bg_task_count, exp_acl_count)

  def test_acl_on_object_deletion(self):
    """Test related ACL records removed on related object delete"""
    self._create_propagation_acl_test_data()
    acl_count = all_models.AccessControlList.query.count()
    self.assertNotEqual(acl_count, 0)

    admin = all_models.Person.query.get(1)
    self.api.set_user(admin)

    related_models = (
        (all_models.CycleTaskEntry, 18, False),
        (all_models.TaskGroup, 12, False),
        (all_models.TaskGroupTask, 12, True),
        (all_models.Cycle, 3, False),
        (all_models.CycleTaskGroup, 3, True),
        (all_models.CycleTaskGroupObjectTask, 3, True),
    )
    for related_model, acl_count, is_deleted in related_models:
      self._delete_and_check_related_acl(related_model, acl_count, is_deleted)

  def test_acl_on_workflow_delete(self):
    """Test related ACL records removed on Workflow delete"""
    self._create_propagation_acl_test_data()
    acl_count = all_models.AccessControlList.query.count()
    self.assertNotEqual(acl_count, 0)

    admin = all_models.Person.query.get(1)
    self.api.set_user(admin)
    workflow = all_models.Workflow.query.one()
    response = self.api.delete(workflow)
    self.assert200(response)

    acl_count = all_models.AccessControlList.query.count()
    bg_acl_count = all_models.AccessControlList.query.filter(
        all_models.AccessControlList.object_type == "BackgroundTask"
    ).count()
    self.assertEqual(acl_count, bg_acl_count)

  def test_acl_for_new_related_object(self):
    """Test Workflow ACL propagation for new related objects."""
    data = self.get_workflow_dict()
    acl_map = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Workflow Member'],
    }
    data["workflow"]["access_control_list"] = acl_helper.get_acl_list(acl_map)
    data["workflow"]["unit"] = "week"
    data["workflow"]["repeat_every"] = 1
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

    data = self.get_task_group_dict(response.json["workflow"])
    data["task_group"]["contact"]["id"] = self.people_ids[2]
    data["task_group"]["contact"]["href"] = "/api/people/{}".format(
        self.people_ids[2])
    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

    task_group = all_models.TaskGroup.eager_query().one()
    data = self.get_task_dict(task_group)
    data["task_group_task"]["start_date"] = "2018-01-04"
    data["task_group_task"]["end_date"] = "2018-01-05"
    response = self.api.post(all_models.TaskGroupTask, data)
    self.assertEqual(response.status_code, 201)

    workflow = all_models.Workflow.query.one()
    with freezegun.freeze_time("2018-01-05"):  # Generate 1 cycle
      self.generator.activate_workflow(workflow)

    cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
    cycle = all_models.Cycle.query.one()
    data = self.get_comment_dict(cycle_task, cycle)
    response = self.api.post(all_models.CycleTaskEntry, data)
    self.assertEqual(response.status_code, 201)

    self._check_propagated_acl(3)

  @ddt.data('Admin', 'Workflow Member')
  def test_tg_assignee(self, role_name):
    """Test TaskGroup assignee already has {0} role."""
    data = self.get_workflow_dict()
    init_acl = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES[role_name],
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_acl)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

    data = self.get_task_group_dict(response.json["workflow"])
    data["task_group"]["contact"]["id"] = self.people_ids[1]
    data["task_group"]["contact"]["href"] = "/api/people/{}".format(
        self.people_ids[1])
    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

    workflow = all_models.Workflow.query.one()
    task_group = all_models.TaskGroup.query.one()

    actual_acl = all_models.AccessControlList.eager_query().filter(
        all_models.AccessControlList.person_id == task_group.contact_id,
    ).all()
    self.assertEqual(len(actual_acl), 2)

    expected = {
        role_name: (workflow.type, workflow.id),
        "{} Mapped".format(role_name): (task_group.type, task_group.id)
    }
    actual = {
        acl.ac_role.name: (acl.object_type, acl.object_id)
        for acl in actual_acl
    }
    self.assertDictEqual(expected, actual)

  def test_task_group_assignee_gets_workflow_member(self):  # noqa pylint: disable=invalid-name
    """Test TaskGroup assignee gets WorkflowMember role."""
    data = self.get_workflow_dict()
    init_acl = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Workflow Member'],
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_acl)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

    data = self.get_task_group_dict(response.json["workflow"])
    data["task_group"]["contact"]["id"] = self.people_ids[2]
    data["task_group"]["contact"]["href"] = "/api/people/{}".format(
        self.people_ids[2])
    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

    workflow = all_models.Workflow.query.one()
    task_group = all_models.TaskGroup.query.one()

    parent_acl = all_models.AccessControlList.eager_query().filter(
        all_models.AccessControlList.person_id == task_group.contact_id,
        all_models.AccessControlList.object_type == workflow.type,
        all_models.AccessControlList.object_id == workflow.id
    ).one()
    tg_acl = all_models.AccessControlList.eager_query().filter(
        all_models.AccessControlList.person_id == task_group.contact_id,
        all_models.AccessControlList.object_type == task_group.type,
        all_models.AccessControlList.object_id == task_group.id
    ).one()
    self.assertEqual(parent_acl.ac_role.name, "Workflow Member")
    self.assertEqual(tg_acl.parent_id, parent_acl.id)
    self.assertEqual(tg_acl.ac_role.name, "Workflow Member Mapped")

  def _create_propagation_acl_test_data(self):  # noqa pylint: disable=invalid-name
    """Create objects for Workflow ACL propagation test."""
    with freezegun.freeze_time("2017-08-9"):
      with factories.single_commit():
        workflow = wf_factories.WorkflowFactory(
            title='wf1',
            unit=all_models.Workflow.WEEK_UNIT,
            is_verification_needed=True,
            repeat_every=1)
        wf_factories.TaskGroupTaskFactory(
            title='tgt1',
            task_group=wf_factories.TaskGroupFactory(
                title='tg1',
                context=factories.ContextFactory(),
                workflow=workflow
            ),
            # One cycle should be created
            start_date=datetime.date(2017, 8, 3),
            end_date=datetime.date(2017, 8, 7)
        )
      self.generator.activate_workflow(workflow)
      cycle = all_models.Cycle.query.one()
      cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
      wf_factories.CycleTaskEntryFactory(
          cycle=cycle,
          cycle_task_group_object_task=cycle_task,
          description="Cycle task comment",
      )
      workflow = all_models.Workflow.query.one()
      acl_map = {
          self.people_ids[0]: WF_ROLES['Admin'],
          self.people_ids[1]: WF_ROLES['Workflow Member'],
          self.people_ids[2]: WF_ROLES['Workflow Member'],
      }
      put_params = {'access_control_list': acl_helper.get_acl_list(acl_map)}
      response = self.api.put(workflow, put_params)
      self.assert200(response)

  def _check_propagated_acl(self, roles_count):
    """Check Workflow propagated ACL records.

    Args:
        roles_count: roles' count created in test
    """
    related_objects = (
        (all_models.TaskGroup.query.one().id, all_models.TaskGroup.__name__),
        (all_models.TaskGroupTask.query.one().id,
         all_models.TaskGroupTask.__name__),
        (all_models.Cycle.query.one().id, all_models.Cycle.__name__),
        (all_models.CycleTaskGroup.query.one().id,
         all_models.CycleTaskGroup.__name__),
        (all_models.CycleTaskGroupObjectTask.query.one().id,
         all_models.CycleTaskGroupObjectTask.__name__),
        (all_models.CycleTaskEntry.query.one().id,
         all_models.CycleTaskEntry.__name__)
    )
    related_count = len(related_objects)
    bd_tasks_count = all_models.BackgroundTask.query.count()

    all_acl = [acl for acl in all_models.AccessControlList.eager_query().all()]
    self.assertEqual(
        len(all_acl),
        bd_tasks_count + roles_count + roles_count * related_count
    )

    workflow = all_models.Workflow.query.one()
    parent_acl, related_acl = [], []
    for acl in all_acl:
      if (not acl.parent_id and acl.object_id == workflow.id and
              acl.object_type == workflow.type):
        parent_acl.append(acl)
      else:
        related_acl.append(acl)

    result = defaultdict(set)
    for p_acl in parent_acl:
      for r_acl in related_acl:
        if (r_acl.ac_role.name == '{} Mapped'.format(p_acl.ac_role.name) and
                r_acl.parent_id == p_acl.id and
                r_acl.person_id == p_acl.person_id):
          result[p_acl.id].add((r_acl.object_id, r_acl.object_type))
    self.assertEqual(roles_count, len(result))

  def test_assign_workflow_acl(self):
    """Test propagation Workflow ACL roles on Workflow's update ACL records."""
    self._create_propagation_acl_test_data()
    self._check_propagated_acl(3)

  def test_unassign_workflow_acl(self):
    """Test propagation Workflow ACL roles on person unassigned."""
    self._create_propagation_acl_test_data()
    with freezegun.freeze_time("2017-08-9"):
      workflow = all_models.Workflow.query.one()
      acl_map = {
          self.people_ids[0]: WF_ROLES['Admin'],
          self.people_ids[1]: WF_ROLES['Workflow Member'],
      }
      put_params = {'access_control_list': acl_helper.get_acl_list(acl_map)}
      response = self.api.put(workflow, put_params)
      self.assert200(response)

    self._check_propagated_acl(2)

  def test_post_workflow_with_acl(self):
    """Test PUT workflow with ACL."""
    data = self.get_workflow_dict()

    exp_res = {
        self.wf_admin_id: WF_ROLES['Admin'],
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Workflow Member'],
        self.people_ids[2]: WF_ROLES['Workflow Member'],
        self.people_ids[3]: WF_ROLES['Workflow Member']
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(exp_res)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)
    workflow = all_models.Workflow.eager_query().one()
    act_res = {acl.person_id: acl.ac_role_id
               for acl in workflow.access_control_list}
    self.assertDictEqual(exp_res, act_res)

  def test_update_workflow_acl_people(self):
    """Test PUT workflow with updated ACL."""
    data = self.get_workflow_dict()
    init_map = {
        self.wf_admin_id: WF_ROLES['Admin'],
        self.people_ids[0]: WF_ROLES['Workflow Member'],
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_map)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)
    exp_res = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Admin'],
        self.people_ids[2]: WF_ROLES['Workflow Member'],
        self.people_ids[3]: WF_ROLES['Workflow Member'],
        self.people_ids[4]: WF_ROLES['Workflow Member']
    }
    workflow = all_models.Workflow.eager_query().one()
    put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)}
    response = self.api.put(workflow, put_params)
    self.assert200(response)
    workflow = all_models.Workflow.eager_query().one()
    act_res = {acl.person_id: acl.ac_role_id
               for acl in workflow.access_control_list}
    self.assertDictEqual(exp_res, act_res)

  def test_send_invalid_data(self):
    """Test send invalid data on Workflow post."""
    data = self.get_workflow_dict()
    del data["workflow"]["title"]
    del data["workflow"]["context"]
    response = self.api.post(all_models.Workflow, data)
    self.assert400(response)
    # TODO: check why response.json["message"] is empty

  def test_create_one_time_workflows(self):
    """Test simple create one time Workflow over api."""
    data = self.get_workflow_dict()
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_weekly_workflow(self):
    """Test create valid weekly wf"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 7
    data["workflow"]["unit"] = "day"
    data["workflow"]["title"] = "Weekly"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_annually_workflow(self):
    """Test create valid annual wf"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 12
    data["workflow"]["unit"] = "month"
    data["workflow"]["title"] = "Annually"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  @ddt.data("wrong value", 0, -4)
  def test_create_wrong_repeat_every_workflow(self, value):  # noqa pylint: disable=invalid-name
    """Test case for invalid repeat_every value"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = value
    data["workflow"]["unit"] = "month"
    data["workflow"]["title"] = "Wrong wf"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 400)

  def test_create_wrong_unit_workflow(self):
    """Test case for invalid unit value"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 12
    data["workflow"]["unit"] = "wrong value"
    data["workflow"]["title"] = "Wrong wf"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 400)

  def test_create_task_group(self):
    """Test create task group over api."""
    wf_data = self.get_workflow_dict()
    wf_data["workflow"]["title"] = "Create_task_group"
    wf_response = self.api.post(all_models.Workflow, wf_data)

    data = self.get_task_group_dict(wf_response.json["workflow"])

    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

  @staticmethod
  def get_workflow_dict():
    return {
        "workflow": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "title": "One_time",
            "description": "",
            "unit": None,
            "repeat_every": None,
            "notify_on_change": False,
            "task_group_title": "Task Group 1",
            "notify_custom_message": "",
            "is_verification_needed": True,
            "context": None,
        }
    }

  def get_task_group_dict(self, workflow):
    return {
        "task_group": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "_transient": {},
            "contact": {
                "id": self.wf_admin_id,
                "href": "/api/people/{}".format(self.wf_admin_id),
                "type": "Person"
            },
            "workflow": {
                "id": workflow["id"],
                "href": "/api/workflows/%d" % workflow["id"],
                "type": "Workflow"
            },
            "context": {
                "id": workflow["context"]["id"],
                "href": "/api/contexts/%d" % workflow["context"]["id"],
                "type": "Context"
            },
            "modal_title": "Create Task Group",
            "title": "Create_task_group",
            "description": "",
        }
    }

  def get_task_dict(self, task_group):
    return {
        "task_group_task": {
            "start_date": "2017-12-25",
            "end_date": "2017-12-31",
            "custom_attributes": {},
            "contact": {
                "id": self.wf_admin_id,
                "href": "/api/people/{}".format(self.wf_admin_id),
                "type": "Person"
            },
            "task_group": {
                "id": task_group.id,
                "href": "/api/task_groups/{}".format(task_group.id),
                "type": "TaskGroup"
            },
            "context": {
                "id": task_group.context_id,
                "href": "/api/contexts/{}".format(task_group.context_id),
                "type": "Context"
            },
            "title": "Create_task",
            "task_type": "text",
            "description": ""
        }
    }

  @staticmethod
  def get_comment_dict(cycle_task, cycle):
    return {
        "cycle_task_entry": {
            "custom_attributes": {},
            "cycle_task_group_object_task": {
                "id": cycle_task.id,
                "href": "/api/cycle_task_group_object_tasks/{}".format(
                    cycle_task.id),
                "type": "CycleTaskGroupObjectTask"
            },
            "cycle": {
                "id": cycle.id,
                "href": "/api/cycles/{}".format(cycle.id),
                "type": "Cycle"
            },
            "context": {
                "id": cycle.context_id,
                "href": "/api/contexts/{}".format(cycle.context_id),
                "type": "Context"
            },
            "is_declining_review": "",
            "description": "CT comment"
        }
    }

  @ddt.data({},
            {"repeat_every": 5, "unit": "month"})
  def test_repeat_multiplier_field(self, data):
    """Check repeat_multiplier is set to 0 after wf creation."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(**data)
    workflow_id = workflow.id
    self.assertEqual(
        0, all_models.Workflow.query.get(workflow_id).repeat_multiplier)

  # TODO: Unskip in the patch 2
  @unittest.skip("Will be activated in patch 2")
  def test_change_to_one_time_wf(self):
    """Check repeat_every and unit can be set to Null only together."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                              unit="day")
    resp = self.api.put(workflow, {"repeat_every": None,
                                   "unit": None})
    self.assert200(resp)

  @ddt.data({"repeat_every": 5},
            {"unit": "month"})
  def test_change_repeat_every(self, data):
    """Check repeat_every or unit can not be changed once set."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory()
    resp = self.api.put(workflow, data)
    self.assert400(resp)

  def test_not_change_to_one_time_wf(self):
    """Check repeat_every or unit can't be set to Null separately.
    This test will be useful in the 2nd patch, where we allow to change
    WF setup
    """
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                              unit="day")
    resp = self.api.put(workflow, {"repeat_every": None})
    self.assert400(resp)
    resp = self.api.put(workflow, {"unit": None})
    self.assert400(resp)

  @ddt.data(True, False)
  def test_autogen_verification_flag(self, flag):
    """Check is_verification_needed flag for activate WF action."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
      group = wf_factories.TaskGroupFactory(workflow=workflow)
      wf_factories.TaskGroupTaskFactory(task_group=group)
    data = [{
        "cycle": {
            "autogenerate": True,
            "isOverdue": False,
            "workflow": {
                "id": workflow.id,
                "type": "Workflow",
            },
            "context": {
                "id": workflow.context_id,
                "type": "Context",
            },
        }
    }]
    resp = self.api.send_request(
        self.api.client.post,
        api_link="/api/cycles",
        data=data)
    cycle_id = resp.json[0][1]["cycle"]["id"]
    self.assertEqual(
        flag, all_models.Cycle.query.get(cycle_id).is_verification_needed)

  @ddt.data(True, False)
  def test_verification_flag_positive(self, flag):  # noqa pylint: disable=invalid-name
    """is_verification_needed flag is changeable for DRAFT workflow."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": not flag})
    self.assert200(resp)
    self.assertEqual(
        all_models.Workflow.query.get(workflow_id).is_verification_needed,
        not flag)

  @ddt.data(True, False)
  def test_verification_flag_negative(self, flag):
    """Test immutable verification flag on active workflows."""
    with freezegun.freeze_time("2017-08-10"):
      with factories.single_commit():
        workflow = wf_factories.WorkflowFactory(
            unit=all_models.Workflow.WEEK_UNIT,
            is_verification_needed=flag,
            repeat_every=1)
        wf_factories.TaskGroupTaskFactory(
            task_group=wf_factories.TaskGroupFactory(
                context=factories.ContextFactory(),
                workflow=workflow
            ),
            # Two cycles should be created
            start_date=datetime.date(2017, 8, 3),
            end_date=datetime.date(2017, 8, 7))
      workflow_id = workflow.id
      self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
      self.generator.activate_workflow(workflow)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.status, all_models.Workflow.ACTIVE)
      resp = self.api.put(workflow, {"is_verification_needed": not flag})
      self.assert400(resp)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.is_verification_needed, flag)

      # End all current cycles
      for cycle in workflow.cycles:
        self.generator.modify_object(cycle, {'is_current': False})
      workflow = all_models.Workflow.query.filter(
          all_models.Workflow.id == workflow_id).first()
      self.assertEqual(workflow.status, all_models.Workflow.INACTIVE)
      resp = self.api.put(workflow, {"is_verification_needed": not flag})
      self.assert400(resp)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.is_verification_needed, flag)

  @ddt.data(True, False)
  def test_not_change_vf_flag(self, flag):
    """Check is_verification_needed not change on update."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": flag})
    self.assert200(resp)
    self.assertEqual(
        flag,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)

  @ddt.data(True, False, None)
  def test_create_vf_flag(self, flag):
    """Check is_verification_needed flag setup on create."""
    data = self.get_workflow_dict()
    if flag is None:
      data['workflow'].pop('is_verification_needed', None)
    else:
      data['workflow']['is_verification_needed'] = flag
    resp = self.api.post(all_models.Workflow, data)
    self.assertEqual(201, resp.status_code)
    workflow_id = resp.json['workflow']['id']
    self.assertEqual(
        flag if flag is not None else True,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)
Ejemplo n.º 52
0
class TestProposalEmail(TestCase):
    """Test case about email sending and email presenting for proposals."""
    def setUp(self):
        super(TestProposalEmail, self).setUp()
        self.api = Api()
        self.client.get("/login")

    @ddt.data(True, False)
    def test_email_presentation(self, is_admin):
        """Test presentation of proposal digest email if is_admin is {0}."""
        person = factories.PersonFactory()
        self.api.set_user(person=person)
        with mock.patch("ggrc.rbac.permissions.is_admin",
                        return_value=is_admin):
            resp = self.client.get("/_notifications/show_fast_digest")
        if is_admin:
            self.assert200(resp)
        else:
            self.assert403(resp)

    def test_email_sending(self):
        """Test sending emails about proposals."""
        role_1 = factories.AccessControlRoleFactory(object_type="Program",
                                                    notify_about_proposal=True)
        role_2 = factories.AccessControlRoleFactory(object_type="Program",
                                                    notify_about_proposal=True)
        role_3 = factories.AccessControlRoleFactory(
            object_type="Program", notify_about_proposal=False)
        with factories.single_commit():
            program = factories.ProgramFactory()
            person_1 = factories.PersonFactory()  # has 1 role
            person_2 = factories.PersonFactory()  # has no roles
            person_3 = factories.PersonFactory()  # has 2 roles
            factories.PersonFactory()  # not related to program at all
            factories.AccessControlPersonFactory(
                ac_list=program.acr_acl_map[role_1], person=person_1)
            factories.AccessControlPersonFactory(
                ac_list=program.acr_acl_map[role_1], person=person_3)
            factories.AccessControlPersonFactory(
                ac_list=program.acr_acl_map[role_2], person=person_3)
            factories.AccessControlPersonFactory(
                ac_list=program.acr_acl_map[role_3], person=person_2)
            proposal_1 = factories.ProposalFactory(
                instance=program,
                content={
                    "fields": {
                        "title": "a"
                    },
                    "access_control_list": {},
                    "custom_attribute_values": {},
                    "mapping_fields": {},
                    "mapping_list_fields": {},
                },
                agenda="agenda 1")
            proposal_2 = factories.ProposalFactory(
                instance=program,
                content={
                    "fields": {
                        "title": "b"
                    },
                    "access_control_list": {},
                    "custom_attribute_values": {},
                    "mapping_fields": {},
                    "mapping_list_fields": {},
                },
                agenda="agenda 2")
        self.assertIsNone(proposal_1.proposed_notified_datetime)
        self.assertIsNone(proposal_2.proposed_notified_datetime)
        with mock.patch("google.appengine.api.mail.send_mail") as mailer_mock:
            with mock.patch.object(fast_digest.DIGEST_TMPL,
                                   "render") as bodybuilder_mock:
                fast_digest.send_notification()
        self.assertIsNotNone(proposal_1.proposed_notified_datetime)
        self.assertIsNotNone(proposal_2.proposed_notified_datetime)
        self.assertEqual(2, len(bodybuilder_mock.call_args_list))
        self.assertEqual(2, len(mailer_mock.call_args_list))
        # email to each required person
        self.assertListEqual(
            sorted([person_1.email, person_3.email]),
            sorted([a[1]["to"] for a in mailer_mock.call_args_list]))
        # no matter how many roles each proposal should be otified
        # only once for that person
        self.assertListEqual(
            [2] * 2,
            [len(a[1]["proposals"]) for a in bodybuilder_mock.call_args_list])

    @ddt.data('Program Managers', 'Program Editors', 'Primary Contacts')
    def test_email_proposal_program(self, role_name):
        """Test sending email to Program manager/Editor/Primary Contacts"""
        from ggrc.models import all_models

        role_1 = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == role_name,
            all_models.AccessControlRole.object_type == 'Program',
        ).one()
        with factories.single_commit():
            program = factories.ProgramFactory()
            person_1 = factories.PersonFactory()  # has 1 role
            factories.AccessControlPersonFactory(
                ac_list=program.acr_acl_map[role_1], person=person_1)
            proposal_1 = factories.ProposalFactory(
                instance=program,
                content={
                    "fields": {
                        "title": "a"
                    },
                    "access_control_list": {},
                    "custom_attribute_values": {},
                    "mapping_fields": {},
                    "mapping_list_fields": {},
                },
                agenda="agenda 1")
        self.assertIsNone(proposal_1.proposed_notified_datetime)
        with mock.patch("google.appengine.api.mail.send_mail") as mailer_mock:
            with mock.patch.object(fast_digest.DIGEST_TMPL,
                                   "render") as bodybuilder_mock:
                fast_digest.send_notification()
        self.assertIsNotNone(proposal_1.proposed_notified_datetime)
        self.assertEqual(1, len(bodybuilder_mock.call_args_list))
        self.assertEqual(1, len(mailer_mock.call_args_list))
        # email to each required person
        self.assertEqual([person_1.email],
                         [a[1]["to"] for a in mailer_mock.call_args_list])
Ejemplo n.º 53
0
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"])
Ejemplo n.º 54
0
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": [{
                    "ac_role_id": acr.id,
                    "person": {
                        "id": user.id
                    },
                    "type": "AccessControlList",
                }]
            })

    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, 200)

        # But he should still not be allowed to update
        response = self.api.put(system, response.json)
        self.assertEqual(response.status_code, 403)
Ejemplo n.º 55
0
class TestAccessControlRole(TestCase):
    """TestAccessControlRole"""
    def setUp(self):
        self.clear_data()
        super(TestAccessControlRole, self).setUp()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.people = {}
        for name in ["Creator", "Reader", "Editor"]:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=name)
            self.people[name] = user

    def _post_role(self, name=None, object_type="Control"):
        """Helper function for POSTing roles"""
        if name is None:
            name = random_str(prefix="Access Control Role - ")
        return self.api.post(
            AccessControlRole, {
                "access_control_role": {
                    "name": name,
                    "object_type": object_type,
                    "context": None,
                    "read": True
                },
            })

    def test_create_after_objects(self):
        """Test eager creation of ACLs on existing objects with new ACR."""
        program_id = factories.ProgramFactory().id
        role_name = "New Custom Role"
        self._post_role(name=role_name, object_type="Program")
        program = all_models.Program.query.get(program_id)
        self.assertIn(role_name, program.acr_name_acl_map.keys())
        self.assertIsNotNone(program.acr_name_acl_map[role_name])

    def test_create(self):
        """Test Access Control Role creation"""
        response = self._post_role(object_type="Program")
        assert response.status_code == 201, \
            "Failed to create a new access control role, response was {}".format(
                response.status)

        id_ = response.json['access_control_role']['id']
        role = AccessControlRole.query.filter(
            AccessControlRole.id == id_).first()
        assert role.read == 1, \
            "Read permission not correctly saved {}".format(role.read)
        assert role.update == 1, \
            "Update permission not correctly saved {}".format(role.update)
        assert role.delete == 1, \
            "Update permission not correctly saved {}".format(role.delete)

    @ddt.data(
        {
            "mandatory": True,
            "exp_response": MANDATORY_ROLE_RESPONSE
        },
        {
            "mandatory": False,
            "exp_response": NON_MANDATORY_ROLE_RESPONSE
        },
    )
    @ddt.unpack
    def test_mandatory_delete(self, mandatory, exp_response):
        """Test set empty field via import if acr mandatory is {mandatory}"""
        role = factories.AccessControlRoleFactory(
            name=ROLE_NAME,
            object_type="Program",
            mandatory=mandatory,
        )
        with factories.single_commit():
            user = factories.PersonFactory()
            program = factories.ProgramFactory()
            role_id = role.id
            factories.AccessControlPersonFactory(
                ac_list=program.acr_name_acl_map[ROLE_NAME],
                person=user,
            )
        response = self.import_data(
            OrderedDict([
                ("object_type", "Program"),
                ("Code*", program.slug),
                (ROLE_NAME, "--"),
            ]))
        self._check_csv_response(response, exp_response)
        db_data = defaultdict(set)
        program = all_models.Program.query.get(program.id)
        for person, acl in program.access_control_list:
            db_data[acl.ac_role_id].add(person.id)
        if mandatory:
            cur_user = all_models.Person.query.filter_by(
                email="*****@*****.**").first()
            self.assertEqual(set([cur_user.id]), db_data[role_id])
        else:
            self.assertFalse(db_data[role_id])

    def test_only_admin_can_post(self):
        """Only admin users should be able to POST access control roles"""
        for name in ("Creator", "Reader", "Editor"):
            person = self.people.get(name)
            self.api.set_user(person)
            response = self._post_role()
            assert response.status_code == 403, \
                "Non admins should get forbidden error when POSTing role. {}".format(
                    response.status)

    @ddt.data(
        ("name", "New ACR"),
        ("read", False),
        ("mandatory", False),
        ("non_editable", False),
    )
    @ddt.unpack
    def test_modify_non_editable_role(self, field_name, field_value):
        """Test if user can modify non-editable role"""
        # Primary Contacts role of Control is non-editable
        ac_role = AccessControlRole.query.filter_by(
            object_type="Control",
            name="Control Operators",
        ).first()

        response = self.api.put(ac_role, {field_name: field_value})
        assert response.status_code == 403, \
            "Forbidden error should be thrown when non-editable " \
            "role {} updated.".format(ac_role.name)

    def test_delete_non_editable_role(self):
        """Test if user can delete non-editable role"""
        # Primary Contacts role of Control is non-editable
        ac_role = AccessControlRole.query.filter_by(
            object_type="Control",
            name="Control Operators",
        ).first()

        response = self.api.delete(ac_role)
        assert response.status_code == 403, \
            "Forbidden error should be thrown when non-editable " \
            "role {} deleted.".format(ac_role.name)

    @ddt.data("Control")
    def test_create_from_ggrcq(self, object_type):
        """Test that create action only for GGRCQ."""
        with self.api.as_external():
            response = self._post_role(object_type=object_type)
            self.assertEqual(response.status_code, 201)

    @ddt.data("Control")
    def test_create_from_ggrc(self, object_type):
        """Test create action not allowed for GGRC."""
        response = self._post_role(object_type=object_type)
        self.assertEqual(response.status_code, 405)

    @ddt.data("Control")
    def test_modify_from_ggrcq(self, object_type):
        """Test that modify action only for GGRCQ."""
        with factories.single_commit():
            acr_id = factories.AccessControlRoleFactory(
                object_type=object_type).id

        with self.api.as_external():
            acr = all_models.AccessControlRole.query.get(acr_id)
            response = self.api.put(acr, {"name": "new acr"})
            self.assertEqual(response.status_code, 200)

    @ddt.data("Control")
    def test_modify_from_ggrc(self, object_type):
        """Test modify action not allowed for GGRC."""
        with factories.single_commit():
            acr = factories.AccessControlRoleFactory(object_type=object_type)

        response = self.api.put(acr, {"name": "new acr"})
        self.assertEqual(response.status_code, 405)

    @ddt.data("Control")
    def test_delete_from_ggrcq(self, object_type):
        """Test that modify action only for GGRCQ."""
        with factories.single_commit():
            acr_id = factories.AccessControlRoleFactory(
                object_type=object_type).id

        with self.api.as_external():
            acr = all_models.AccessControlRole.query.get(acr_id)
            response = self.api.delete(acr)
            self.assertEqual(response.status_code, 200)

    @ddt.data("Control")
    def test_delete_from_ggrc(self, object_type):
        """Test modify action not allowed for GGRC."""
        with factories.single_commit():
            acr = factories.AccessControlRoleFactory(object_type=object_type)

        response = self.api.delete(acr)
        self.assertEqual(response.status_code, 405)

    @ddt.data(
        {
            "name": "Test 1",
            "update": False,
            "read": False,
            "delete": True
        },
        {
            "name": "Test 2",
            "update": True,
            "read": False,
            "delete": False
        },
        {
            "name": "Test 3",
            "update": True,
            "read": False,
            "delete": True
        },
    )
    @ddt.unpack
    def test_create_with_wrong_options(self, name, update, read, delete):
        """ Test if user create ACR with wrong options."""
        options = [{
            'access_control_role': {
                'modal_title': 'Add Custom Role to type Regulation',
                'object_type': 'Regulation',
                'parent_type': 'Regulation',
                'context': {
                    'id': None
                },
                'delete': delete,
                'update': update,
                'read': read,
                'name': name
            }
        }]
        response = self.api.post(AccessControlRole, options)
        self.assert400(response)
Ejemplo n.º 56
0
class TestPersonResource(TestCase, WithQueryApi):
    """Tests for special people api endpoints."""
    def setUp(self):
        super(TestPersonResource, self).setUp()
        self.client.get("/login")
        self.api = Api()
        self.generator = WorkflowsGenerator()

    @staticmethod
    def _create_users_names_rbac(users):
        """Create name and Creator role for users, created vid PersonFactory"""
        if not users:
            return
        roles = {r.name: r for r in all_models.Role.query.all()}
        for user in users:
            user.name = user.email.split("@")[0]
            rbac_factories.UserRoleFactory(role=roles["Creator"], person=user)

    def assert_profile_get_successful(self, response, expected_datetime):
        """Verify assertions for successful GET profile method"""
        self.assert200(response)
        response_datetime = date_parser.parse(
            response.json["last_seen_whats_new"])
        self.assertEqual(expected_datetime, response_datetime)

    @freeze_time("2018-05-20 12:23:17")
    def test_profile_get_successful(self):
        """Test person_profile GET method successfully achieves correct data"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        response = self.api.client.get("/api/people/{}/profile".format(
            user.id))
        self.assert_profile_get_successful(response, default_date())

    def test_profile_get_no_profile(self):
        """Test person_profile GET method achieves data with missing profile"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        profiles_table = PersonProfile.__table__
        db_request = profiles_table.delete().where(
            profiles_table.c.person_id == user.id)
        db.engine.execute(db_request)
        with freeze_time("2018-05-28 23:30:10"):
            response = self.api.client.get("/api/people/{}/profile".format(
                user.id))
            self.assert_profile_get_successful(response, default_date())

    def test_profile_get_failed(self):
        """Test person_profiles GET method fails

    Now only logged user can request his profile
    """
        with factories.single_commit():
            valid_user = factories.PersonFactory()
            self._create_users_names_rbac([valid_user])

        response = self.client.get("/api/people/{}/profile".format(
            valid_user.id))
        # logged with default user during setUp
        self.assert403(response)
        response = self.api.client.get("/api/people/{}/profile".format(
            valid_user.id))
        # not authorized user
        self.assert403(response)

    @ddt.data("Creator", "Reader", "Editor", "Administrator")
    def test_profile_post_empty_body(self, role_name):
        """Test person_profile POST method with empty body - {}."""
        role = all_models.Role.query.filter(
            all_models.Role.name == role_name).one()
        with factories.single_commit():
            user = factories.PersonFactory()
            rbac_factories.UserRoleFactory(role=role, person=user)
        self.api.set_user(person=user)

        response = self.api.send_request(
            self.api.client.post,
            data={},
            api_link="/api/people/{}/profile".format(user.id))

        self.assert405(response)

    def test_profile_post_unauthorized(self):
        """Test person_profile POST method with empty body - No Access."""
        with factories.single_commit():
            user = factories.PersonFactory()

        response = self.api.send_request(
            self.api.client.post,
            data={},
            api_link="/api/people/{}/profile".format(user.id))
        # not authorized user
        self.assert405(response)

    def assert_profile_put_successful(self, response, correct_response, user,
                                      expected):
        """Verify assertions for successful PUT profile method"""
        self.assert200(response)
        self.assertEqual(response.json, correct_response)
        profile = PersonProfile.query.filter_by(person_id=user.id).first()
        self.assertEqual(profile.last_seen_whats_new,
                         date_parser.parse(expected))

    @ddt.data(["2018-05-20 16:38:17", "2018-05-20 16:38:17"],
              ["2018-07-05T14:11:31Z", "2018-07-05T14:11:31"])
    @ddt.unpack
    def test_profile_put_successful(self, new_date, expected_date):
        """Test person_profile PUT method for setting data and correct response"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        data = {"last_seen_whats_new": new_date}
        correct_response = {"Person": {"id": user.id, "profile": data}}
        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        self.assert_profile_put_successful(response, correct_response, user,
                                           expected_date)

    def test_profile_put_no_profile(self):
        """Test person_profile PUT method for setting data for missing profile"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        new_date = "2018-05-20 22:05:17"
        data = {"last_seen_whats_new": new_date}
        correct_response = {"Person": {"id": user.id, "profile": data}}
        profiles_table = PersonProfile.__table__
        db_request = profiles_table.delete().where(
            profiles_table.c.person_id == user.id)
        db.engine.execute(db_request)
        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        self.assert_profile_put_successful(response, correct_response, user,
                                           new_date)

    def test_profile_put_unauthorized(self):
        """Test person_profiles PUT method fails for unauthorized user"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])

        new_date = "2018-05-20 22:05:17"
        data = {"last_seen_whats_new": new_date}
        response = self.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
        # logged with default user during setUp
        self.assert403(response)
        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        # not authorized user
        self.assert403(response)

    @ddt.data({"last_seen_whats_new": "NOT A 123 DAT456A"}, {
        "other_key": "2018-05-20 22:05:17",
        "one_more_key": 42
    })
    def test_profile_put_corrupted_data(self, data):
        """Test person_profiles PUT method fails via incorrect request data

    If request doesn't have "last_seen_whats_new" key or date is incorrect,
      response is code 400 "Bad Request"
    """
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        # missed key in request
        self.assert400(response)

    def test_task_count_empty(self):
        """Test query count without any workflows and tasks."""
        user = all_models.Person.query.first()
        response = self.client.get("/api/people/{}/task_count".format(user.id))
        self.assertEqual(response.json, {
            "open_task_count": 0,
            "has_overdue": False
        })

    @ddt.data(
        (True, [
            ("task 1", "Finished", 3, True, 3),
            ("task 1", "Verified", 2, True, 3),
            ("task 2", "Declined", 2, True, 3),
            ("task 2", "Verified", 1, False, 3),
            ("task 2", "Finished", 2, True, 3),
            ("task 3", "Verified", 1, True, 3),
            ("task 2", "Verified", 0, False, 3),
        ]),
        (False, [
            ("task 1", "Finished", 2, True, 3),
            ("task 2", "In Progress", 2, True, 3),
            ("task 2", "Finished", 1, False, 3),
            ("task 3", "Finished", 0, False, 3),
        ]),
    )
    @ddt.unpack
    def test_task_count(self, is_verification_needed, transitions):
        """Test person task counts.

    This tests checks for correct task counts
     - with inactive workflows and
     - with overdue tasks
     - without overdue tasks
     - with finished overdue tasks

    The four checks are done in a single test due to complex differences
    between tests that make ddt cumbersome and the single test also improves
    integration test performance due to slow workflow setup stage.
    """
        # pylint: disable=too-many-locals

        user = all_models.Person.query.first()
        dummy_user = factories.PersonFactory()
        user_id = user.id
        role_id = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == "Task Assignees",
            all_models.AccessControlRole.object_type == "TaskGroupTask",
        ).one().id
        secondary_role_id = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == "Task Secondary Assignees",
            all_models.AccessControlRole.object_type == "TaskGroupTask",
        ).one().id

        one_time_workflow = {
            "title":
            "Person resource test workflow",
            "notify_on_change":
            True,
            "description":
            "some test workflow",
            "owners": [create_stub(user)],
            "is_verification_needed":
            is_verification_needed,
            "task_groups": [{
                "title":
                "one time task group",
                "contact":
                create_stub(user),
                "task_group_tasks": [
                    {
                        "title":
                        "task 1",
                        "description":
                        "some task",
                        "access_control_list": [
                            acl_helper.get_acl_json(role_id, user.id),
                            acl_helper.get_acl_json(secondary_role_id, user.id)
                        ],
                        "start_date":
                        date(2017, 5, 5),
                        "end_date":
                        date(2017, 8, 15),
                    },
                    {
                        "title":
                        "task 2",
                        "description":
                        "some task 3",
                        "access_control_list": [
                            acl_helper.get_acl_json(role_id, user.id),
                            acl_helper.get_acl_json(secondary_role_id,
                                                    user.id),
                            acl_helper.get_acl_json(secondary_role_id,
                                                    dummy_user.id)
                        ],
                        "start_date":
                        date(2017, 5, 5),
                        "end_date":
                        date(2017, 9, 16),
                    },
                    {
                        "title":
                        "task 3",
                        "description":
                        "some task 4",
                        "access_control_list": [
                            acl_helper.get_acl_json(role_id, user.id),
                            acl_helper.get_acl_json(role_id, dummy_user.id)
                        ],
                        "start_date":
                        date(2017, 6, 5),
                        "end_date":
                        date(2017, 10, 16),
                    },
                    {
                        "title":
                        "dummy task 4",  # task should not counted
                        "description":
                        "some task 4",
                        "access_control_list":
                        [acl_helper.get_acl_json(role_id, dummy_user.id)],
                        "start_date":
                        date(2017, 6, 5),
                        "end_date":
                        date(2017, 11, 17),
                    },
                    {
                        "title":
                        "dummy task 5",  # task should not counted
                        "description":
                        "some task 4",
                        "access_control_list":
                        [acl_helper.get_acl_json(role_id, dummy_user.id)],
                        "start_date":
                        date(2017, 6, 5),
                        "end_date":
                        date(2017, 11, 18),
                    }
                ],
                "task_group_objects": []
            }]
        }

        inactive_workflow = {
            "title":
            "Activated workflow with archived cycles",
            "notify_on_change":
            True,
            "description":
            "Extra test workflow",
            "owners": [create_stub(user)],
            "task_groups": [{
                "title":
                "Extra task group",
                "contact":
                create_stub(user),
                "task_group_tasks": [{
                    "title":
                    "not counted existing task",
                    "description":
                    "",
                    "access_control_list":
                    [acl_helper.get_acl_json(role_id, user.id)],
                    "start_date":
                    date(2017, 5, 5),
                    "end_date":
                    date(2017, 8, 15),
                }],
                "task_group_objects": []
            }]
        }

        with freeze_time("2017-10-16 05:09:10"):
            self.client.get("/login")
            # Activate normal one time workflow
            _, workflow = self.generator.generate_workflow(one_time_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            tasks = {t.title: t for t in cycle.cycle_task_group_object_tasks}
            _, workflow = self.generator.activate_workflow(workflow)

            # Activate and close the inactive workflow
            _, workflow = self.generator.generate_workflow(inactive_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            _, workflow = self.generator.activate_workflow(workflow)
            self.generator.modify_object(cycle, data={"is_current": False})

        with freeze_time("2017-7-16 07:09:10"):
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 3,
                "has_overdue": False
            })

        with freeze_time("2017-10-16 08:09:10"):  # same day as task 3 end date
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 3,
                "has_overdue": True
            })

            for task, status, count, overdue, my_work_count in transitions:
                self.generator.modify_object(tasks[task],
                                             data={"status": status})
                task_count_response = \
                    self.client.get("/api/people/{}/task_count".format(user_id))
                my_work_count_response = \
                    self.client.get("/api/people/{}/my_work_count".format(user_id))

                self.assertEqual(task_count_response.json, {
                    "open_task_count": count,
                    "has_overdue": overdue
                })

                self.assertEqual(
                    my_work_count_response.json["CycleTaskGroupObjectTask"],
                    my_work_count)

    def test_task_count_multiple_wfs(self):
        """Test task count with both verified and non verified workflows.

    This checks task counts with 4 tasks
        2017, 8, 15  - verification needed
        2017, 11, 18  - verification needed
        2017, 8, 15  - No verification needed
        2017, 11, 18  - No verification needed
    """

        user = all_models.Person.query.first()
        user_id = user.id
        role_id = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == "Task Assignees",
            all_models.AccessControlRole.object_type == "TaskGroupTask",
        ).one().id
        workflow_template = {
            "title":
            "verified workflow",
            "owners": [create_stub(user)],
            "is_verification_needed":
            True,
            "task_groups": [{
                "title":
                "one time task group",
                "contact":
                create_stub(user),
                "task_group_tasks": [{
                    "title":
                    "task 1",
                    "description":
                    "some task",
                    "access_control_list":
                    [acl_helper.get_acl_json(role_id, user.id)],
                    "start_date":
                    date(2017, 5, 5),
                    "end_date":
                    date(2017, 8, 15),
                }, {
                    "title":
                    "dummy task 5",
                    "description":
                    "some task 4",
                    "access_control_list":
                    [acl_helper.get_acl_json(role_id, user.id)],
                    "start_date":
                    date(2017, 6, 5),
                    "end_date":
                    date(2017, 11, 18),
                }],
                "task_group_objects": []
            }]
        }

        with freeze_time("2017-10-16 05:09:10"):
            self.client.get("/login")
            verified_workflow = workflow_template.copy()
            verified_workflow["is_verification_needed"] = True
            _, workflow = self.generator.generate_workflow(verified_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            verified_tasks = {
                task.title: task
                for task in cycle.cycle_task_group_object_tasks
            }
            _, workflow = self.generator.activate_workflow(workflow)

            non_verified_workflow = workflow_template.copy()
            non_verified_workflow["is_verification_needed"] = False
            _, workflow = self.generator.generate_workflow(
                non_verified_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            non_verified_tasks = {
                task.title: task
                for task in cycle.cycle_task_group_object_tasks
            }
            _, workflow = self.generator.activate_workflow(workflow)

        with freeze_time("2017-7-16 07:09:10"):
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 4,
                "has_overdue": False
            })

        with freeze_time("2017-10-16 08:09:10"):
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 4,
                "has_overdue": True
            })

            # transition 1, task that needs verification goes to finished state. This
            # transition should not change anything
            self.generator.modify_object(verified_tasks["task 1"],
                                         data={"status": "Finished"})
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 4,
                "has_overdue": True
            })

            # transition 2, task that needs verification goes to verified state. This
            # transition should reduce task count.
            self.generator.modify_object(verified_tasks["task 1"],
                                         data={"status": "Verified"})
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 3,
                "has_overdue": True
            })

            # transition 3, task that does not need verification goes into Finished
            # state. This transition should reduce task count and remove all overdue
            # tasks
            self.generator.modify_object(non_verified_tasks["task 1"],
                                         data={"status": "Finished"})
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 2,
                "has_overdue": False
            })

    @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200),
              ("Administrator", 200))
    @ddt.unpack
    def test_person_editing(self, role_name, status):
        """{0} should receive {1} status code on edit Person."""
        role = all_models.Role.query.filter(
            all_models.Role.name == role_name).one()
        with factories.single_commit():
            client_user = factories.PersonFactory()
            rbac_factories.UserRoleFactory(role=role, person=client_user)
        self.api.set_user(client_user)
        self.client.get("/login")
        base_email = "*****@*****.**"
        person = factories.PersonFactory(email=base_email)
        person_id = person.id
        new_email = "new_{}".format(base_email)
        resp = self.api.put(person, {"email": new_email})
        self.assertEqual(status, resp.status_code)
        person = all_models.Person.query.get(person_id)
        if status == 200:
            self.assertEqual(new_email, person.email)
        else:
            self.assertEqual(base_email, person.email)
Ejemplo n.º 57
0
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")
Ejemplo n.º 58
0
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())
Ejemplo n.º 59
0
class TestIssueMapping(TestCase):
    """Test Issue mapping"""
    def setup_roles(self):
        """Setup necessary roles needed by the tests"""
        query = all_models.Role.query
        self.roles = {
            'creator': query.filter_by(name="Creator").first(),
            'auditor': query.filter_by(name="Auditor").first(),
            'program_editor': query.filter_by(name="ProgramEditor").first()
        }

    def setup_users(self):
        """Creates two creator users"""
        self.users = {}
        for user_name in ('auditor', 'programeditor'):
            user = factories.PersonFactory()
            rbac_factories.UserRoleFactory(role=self.roles['creator'],
                                           person=user)
            self.users[user_name] = user

    def setup_audits(self):
        """Create an audit and an archived audit"""
        self.audits = {
            False: self.create_audit(archived=False),
            True: self.create_audit(archived=True)
        }

    def setup_snapshots_and_issue(self):
        """Create snapshot & issue objects"""
        self.snapshots = {}
        self.issues = {}
        self.control = factories.ControlFactory()
        revision = all_models.Revision.query.filter(
            all_models.Revision.resource_type == self.control.type).first()
        for is_archived in (False, True):
            audit = self.audits[is_archived]
            # Create a snapshot
            self.snapshots[is_archived] = factories.SnapshotFactory(
                child_id=revision.resource_id,
                child_type=revision.resource_type,
                revision=revision,
                parent=audit,
                context=audit.context,
            )
            # Create an issue
            issue = factories.IssueFactory()
            self.issues[is_archived] = issue
            # Map issue to audit
            factories.RelationshipFactory(source=audit,
                                          destination=issue,
                                          context=audit.context)

    def create_audit(self, archived=False):
        """Create an audit object and fix the it's context"""
        audit = factories.AuditFactory(archived=archived)

        # Add auditor & program editor roles
        rbac_factories.UserRoleFactory(context=audit.context,
                                       role=self.roles['auditor'],
                                       person=self.users['auditor'])
        rbac_factories.UserRoleFactory(context=audit.program.context,
                                       role=self.roles['program_editor'],
                                       person=self.users['programeditor'])

        return audit

    def setUp(self):
        """Prepare data needed to run the tests"""
        self.api = Api()
        self.setup_roles()
        self.setup_users()
        self.setup_audits()
        self.setup_snapshots_and_issue()

    @data(
        # user_name, is_archived
        ('auditor', True),
        ('programeditor', True),
        ('auditor', False),
        ('programeditor', False),
    )
    @unpack
    def test_mapping_to_issue(self, user_name, is_archived):
        """Test mapping snapshots to issue"""
        user = self.users[user_name]
        payload = _get_map_dict(self.snapshots[is_archived],
                                self.issues[is_archived])
        self.api.set_user(user)

        # Try to map to audit
        response = self.api.post(all_models.Relationship, payload)
        self.assertStatus(response, 201)

        rel_id = response.json['relationship']['id']
        relationship = all_models.Relationship.query.filter_by(
            id=rel_id).first()
        response = self.api.delete(relationship)
        self.assertStatus(response, 200)
Ejemplo n.º 60
0
class TestRevisionHistory(TestCase):
  """Test checks permissions for revision history."""

  def setUp(self):
    super(TestRevisionHistory, self).setUp()
    self.api = Api()
    roles = {r.name: r for r in all_models.Role.query.all()}

    with factories.single_commit():
      factories.AccessControlRoleFactory(
          name="ACL_Reader",
          object_type="Control",
          update=0,
      )
      factories.AccessControlRoleFactory(
          name="ACL_Editor",
          object_type="Control"
      ),

    with factories.single_commit():
      self.control = factories.ControlFactory()
      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(),
          "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=self.people[role_name],
        )
    with factories.single_commit():
      for role_name in ["ACL_Reader", "ACL_Editor"]:
        rbac_factories.UserRoleFactory(role=roles["Creator"],
                                       person=self.people[role_name])
        factories.AccessControlPersonFactory(
            ac_list=self.control.acr_name_acl_map[role_name],
            person=self.people[role_name],
        )

  @ddt.data(
      ("Creator", True),
      ("Reader", False),
      ("Editor", False),
      ("ACL_Reader", False),
      ("ACL_Editor", False),
      ("Administrator", False),
      ("Program Editors", False),
      ("Program Managers", False),
      ("Program Readers", False),
  )
  @ddt.unpack
  def test_get(self, role_name, empty):
    """Test get revision history for {0}."""
    control_id = self.control.id
    query = all_models.Revision.query.filter(
        all_models.Revision.resource_id == control_id,
        all_models.Revision.resource_type == self.control.type,
    )
    if empty:
      ids = []
    else:
      ids = [i.id for i in query]
    self.api.set_user(self.people[role_name])
    self.client.get("/login")
    resp = self.api.client.get(
        "/api/revisions"
        "?resource_type=Control&resource_id={}".format(control_id)
    )
    self.assertEqual(
        ids,
        [i["id"] for i in resp.json["revisions_collection"]["revisions"]])

  def update_revisions(self, obj):
    """Assert revision diff between api and calculated in test.."""
    query = all_models.Revision.query.filter(
        all_models.Revision.resource_id == obj.id,
        all_models.Revision.resource_type == obj.type,
    ).order_by(
        sa.desc(all_models.Revision.updated_at)
    )
    diffs = [(i.id, json.loads(json.dumps(i.diff_with_current())))
             for i in query]
    for i in range(3):
      resp = self.api.client.get(
          "/api/revisions"
          "?__sort=-updated_at"
          "&resource_type={}"
          "&resource_id={}"
          "&_={}".format(
              obj.type,
              obj.id,
              random.randint(1100000000, 1153513123412)
          )
      )
      resp_diffs = [(i["id"], i["diff_with_current"])
                    for i in resp.json["revisions_collection"]["revisions"]]
      self.assertDictEqual(dict(diffs), dict(resp_diffs))
    self.assertFalse(any(resp_diffs[0][1].values()))

  def test_control_memcache(self):
    """Test get updated control revisions."""
    control_id = self.control.id
    self.api.put(self.control, {"title": "new_title"})
    self.control = all_models.Control.eager_query().get(control_id)
    self.update_revisions(self.control)
    db.session.expire_all()
    self.control = all_models.Control.eager_query().get(control_id)
    self.api.put(self.control, {"description": "new test description BLA"})
    self.control = all_models.Control.eager_query().get(control_id)
    self.update_revisions(self.control)
    self.api.put(self.control, {"description": "bla bla bla"})
    self.control = all_models.Control.eager_query().get(control_id)
    self.update_revisions(self.control)

  def test_risk_memcache(self):
    """Test get updated risk revisions."""
    risk = factories.RiskFactory()
    risk_id = risk.id
    self.api.put(risk, {"title": "new_title"})
    self.update_revisions(risk)
    db.session.expire_all()
    risk = all_models.Risk.eager_query().get(risk_id)
    self.api.put(risk, {"description": "new test description BLA"})
    risk = all_models.Risk.eager_query().get(risk_id)
    self.update_revisions(risk)
    risk = all_models.Risk.eager_query().get(risk_id)
    self.api.put(risk, {"description": "BLA bla bla"})
    risk = all_models.Risk.eager_query().get(risk_id)
    self.update_revisions(risk)

  def test_change_log(self):
    """Test Change log where CAV attribute_object_id is str in revision
     content"""
    person = factories.PersonFactory()
    cad = factories.CustomAttributeDefinitionFactory(
        definition_type="control",
        definition_id=None,
        attribute_type="Map:Person",
        title="Global Person CA",
    )
    factories.CustomAttributeValueFactory(
        attributable=self.control,
        custom_attribute=cad,
        attribute_value=person.type,
        attribute_object_id=str(person.id),
    )
    self.api.put(self.control, {"title": "new_title"})
    control = all_models.Control.eager_query().get(self.control.id)
    self.update_revisions(control)

  @ddt.data(True, False)
  def test_get_mandatory_acrs(self, mandatory):
    """ACR and mandatory meta info if mandatory flag is {0}."""
    control_id = self.control.id
    acr = factories.AccessControlRoleFactory(name="test_name",
                                             object_type=self.control.type,
                                             mandatory=mandatory)
    acr_id = acr.id
    resp = self.api.client.get(
        "/api/revisions"
        "?resource_type=Control&resource_id={}".format(control_id)
    )
    collection = resp.json["revisions_collection"]["revisions"]
    self.assertTrue(collection)
    self.assertIn("meta", collection[0])
    self.assertIn("mandatory", collection[0]["meta"])
    self.assertIn("access_control_roles", collection[0]["meta"]["mandatory"])
    mandatory_acrs = collection[0]["meta"]["mandatory"]["access_control_roles"]
    self.assertEqual(mandatory, acr_id in mandatory_acrs)

  @ddt.data(True, False)
  def test_get_mandatory_cads(self, mandatory):
    """CAD and mandatory meta info if mandatory flag is {0}."""
    control_id = self.control.id
    cad = factories.CustomAttributeDefinitionFactory(
        title="test_name",
        definition_type="control",
        mandatory=mandatory)
    cad_id = cad.id
    resp = self.api.client.get(
        "/api/revisions"
        "?resource_type=Control&resource_id={}".format(control_id)
    )
    collection = resp.json["revisions_collection"]["revisions"]
    self.assertTrue(collection)
    self.assertIn("meta", collection[0])
    self.assertIn("mandatory", collection[0]["meta"])
    mandatory_meta = collection[0]["meta"]["mandatory"]
    self.assertIn("custom_attribute_definitions", mandatory_meta)
    mandatory_cads = mandatory_meta["custom_attribute_definitions"]
    self.assertEqual(mandatory, cad_id in mandatory_cads)

  @ddt.data(
      {"factory": factories.ControlFactory,
       "fields": ['test_plan', 'status', 'notes',
                  'description', 'title', 'slug', 'folder']},
      {"factory": factories.RiskFactory,
       "fields": ['test_plan', 'status', 'description',
                  'notes', 'title', 'slug', 'folder', 'risk_type']},
  )
  @ddt.unpack
  def test_get_mandatory_fields(self, factory, fields):
    """Fields mandatory meta info for {factory._meta.model}."""
    instance = factory()
    resp = self.api.client.get(
        "/api/revisions"
        "?resource_type={}&resource_id={}".format(instance.type, instance.id)
    )
    collection = resp.json["revisions_collection"]["revisions"]
    self.assertTrue(collection)
    self.assertIn("meta", collection[0])
    self.assertIn("mandatory", collection[0]["meta"])
    mandatory_meta = collection[0]["meta"]["mandatory"]
    self.assertIn("fields", mandatory_meta)
    self.assertItemsEqual(fields, mandatory_meta["fields"])

  @ddt.data(
      {"factory": factories.ControlFactory, "fields": []},
      {"factory": factories.RiskFactory, "fields": []},
      {"factory": factories.AssessmentFactory, "fields": []},
  )
  @ddt.unpack
  def test_mandatory_mapping_list(self, factory, fields):
    """Mapping List mandatory meta info for {factory._meta.model}."""
    instance = factory()
    resp = self.api.client.get(
        "/api/revisions"
        "?resource_type={}&resource_id={}".format(instance.type, instance.id)
    )
    collection = resp.json["revisions_collection"]["revisions"]
    self.assertTrue(collection)
    self.assertIn("meta", collection[0])
    self.assertIn("mandatory", collection[0]["meta"])
    mandatory_meta = collection[0]["meta"]["mandatory"]
    self.assertIn("mapping_list_fields", mandatory_meta)
    self.assertEqual(fields, mandatory_meta["mapping_list_fields"])

  @ddt.data(
      {"factory": factories.ControlFactory, "fields": []},
      {"factory": factories.RiskFactory, "fields": []},
      {"factory": factories.AssessmentFactory, "fields": ["audit"]},
  )
  @ddt.unpack
  def test_mandatory_mappings(self, factory, fields):
    """Mapping fields mandatory meta info for {factory._meta.model}."""
    instance = factory()
    resp = self.api.client.get(
        "/api/revisions"
        "?resource_type={}&resource_id={}".format(instance.type, instance.id)
    )
    collection = resp.json["revisions_collection"]["revisions"]
    self.assertTrue(collection)
    self.assertIn("meta", collection[0])
    self.assertIn("mandatory", collection[0]["meta"])
    mandatory_meta = collection[0]["meta"]["mandatory"]
    self.assertIn("mapping_fields", mandatory_meta)
    self.assertEqual(fields, mandatory_meta["mapping_fields"])