Skip to content

Commit

Permalink
#2266 Add queries to retrieve audits
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Nov 29, 2021
1 parent eeea9ad commit d6485c8
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 8 deletions.
39 changes: 35 additions & 4 deletions thehive/app/org/thp/thehive/controllers/v0/AuditCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package org.thp.thehive.controllers.v0
import akka.actor.ActorRef
import akka.pattern.ask
import akka.util.Timeout
import org.thp.scalligraph.EntityIdOrName
import org.thp.scalligraph.controllers.Entrypoint
import org.thp.scalligraph.{EntityId, EntityIdOrName}
import org.thp.scalligraph.controllers.{Entrypoint, FieldsParser}
import org.thp.scalligraph.models.{Database, UMapping}
import org.thp.scalligraph.query.PredicateOps.PredicateOpsDefs
import org.thp.scalligraph.query._
import org.thp.scalligraph.traversal.TraversalOps._
import org.thp.scalligraph.traversal.{IteratorOutput, Traversal}
Expand Down Expand Up @@ -82,11 +83,41 @@ class PublicAudit @Inject() (auditSrv: AuditSrv, organisationSrv: OrganisationSr
)
override val outputQuery: Query = Query.output[RichAudit, Traversal.V[Audit]](_.richAudit)

override val extraQueries: Seq[ParamQuery[_]] = {
implicit val entityIdParser: FieldsParser[String] = FieldsParser.string.on("id")
Seq(
Query.initWithParam[String, Traversal.V[Audit]](
"listAuditFromObject",
(objectId, graph, authContext) =>
if (auditSrv.startTraversal(graph).has(_.objectId, objectId).v[Audit].limit(1).visible(organisationSrv)(authContext).exists)
auditSrv.startTraversal(graph).has(_.objectId, objectId).v[Audit]
else
graph.empty
)
)
}

override val publicProperties: PublicProperties =
PublicPropertyListBuilder[Audit]
.property("operation", UMapping.string)(_.rename("action").readonly)
.property("operation", UMapping.string)(
_.select(_.value(_.action).domainMap(actionToOperation))
.filter[String] {
case (_, audits, _, Right(p)) => audits.has(_.action, p.mapValue(operationToAction))
case (_, audits, _, Left(true)) => audits
case (_, audits, _, _) => audits.empty
}
.readonly
)
.property("details", UMapping.string)(_.field.readonly)
.property("objectType", UMapping.string.optional)(_.field.readonly)
.property("objectType", UMapping.string.optional)(
_.select(_.value(_.objectType).domainMap(fromObjectType))
.filter[String] {
case (_, audits, _, Right(p)) => audits.has(_.objectType, p.mapValue(toObjectType))
case (_, audits, _, Left(true)) => audits
case (_, audits, _, _) => audits.empty
}
.readonly
)
.property("objectId", UMapping.string.optional)(_.field.readonly)
.property("base", UMapping.boolean)(_.rename("mainAction").readonly)
.property("startDate", UMapping.date)(_.rename("_createdAt").readonly)
Expand Down
8 changes: 8 additions & 0 deletions thehive/app/org/thp/thehive/controllers/v0/Conversion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ object Conversion {
case _ => "Unknown"
}

def operationToAction(operation: String): String =
operation match {
case "Creation" => "create"
case "Update" => "update"
case "Delete" => "delete"
case _ => "Unknown"
}

def fromObjectType(objectType: String): String =
objectType match {
case "Task" => "case_task"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.thp.thehive.controllers.v0

import org.apache.tinkerpop.gremlin.structure.Vertex
import org.scalactic.Good
import org.thp.scalligraph.auth.AuthContext
import org.thp.scalligraph.controllers.{FObject, Field, FieldsParser}
Expand All @@ -12,6 +13,7 @@ import org.thp.scalligraph.utils.RichType
import org.thp.scalligraph.{BadRequestError, EntityId, GlobalQueryExecutor}
import org.thp.thehive.models._
import org.thp.thehive.services.AlertOps._
import org.thp.thehive.services.AuditOps._
import org.thp.thehive.services.CaseOps._
import org.thp.thehive.services.CaseTemplateOps._
import org.thp.thehive.services.LogOps._
Expand Down Expand Up @@ -103,7 +105,22 @@ class TheHiveQueryExecutor @Inject() (
publicDatas.map(_.getQuery) ++
publicDatas.map(_.pageQuery(limitedCountThreshold)) ++ // FIXME the value of limitedCountThreshold is read only once. The value is not updated.
publicDatas.map(_.outputQuery) ++
publicDatas.flatMap(_.extraQueries)
publicDatas.flatMap(_.extraQueries) :+
new Query {
override val name: String = "audits"
override def checkFrom(t: ru.Type): Boolean =
RichType.getTypeArgs(t, ru.typeOf[Traversal[_, _, _]]).drop(1).headOption.exists(_ =:= ru.typeOf[Vertex])
override def toType(t: ru.Type): ru.Type = ru.typeOf[Traversal.V[Audit]]
override def apply(param: Unit, fromType: ru.Type, from: Any, authContext: AuthContext): Any = from.asInstanceOf[Traversal.V[Any]].audits
} :+
new Query {
override val name: String = "auditsFromContext"
override def checkFrom(t: ru.Type): Boolean =
RichType.getTypeArgs(t, ru.typeOf[Traversal[_, _, _]]).drop(1).headOption.exists(_ =:= ru.typeOf[Vertex])
override def toType(t: ru.Type): ru.Type = ru.typeOf[Traversal.V[Audit]]
override def apply(param: Unit, fromType: ru.Type, from: Any, authContext: AuthContext): Any =
from.asInstanceOf[Traversal.V[Any]].auditsFromContext
}
override val version: (Int, Int) = 0 -> 0
}

Expand Down
16 changes: 15 additions & 1 deletion thehive/app/org/thp/thehive/controllers/v1/AuditCtrl.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.thp.thehive.controllers.v1

import org.thp.scalligraph.EntityIdOrName
import org.thp.scalligraph.controllers.Entrypoint
import org.thp.scalligraph.controllers.{Entrypoint, FieldsParser}
import org.thp.scalligraph.models.{Database, Schema}
import org.thp.scalligraph.query.{ParamQuery, PublicProperties, Query}
import org.thp.scalligraph.traversal.TraversalOps._
Expand Down Expand Up @@ -42,6 +42,20 @@ class AuditCtrl @Inject() (
)
override val outputQuery: Query = Query.output[RichAudit, Traversal.V[Audit]](_.richAudit)

override val extraQueries: Seq[ParamQuery[_]] = {
implicit val entityIdParser: FieldsParser[String] = FieldsParser.string.on("id")
Seq(
Query.initWithParam[String, Traversal.V[Audit]](
"listAuditFromObject",
(objectId, graph, authContext) =>
if (auditSrv.startTraversal(graph).has(_.objectId, objectId).v[Audit].limit(1).visible(organisationSrv)(authContext).exists)
auditSrv.startTraversal(graph).has(_.objectId, objectId).v[Audit]
else
graph.empty
)
)
}

def flow: Action[AnyContent] =
entrypoint("audit flow")
.authRoTransaction(db) { implicit request => implicit graph =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package org.thp.thehive.controllers.v1

import org.apache.tinkerpop.gremlin.structure.Vertex
import org.thp.scalligraph.EntityId
import org.thp.scalligraph.auth.AuthContext
import org.thp.scalligraph.controllers.{FObject, FieldsParser}
import org.thp.scalligraph.models.Database
import org.thp.scalligraph.query._
import org.thp.scalligraph.services.config.{ApplicationConfig, ConfigItem}
import org.thp.scalligraph.traversal.Traversal
import org.thp.scalligraph.utils.RichType
import org.thp.thehive.models.Audit
import org.thp.thehive.services.AuditOps._

import javax.inject.{Inject, Singleton}
import scala.reflect.runtime.{universe => ru}

case class InCase(caseId: EntityId)
case class InAlert(alertId: EntityId)
Expand Down Expand Up @@ -84,5 +91,20 @@ class TheHiveQueryExecutor @Inject() (
controllers.map(_.getQuery) ++
controllers.map(_.pageQuery(limitedCountThreshold)) ++ // FIXME the value of limitedCountThreshold is read only once. The value is not updated.
controllers.map(_.outputQuery) ++
controllers.flatMap(_.extraQueries)
controllers.flatMap(_.extraQueries) :+
new Query {
override val name: String = "audits"
override def checkFrom(t: ru.Type): Boolean =
RichType.getTypeArgs(t, ru.typeOf[Traversal[_, _, _]]).drop(1).headOption.exists(_ =:= ru.typeOf[Vertex])
override def toType(t: ru.Type): ru.Type = ru.typeOf[Traversal.V[Audit]]
override def apply(param: Unit, fromType: ru.Type, from: Any, authContext: AuthContext): Any = from.asInstanceOf[Traversal.V[Any]].audits
} :+
new Query {
override val name: String = "auditsFromContext"
override def checkFrom(t: ru.Type): Boolean =
RichType.getTypeArgs(t, ru.typeOf[Traversal[_, _, _]]).drop(1).headOption.exists(_ =:= ru.typeOf[Vertex])
override def toType(t: ru.Type): ru.Type = ru.typeOf[Traversal.V[Audit]]
override def apply(param: Unit, fromType: ru.Type, from: Any, authContext: AuthContext): Any =
from.asInstanceOf[Traversal.V[Any]].auditsFromContext
}
}
7 changes: 6 additions & 1 deletion thehive/app/org/thp/thehive/services/AuditSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.apache.tinkerpop.gremlin.structure.Transaction.Status
import org.apache.tinkerpop.gremlin.structure.Vertex
import org.thp.scalligraph.EntityId
import org.thp.scalligraph.auth.AuthContext
import org.thp.scalligraph.models.{Entity, _}
import org.thp.scalligraph.models._
import org.thp.scalligraph.services._
import org.thp.scalligraph.traversal.TraversalOps._
import org.thp.scalligraph.traversal.{Converter, Graph, IdentityConverter, Traversal}
Expand Down Expand Up @@ -320,6 +320,11 @@ object AuditOps {
def share: Traversal.V[Share] = traversal.coalesceIdent(_.in[ShareObservable], _.in[ShareTask], _.in[ShareCase], _.identity).v[Share]
}

implicit class AuditedObjectOpsDefs[A](traversal: Traversal.V[A]) {
def audits: Traversal.V[Audit] = traversal.in[Audited].v[Audit]
def auditsFromContext: Traversal.V[Audit] = traversal.in[AuditContext].v[Audit]
}

implicit class AuditOpsDefs(traversal: Traversal.V[Audit]) {
def auditContextObjectOrganisation: Traversal[
(Audit with Entity, Option[Map[String, Seq[Any]] with Entity], Option[Map[String, Seq[Any]] with Entity], Seq[Organisation with Entity]),
Expand Down

0 comments on commit d6485c8

Please sign in to comment.