Exemplo n.º 1
0
def handle_relationship_creation(session, flush_context):
    """Create relations for mapped objects."""
    # pylint: disable=unused-argument
    base_objects = defaultdict(set)
    related_objects = defaultdict(set)
    snapshot_ids = {}
    for obj in session.new:
        if isinstance(obj, all_models.Relationship) and (
                issubclass(type(obj.source), Assignable)
                or issubclass(type(obj.destination), Assignable)):
            assign_obj, other = obj.source, obj.destination
            if not issubclass(type(obj.source), Assignable):
                assign_obj, other = other, assign_obj
            for acl in assign_obj.access_control_list:
                acr_id = acl.ac_role.id if acl.ac_role else acl.ac_role_id
                ac_role = get_custom_roles_for(acl.object_type).get(
                    acr_id, None)
                if ac_role in assign_obj.ASSIGNEE_TYPES:
                    assign_stub = Stub(assign_obj.type, assign_obj.id)
                    other_stub = Stub(other.type, other.id)
                    base_objects[assign_stub].add(acl)
                    related_objects[assign_stub].add(other_stub)

                    if other.type == "Snapshot":
                        snapshot_ids[other.id] = assign_stub

    if base_objects:
        if snapshot_ids:
            add_related_snapshots(snapshot_ids, related_objects)
        create_related_roles(base_objects, related_objects)
Exemplo n.º 2
0
  def _flush(self, parent_relationship):
    """Manually INSERT generated automappings."""
    if not self.auto_mappings:
      return
    with benchmark("Automapping flush"):
      current_user_id = login.get_current_user_id()
      automapping_result = db.session.execute(
          Automapping.__table__.insert().values(
              relationship_id=parent_relationship.id,
              source_id=parent_relationship.source_id,
              source_type=parent_relationship.source_type,
              destination_id=parent_relationship.destination_id,
              destination_type=parent_relationship.destination_type,
              modified_by_id=current_user_id,
          )
      )
      automapping_id = automapping_result.inserted_primary_key[0]
      self.automapping_ids.add(automapping_id)
      now = datetime.utcnow()
      # We are doing an INSERT IGNORE INTO here to mitigate a race condition
      # that happens when multiple simultaneous requests create the same
      # automapping. If a relationship object fails our unique constraint
      # it means that the mapping was already created by another request
      # and we can safely ignore it.
      inserter = Relationship.__table__.insert().prefix_with("IGNORE")
      original = self.order(Stub.from_source(parent_relationship),
                            Stub.from_destination(parent_relationship))
      db.session.execute(inserter.values([{
          "id": None,
          "modified_by_id": current_user_id,
          "created_at": now,
          "updated_at": now,
          "source_id": src.id,
          "source_type": src.type,
          "destination_id": dst.id,
          "destination_type": dst.type,
          "context_id": None,
          "status": None,
          "parent_id": parent_relationship.id,
          "automapping_id": automapping_id,
          "is_external": False}
          for src, dst in self.auto_mappings
          if (src, dst) != original]))  # (src, dst) is sorted

      self._set_audit_id_for_issues(automapping_id)

      cache = Cache.get_cache(create=True)
      if cache:
        # Add inserted relationships into new objects collection of the cache,
        # so that they will be logged within event and appropriate revisions
        # will be created.
        cache.new.update(
            (relationship, relationship.log_json())
            for relationship in Relationship.query.filter_by(
                automapping_id=automapping_id,
            )
        )
Exemplo n.º 3
0
  def _flush(self, parent_relationship):
    """Manually INSERT generated automappings."""
    if not self.auto_mappings:
      return
    with benchmark("Automapping flush"):
      current_user_id = login.get_current_user_id()
      automapping_result = db.session.execute(
          Automapping.__table__.insert().values(
              relationship_id=parent_relationship.id,
              source_id=parent_relationship.source_id,
              source_type=parent_relationship.source_type,
              destination_id=parent_relationship.destination_id,
              destination_type=parent_relationship.destination_type,
          )
      )
      automapping_id = automapping_result.inserted_primary_key[0]
      self.automapping_ids.add(automapping_id)
      now = datetime.utcnow()
      # We are doing an INSERT IGNORE INTO here to mitigate a race condition
      # that happens when multiple simultaneous requests create the same
      # automapping. If a relationship object fails our unique constraint
      # it means that the mapping was already created by another request
      # and we can safely ignore it.
      inserter = Relationship.__table__.insert().prefix_with("IGNORE")
      original = self.order(Stub.from_source(parent_relationship),
                            Stub.from_destination(parent_relationship))
      db.session.execute(inserter.values([{
          "id": None,
          "modified_by_id": current_user_id,
          "created_at": now,
          "updated_at": now,
          "source_id": src.id,
          "source_type": src.type,
          "destination_id": dst.id,
          "destination_type": dst.type,
          "context_id": None,
          "status": None,
          "parent_id": parent_relationship.id,
          "automapping_id": automapping_id,
          "is_external": False}
          for src, dst in self.auto_mappings
          if (src, dst) != original]))  # (src, dst) is sorted

      self._set_audit_id_for_issues(automapping_id)

      cache = Cache.get_cache(create=True)
      if cache:
        # Add inserted relationships into new objects collection of the cache,
        # so that they will be logged within event and appropriate revisions
        # will be created.
        cache.new.update(
            (relationship, relationship.log_json())
            for relationship in Relationship.query.filter_by(
                automapping_id=automapping_id,
            )
        )
Exemplo n.º 4
0
    def generate_automappings(self, relationship):
        """Generate Automappings for a given relationship"""
        # pylint: disable=protected-access
        self.auto_mappings = set()
        with benchmark("Automapping generate_automappings"):
            # initial relationship is special since it is already created and
            # processing it would abort the loop so we manually enqueue the
            # neighborhood
            src = Stub.from_source(relationship)
            dst = Stub.from_destination(relationship)
            self._step(src, dst)
            self._step(dst, src)
            while self.queue:
                if len(self.auto_mappings) > self.COUNT_LIMIT:
                    break
                src, dst = entry = self.queue.pop()

                if {src.type, dst.type} != {"Audit", "Issue"}:
                    # Auditor doesn't have edit (+map) permission on the Audit,
                    # but the Auditor should be allowed to Raise an Issue.
                    # Since Issue-Assessment-Audit is the only rule that
                    # triggers Issue to Audit mapping, we should skip the
                    # permission check for it
                    if not (permissions.is_allowed_update(
                            src.type, src.id, None)
                            and permissions.is_allowed_update(
                                dst.type, dst.id, None)):
                        continue

                created = self._ensure_relationship(src, dst)
                self.processed.add(entry)
                if not created:
                    # If the edge already exists it means that auto mappings for it have
                    # already been processed and it is safe to cut here.
                    continue
                self._step(src, dst)
                self._step(dst, src)

            if len(self.auto_mappings) <= self.COUNT_LIMIT:
                self._flush(relationship)
            else:
                relationship._json_extras = {  # pylint: disable=protected-access
                    'automapping_limit_exceeded': True
                }
Exemplo n.º 5
0
    def generate_automappings(self, relationship):
        """Generate Automappings for a given relationship"""
        self.auto_mappings = set()

        # initial relationship is special since it is already created and
        # processing it would abort the loop so we manually enqueue the
        # neighborhood
        src = Stub.from_source(relationship)
        dst = Stub.from_destination(relationship)
        self._step(src, dst)
        self._step(dst, src)
        while self.queue:
            if len(self.auto_mappings) > self.COUNT_LIMIT:
                break
            src, dst = entry = self.queue.pop()

            if {src.type, dst.type} not in self._AUTOMAP_WITHOUT_PERMISSION:
                # Mapping between some objects should be created even if there is no
                # permission to edit (+map) this objects. Thus permissions check for
                # them should be skipped.
                if not (permissions.is_allowed_update(src.type, src.id, None)
                        and permissions.is_allowed_update(
                            dst.type, dst.id, None)):
                    continue

            created = self._ensure_relationship(src, dst)
            self.processed.add(entry)
            if not created:
                # If the edge already exists it means that auto mappings for it have
                # already been processed and it is safe to cut here.
                continue
            self._step(src, dst)
            self._step(dst, src)

        if len(self.auto_mappings) <= self.COUNT_LIMIT:
            if self.auto_mappings:
                logger.info("Automapping count: count=%s",
                            len(self.auto_mappings))
            self._flush(relationship)
        else:
            logger.error("Automapping limit exceeded: limit=%s, count=%s",
                         self.COUNT_LIMIT, len(self.auto_mappings))
Exemplo n.º 6
0
  def generate_automappings(self, relationship):
    """Generate Automappings for a given relationship"""
    # pylint: disable=protected-access
    self.auto_mappings = set()
    with benchmark("Automapping generate_automappings"):
      # initial relationship is special since it is already created and
      # processing it would abort the loop so we manually enqueue the
      # neighborhood
      src = Stub.from_source(relationship)
      dst = Stub.from_destination(relationship)
      self._step(src, dst)
      self._step(dst, src)
      while self.queue:
        if len(self.auto_mappings) > self.COUNT_LIMIT:
          break
        src, dst = entry = self.queue.pop()

        if {src.type, dst.type} != {"Audit", "Issue"}:
          # Auditor doesn't have edit (+map) permission on the Audit,
          # but the Auditor should be allowed to Raise an Issue.
          # Since Issue-Assessment-Audit is the only rule that
          # triggers Issue to Audit mapping, we should skip the
          # permission check for it
          if not (permissions.is_allowed_update(src.type, src.id, None) and
                  permissions.is_allowed_update(dst.type, dst.id, None)):
            continue

        created = self._ensure_relationship(src, dst)
        self.processed.add(entry)
        if not created:
          # If the edge already exists it means that auto mappings for it have
          # already been processed and it is safe to cut here.
          continue
        self._step(src, dst)
        self._step(dst, src)

      if len(self.auto_mappings) <= self.COUNT_LIMIT:
        self._flush(relationship)
      else:
        logger.error("Automapping limit exceeded: limit=%s, count=%s",
                     self.COUNT_LIMIT, len(self.auto_mappings))
Exemplo n.º 7
0
def add_related_snapshots(snapshot_ids, related_objects):
    """Get Stubs of Objective and Regulations snapshots mapped to
  snapshot of Control

  Args:
    snapshot_ids(dict): Ids of control snapshots with Stub of assigned object.
    related_objects(dict): Dict of base assigned objects with Stubs of related.
  """
    related_regulations = related_regulation_snaps(snapshot_ids.keys())
    for base_snap, related_snap in related_regulations:
        rel_snap_stub = Stub("Snapshot", related_snap)
        related_objects[snapshot_ids[base_snap]].add(rel_snap_stub)
def handle_acl_creation(session):
    """Create relations for mapped objects."""
    base_objects = defaultdict(set)
    for obj in session.new:
        if isinstance(obj, all_models.AccessControlList):
            acr_id = obj.ac_role.id if obj.ac_role else obj.ac_role_id
            acr_name = get_custom_roles_for(obj.object_type).get(acr_id)
            if acr_name in Assignable.ASSIGNEE_TYPES:
                base_objects[Stub(obj.object_type, obj.object_id)].add(obj)
    if base_objects:
        related_objects = related(base_objects.keys(), RelationshipsCache())
        snapshot_ids = collect_snapshot_ids(related_objects)
        if snapshot_ids:
            add_related_snapshots(snapshot_ids, related_objects)
        create_related_roles(base_objects, related_objects)
Exemplo n.º 9
0
 def handle_relationships(self, propagation, acl):
     """Hanle relationships"""
     relationship_cache = self.relationship_cache
     role_map = self.program_roles
     acl_manager = self.access_control_list_manager
     program_stub = Stub(acl.object_type, acl.object_id)
     related_stubs = related([program_stub], relationship_cache)
     for stub in related_stubs[program_stub]:
         if not (propagation["type"] == "any"
                 or stub.type in propagation["type"].split(",")):
             continue
         role_id = role_map[ROLE_PROPAGATION[self._get_acr_name(acl)]]
         child = acl_manager.get_or_create(stub, acl, acl.person, role_id)
         if "propagate" in propagation:
             self.handle_propagation(propagation["propagate"], child)
Exemplo n.º 10
0
    def _create_mapped_acls(self, acl, role_map):
        """Helper to propagate roles for auditors and captains"""
        audit = acl.object
        assert isinstance(audit, all_models.Audit), \
            "`{}` role assigned to a non Audit object.".format(acl.ac_role.name)

        # Add Audit Captains Mapped role to all the objects in the audit
        snapshots_cache = self.caches["snapshots_cache"]
        acl_manager = self.caches["access_control_list_manager"]
        relationship_cache = self.caches["relationship_cache"]

        if audit.id not in snapshots_cache:
            snapshots_cache[audit.id] = all_models.Snapshot.query.filter(
                all_models.Snapshot.parent_id == audit.id,
                all_models.Snapshot.parent_type == "Audit").options(
                    load_only("id")).all()

        for snapshot in snapshots_cache[audit.id]:
            acl_manager.get_or_create(snapshot, acl, acl.person,
                                      role_map["Snapshot"])

        # Add Audit Captains Mapped to all related
        audit_stub = Stub(acl.object_type, acl.object_id)
        related_stubs = related([audit_stub], relationship_cache)

        for stub in related_stubs[audit_stub]:
            if stub.type not in ("Assessment", "AssessmentTemplate", "Issue",
                                 "Comment", "Document"):
                continue
            acl_manager.get_or_create(stub, acl, acl.person,
                                      role_map[stub.type])

        # Add Audit Captains Mapped to all realted comments and documents
        mapped_stubs = related(related_stubs[audit_stub], relationship_cache)
        for parent in mapped_stubs:
            for stub in mapped_stubs[parent]:
                if stub.type not in ("Comment", "Document"):
                    continue
                acl_manager.get_or_create(stub, acl, acl.person,
                                          role_map[stub.type])