From 6c6796a6a61cb36ea730c7bcf80b52fd869001de Mon Sep 17 00:00:00 2001 From: To-om Date: Fri, 19 Nov 2021 10:58:16 +0100 Subject: [PATCH] #2245 Add user/org in Analyzers requests parameters --- .../thp/cortex/client/CortexClientTest.scala | 2 +- .../cortex/controllers/v0/JobCtrl.scala | 9 ++++--- .../connector/cortex/services/JobSrv.scala | 26 +++++++++++++++---- .../notification/notifiers/RunAnalyzer.scala | 10 +++++-- .../cortex/services/JobSrvTest.scala | 4 +-- .../org/thp/cortex/dto/v0/Artifact.scala | 21 ++++++++------- 6 files changed, 50 insertions(+), 22 deletions(-) diff --git a/cortex/client/src/test/scala/org/thp/cortex/client/CortexClientTest.scala b/cortex/client/src/test/scala/org/thp/cortex/client/CortexClientTest.scala index 5833f91dad..030b8452fa 100644 --- a/cortex/client/src/test/scala/org/thp/cortex/client/CortexClientTest.scala +++ b/cortex/client/src/test/scala/org/thp/cortex/client/CortexClientTest.scala @@ -37,7 +37,7 @@ class CortexClientTest extends PlaySpecification { } "run an analysis" in { - await(client.analyse("anaTest1", InputArtifact(1, 1, "test", "test", Some("test"), None))) must equalTo( + await(client.analyse("anaTest1", InputArtifact(1, 1, "test", "test", Some("test"), None, JsObject.empty))) must equalTo( OutputJob( id = "AWuYKFatq3Rtqym9DFmL", workerId = "anaTest1", diff --git a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/controllers/v0/JobCtrl.scala b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/controllers/v0/JobCtrl.scala index 140ec854da..95b6460d01 100644 --- a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/controllers/v0/JobCtrl.scala +++ b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/controllers/v0/JobCtrl.scala @@ -16,6 +16,7 @@ import org.thp.thehive.controllers.v0.{OutputParam, PublicData, QueryCtrl} import org.thp.thehive.models.{Observable, Permissions, RichCase, RichObservable} import org.thp.thehive.services.ObservableOps._ import org.thp.thehive.services.ObservableSrv +import play.api.libs.json.JsObject import play.api.mvc.{Action, AnyContent, Results} import javax.inject.{Inject, Singleton} @@ -48,10 +49,12 @@ class JobCtrl @Inject() ( .extract("analyzerId", FieldsParser[String].on("analyzerId")) .extract("cortexId", FieldsParser[String].on("cortexId")) .extract("artifactId", FieldsParser[String].on("artifactId")) + .extract("parameters", FieldsParser.jsObject.optional.on("parameters")) .asyncAuth { implicit request => if (request.isPermitted(Permissions.manageAnalyse)) { - val analyzerId: String = request.body("analyzerId") - val cortexId: String = request.body("cortexId") + val analyzerId: String = request.body("analyzerId") + val cortexId: String = request.body("cortexId") + val parameters: Option[JsObject] = request.body("parameters") db.roTransaction { implicit graph => val artifactId: String = request.body("artifactId") for { @@ -63,7 +66,7 @@ class JobCtrl @Inject() ( { case (o, c) => jobSrv - .submit(cortexId, analyzerId, o, c) + .submit(cortexId, analyzerId, o, c, parameters.getOrElse(JsObject.empty)) .map(j => Results.Created(j.toJson)) } ) diff --git a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala index 7152f60ca6..8c93d7ba48 100644 --- a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala +++ b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala @@ -25,7 +25,7 @@ import org.thp.thehive.models._ import org.thp.thehive.services.CaseOps._ import org.thp.thehive.services.ObservableOps._ import org.thp.thehive.services.OrganisationOps._ -import org.thp.thehive.services.{AttachmentSrv, ObservableSrv, ObservableTypeSrv, ReportTagSrv} +import org.thp.thehive.services.{AttachmentSrv, ObservableSrv, ObservableTypeSrv, OrganisationSrv, ReportTagSrv} import play.api.libs.json.{JsObject, JsString, Json} import java.nio.file.Files @@ -44,6 +44,7 @@ class JobSrv @Inject() ( reportTagSrv: ReportTagSrv, serviceHelper: ServiceHelper, auditSrv: CortexAuditSrv, + organisationSrv: OrganisationSrv, implicit val db: Database, implicit val ec: ExecutionContext, implicit val mat: Materializer @@ -63,9 +64,15 @@ class JobSrv @Inject() ( * @param authContext auth context instance * @return */ - def submit(cortexId: String, workerId: String, observable: RichObservable, `case`: Case with Entity)(implicit + def submit(cortexId: String, workerId: String, observable: RichObservable, `case`: Case with Entity, parameters: JsObject)(implicit authContext: AuthContext - ): Future[RichJob] = + ): Future[RichJob] = { + val parametersWithRequesterInfo = db.roTransaction { implicit graph => + parameters + + ("organisation" -> JsString(organisationSrv.current.value(_.name).head)) + + ("user" -> JsString(authContext.userId)) + } + for { cortexClient <- serviceHelper @@ -78,12 +85,20 @@ class JobSrv @Inject() ( cortexArtifact <- observable.dataOrAttachment match { case Left(data) => Future.successful( - InputArtifact(observable.tlp, `case`.pap, observable.dataType, `case`.number.toString, Some(data), None) + InputArtifact(observable.tlp, `case`.pap, observable.dataType, `case`.number.toString, Some(data), None, parametersWithRequesterInfo) ) case Right(a) => val attachment = CortexAttachment(a.name, a.size, a.contentType, attachmentSrv.source(a)) Future.successful( - InputArtifact(observable.tlp, `case`.pap, observable.dataType, `case`.number.toString, None, Some(attachment)) + InputArtifact( + observable.tlp, + `case`.pap, + observable.dataType, + `case`.number.toString, + None, + Some(attachment), + parametersWithRequesterInfo + ) ) case _ => Future.failed(new Exception(s"Invalid Observable data for ${observable.observable._id}")) } @@ -102,6 +117,7 @@ class JobSrv @Inject() ( }) _ = cortexActor ! CheckJob(Some(createdJob._id), cortexOutputJob.id, None, cortexClient.name, authContext) } yield createdJob + } private def fromCortexOutputJob(j: CortexJob): Job = j.into[Job] diff --git a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/notification/notifiers/RunAnalyzer.scala b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/notification/notifiers/RunAnalyzer.scala index 7487583653..501b534707 100644 --- a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/notification/notifiers/RunAnalyzer.scala +++ b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/notification/notifiers/RunAnalyzer.scala @@ -1,5 +1,6 @@ package org.thp.thehive.connector.cortex.services.notification.notifiers +import com.typesafe.config.ConfigRenderOptions import org.thp.scalligraph.models.Entity import org.thp.scalligraph.traversal.Graph import org.thp.scalligraph.traversal.TraversalOps._ @@ -11,6 +12,7 @@ import org.thp.thehive.services.ObservableOps._ import org.thp.thehive.services._ import org.thp.thehive.services.notification.notifiers.{Notifier, NotifierProvider} import play.api.Configuration +import play.api.libs.json.{JsObject, Json} import javax.inject.{Inject, Singleton} import scala.concurrent.{ExecutionContext, Future} @@ -26,10 +28,12 @@ class RunAnalyzerProvider @Inject() ( ) extends NotifierProvider { override val name: String = "RunAnalyzer" - override def apply(config: Configuration): Try[Notifier] = + override def apply(config: Configuration): Try[Notifier] = { + val parameters = Try(Json.parse(config.underlying.getValue("parameters").render(ConfigRenderOptions.concise())).as[JsObject]).toOption config.getOrFail[String]("analyzerName").map { responderName => new RunAnalyzer( responderName, + parameters.getOrElse(JsObject.empty), analyzerSrv, jobSrv, caseSrv, @@ -37,10 +41,12 @@ class RunAnalyzerProvider @Inject() ( ec ) } + } } class RunAnalyzer( analyzerName: String, + parameters: JsObject, analyzerSrv: AnalyzerSrv, jobSrv: JobSrv, caseSrv: CaseSrv, @@ -78,6 +84,6 @@ class RunAnalyzer( workers <- analyzerSrv.getAnalyzerByName(analyzerName, organisation._id) (worker, cortexIds) <- Future.fromTry(workers.headOption.toTry(Failure(NotFoundError(s"Analyzer $analyzerName not found")))) authContext = LocalUserSrv.getSystemAuthContext.changeOrganisation(organisation._id, Permissions.all) - _ <- jobSrv.submit(cortexIds.head, worker.id, observable, case0)(authContext) + _ <- jobSrv.submit(cortexIds.head, worker.id, observable, case0, parameters)(authContext) } yield () } diff --git a/cortex/connector/src/test/scala/org/thp/thehive/connector/cortex/services/JobSrvTest.scala b/cortex/connector/src/test/scala/org/thp/thehive/connector/cortex/services/JobSrvTest.scala index 9cfe8927a5..ab81ed48a9 100644 --- a/cortex/connector/src/test/scala/org/thp/thehive/connector/cortex/services/JobSrvTest.scala +++ b/cortex/connector/src/test/scala/org/thp/thehive/connector/cortex/services/JobSrvTest.scala @@ -14,7 +14,7 @@ import org.thp.thehive.services.ObservableOps._ import org.thp.thehive.services.UserOps._ import org.thp.thehive.services._ import org.thp.thehive.services.notification.triggers.JobFinished -import play.api.libs.json.Json +import play.api.libs.json.{JsObject, Json} import play.api.test.PlaySpecification import java.util.Date @@ -89,7 +89,7 @@ class JobSrvTest extends PlaySpecification with TestAppBuilder { case0 <- app[Database].roTransaction { implicit graph => app[CaseSrv].getOrFail(EntityName("1")) } - } yield await(app[JobSrv].submit("test", "anaTest1", observable, case0)) + } yield await(app[JobSrv].submit("test", "anaTest1", observable, case0, JsObject.empty)) x must beASuccessfulTry.which { job => job.cortexId shouldEqual "test" diff --git a/cortex/dto/src/main/scala/org/thp/cortex/dto/v0/Artifact.scala b/cortex/dto/src/main/scala/org/thp/cortex/dto/v0/Artifact.scala index e742b876e0..00cc446083 100644 --- a/cortex/dto/src/main/scala/org/thp/cortex/dto/v0/Artifact.scala +++ b/cortex/dto/src/main/scala/org/thp/cortex/dto/v0/Artifact.scala @@ -1,6 +1,5 @@ package org.thp.cortex.dto.v0 -import play.api.libs.functional.syntax._ import play.api.libs.json._ case class InputArtifact( @@ -9,15 +8,19 @@ case class InputArtifact( dataType: String, message: String, data: Option[String], - attachment: Option[Attachment] + attachment: Option[Attachment], + parameters: JsObject ) object InputArtifact { - implicit val writes: Writes[InputArtifact] = ( - (JsPath \ "tlp").write[Int] and - (JsPath \ "pap").write[Int] and - (JsPath \ "dataType").write[String] and - (JsPath \ "message").write[String] and - (JsPath \ "data").writeNullable[String] - )(i => (i.tlp, i.pap, i.dataType, i.message, i.data)) + implicit val writes: Writes[InputArtifact] = Writes[InputArtifact] { a => + Json.obj( + "tlp" -> a.tlp, + "pap" -> a.pap, + "dataType" -> a.dataType, + "message" -> a.message, + "data" -> a.data, + "parameters" -> a.parameters + ) + } }