From 6066a584fdec7adbd37f845ed1aff79a8f6f3930 Mon Sep 17 00:00:00 2001 From: To-om Date: Thu, 11 Mar 2021 13:02:24 +0100 Subject: [PATCH] #1264 Fix tests --- .../org/thp/thehive/services/CaseSrv.scala | 57 +++--- .../thp/thehive/services/CaseSrvTest.scala | 171 +++++++++--------- thehive/test/resources/data/Observable.json | 20 ++ .../test/resources/data/ObservableType.json | 1 - .../resources/data/OrganisationShare.json | 3 +- thehive/test/resources/data/Share.json | 3 +- thehive/test/resources/data/ShareCase.json | 4 +- .../test/resources/data/ShareObservable.json | 6 +- thehive/test/resources/data/ShareProfile.json | 3 +- thehive/test/resources/data/ShareTask.json | 6 +- thehive/test/resources/data/Task.json | 20 ++ 11 files changed, 168 insertions(+), 126 deletions(-) delete mode 100644 thehive/test/resources/data/ObservableType.json diff --git a/thehive/app/org/thp/thehive/services/CaseSrv.scala b/thehive/app/org/thp/thehive/services/CaseSrv.scala index 160c060060..9979752e5e 100644 --- a/thehive/app/org/thp/thehive/services/CaseSrv.scala +++ b/thehive/app/org/thp/thehive/services/CaseSrv.scala @@ -336,52 +336,50 @@ class CaseSrv @Inject() ( cases.flatMap(_.tags).distinct ) - val allProfilesOrgas = get(cases.head) + val allProfilesOrgas: Seq[(Profile with Entity, Organisation with Entity)] = get(cases.head) .shares .project(_.by(_.profile).by(_.organisation)) .toSeq for { - user <- userSrv.get(EntityIdOrName(authContext.userId)).getOrFail("User") - orga <- organisationSrv.current.getOrFail("Organisation") - richCase <- create(mergedCase, Some(user), orga, Seq(), None, Seq()) + user <- userSrv.current.getOrFail("User") + currentOrga <- organisationSrv.current.getOrFail("Organisation") + richCase <- create(mergedCase, Some(user), currentOrga, Seq(), None, Seq()) + // Share case with all organisations except the one who created the merged case + _ <- + allProfilesOrgas + .filterNot(_._2._id == currentOrga._id) + .toTry(profileOrg => shareSrv.shareCase(owner = false, richCase.`case`, profileOrg._2, profileOrg._1)) _ <- cases.toTry { c => for { - // Share case with all organisations except the one who created the merged case - _ <- - allProfilesOrgas - .filter(_._2._id != organisationSrv.currentId) - .toTry(profileOrg => shareSrv.shareCase(owner = false, richCase.`case`, profileOrg._2, profileOrg._1)) _ <- shareMergedCaseTasks(allProfilesOrgas.map(_._2), c, richCase.`case`) _ <- shareMergedCaseObservables(allProfilesOrgas.map(_._2), c, richCase.`case`) _ <- get(c) .alert - .toList + .toSeq .toTry(alertSrv.alertCaseSrv.create(AlertCase(), _, richCase.`case`)) _ <- get(c) .procedure - .toList + .toSeq .toTry(caseProcedureSrv.create(CaseProcedure(), richCase.`case`, _)) _ <- get(c) .richCustomFields - .toList + .toSeq .toTry(c => createCustomField(richCase.`case`, EntityIdOrName(c.customField.name), c.value, c.order)) } yield Success(()) } - _ = cases.map(remove(_)) + _ <- cases.toTry(remove(_)) } yield richCase } else Failure(BadRequestError("To be able to merge, cases must have same organisation / profile pair and user must be org-admin")) private def canMerge(cases: Seq[Case with Entity])(implicit graph: Graph, authContext: AuthContext): Boolean = { val allOrgProfiles = getByIds(cases.map(_._id): _*) - .shares - .project(_.by(_.profile.value(_.name)).by(_.organisation._id)) - .fold + .flatMap(_.shares.project(_.by(_.profile.value(_.name)).by(_.organisation._id)).fold) .toSeq .map(_.toSet) .distinct @@ -390,41 +388,40 @@ class CaseSrv @Inject() ( // case organisation must match current organisation and be of org-admin profile allOrgProfiles.size == 1 && allOrgProfiles .head - .find(_._2 == organisationSrv.currentId) - .map(_._1) - .contains(Profile.orgAdmin.name) + .exists { + case (profile, orgId) => orgId == organisationSrv.currentId && profile == Profile.orgAdmin.name + } } private def shareMergedCaseTasks(orgs: Seq[Organisation with Entity], fromCase: Case with Entity, mergedCase: Case with Entity)(implicit graph: Graph, authContext: AuthContext ): Try[Unit] = - for { - _ <- orgs.toTry(org => + orgs + .toTry { org => get(fromCase) .share(org._id) .tasks .richTask - .toList + .toSeq .toTry(shareSrv.shareTask(_, mergedCase, org._id)) - ) - } yield Success() + } + .map(_ => ()) private def shareMergedCaseObservables(orgs: Seq[Organisation with Entity], fromCase: Case with Entity, mergedCase: Case with Entity)(implicit graph: Graph, authContext: AuthContext ): Try[Unit] = - for { - _ <- orgs.toTry(org => + orgs + .toTry { org => get(fromCase) .share(org._id) .observables .richObservable - .toList + .toSeq .toTry(shareSrv.shareObservable(_, mergedCase, org._id)) - ) - } yield Success() - + } + .map(_ => ()) } object CaseOps { diff --git a/thehive/test/org/thp/thehive/services/CaseSrvTest.scala b/thehive/test/org/thp/thehive/services/CaseSrvTest.scala index ff5f21fd9b..02a2332dba 100644 --- a/thehive/test/org/thp/thehive/services/CaseSrvTest.scala +++ b/thehive/test/org/thp/thehive/services/CaseSrvTest.scala @@ -1,15 +1,17 @@ package org.thp.thehive.services import org.specs2.matcher.Matcher -import org.thp.scalligraph.EntityName import org.thp.scalligraph.auth.AuthContext import org.thp.scalligraph.controllers.FPathElem import org.thp.scalligraph.models._ import org.thp.scalligraph.query.PropertyUpdater +import org.thp.scalligraph.traversal.{Graph, Traversal} import org.thp.scalligraph.traversal.TraversalOps._ +import org.thp.scalligraph.{BadRequestError, EntityName} import org.thp.thehive.TestAppBuilder import org.thp.thehive.models._ import org.thp.thehive.services.CaseOps._ +import org.thp.thehive.services.ShareOps._ import play.api.libs.json.Json import play.api.test.PlaySpecification @@ -246,41 +248,41 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder { } "add an observable if not existing" in testApp { app => -// app[Database].roTransaction { implicit graph => -// val c1 = app[CaseSrv].get(EntityName("1")).getOrFail("Case").get -// val observables = app[ObservableSrv].startTraversal.richObservable.toList -// -// observables must not(beEmpty) -// -// val hfr = observables.find(_.message.contains("Some weird domain")).get -// -// app[Database].tryTransaction { implicit graph => -//// app[CaseSrv].addObservable(c1, hfr) -// app[CaseSrv].createObservable(c1, hfr, hfr.data.get) -// }.get must throwA[CreateError] -// -// val newObs = app[Database].tryTransaction { implicit graph => -// val organisation = app[OrganisationSrv].current.getOrFail("Organisation").get -// app[ObservableSrv].create( -// Observable( -// message = Some("if you feel lost"), -// tlp = 1, -// ioc = false, -// sighted = true, -// ignoreSimilarity = None, -// dataType = "domain", -// tags = Nil, -// organisationIds = Seq(organisation._id), -// relatedId = c1._id -// ), -// "lost.com" -// ) -// }.get -// -// app[Database].tryTransaction { implicit graph => -// app[CaseSrv].addObservable(c1, newObs) -// } must beSuccessfulTry -// } + // app[Database].roTransaction { implicit graph => + // val c1 = app[CaseSrv].get(EntityName("1")).getOrFail("Case").get + // val observables = app[ObservableSrv].startTraversal.richObservable.toList + // + // observables must not(beEmpty) + // + // val hfr = observables.find(_.message.contains("Some weird domain")).get + // + // app[Database].tryTransaction { implicit graph => + //// app[CaseSrv].addObservable(c1, hfr) + // app[CaseSrv].createObservable(c1, hfr, hfr.data.get) + // }.get must throwA[CreateError] + // + // val newObs = app[Database].tryTransaction { implicit graph => + // val organisation = app[OrganisationSrv].current.getOrFail("Organisation").get + // app[ObservableSrv].create( + // Observable( + // message = Some("if you feel lost"), + // tlp = 1, + // ioc = false, + // sighted = true, + // ignoreSimilarity = None, + // dataType = "domain", + // tags = Nil, + // organisationIds = Seq(organisation._id), + // relatedId = c1._id + // ), + // "lost.com" + // ) + // }.get + // + // app[Database].tryTransaction { implicit graph => + // app[CaseSrv].addObservable(c1, newObs) + // } must beSuccessfulTry + // } pending } @@ -442,24 +444,26 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder { } "show linked cases" in testApp { app => -// app[Database].roTransaction { implicit graph => -// app[CaseSrv].get(EntityName("1")).linkedCases must beEmpty -// val observables = app[ObservableSrv].startTraversal.richObservable.toList -// val hfr = observables.find(_.message.contains("Some weird domain")).get -// -// app[Database].tryTransaction { implicit graph => -// app[CaseSrv].addObservable(app[CaseSrv].get(EntityName("2")).getOrFail("Case").get, hfr) -// } -// -// app[Database].roTransaction(implicit graph => app[CaseSrv].get(EntityName("1")).linkedCases must not(beEmpty)) -// } + // app[Database].roTransaction { implicit graph => + // app[CaseSrv].get(EntityName("1")).linkedCases must beEmpty + // val observables = app[ObservableSrv].startTraversal.richObservable.toList + // val hfr = observables.find(_.message.contains("Some weird domain")).get + // + // app[Database].tryTransaction { implicit graph => + // app[CaseSrv].addObservable(app[CaseSrv].get(EntityName("2")).getOrFail("Case").get, hfr) + // } + // + // app[Database].roTransaction(implicit graph => app[CaseSrv].get(EntityName("1")).linkedCases must not(beEmpty)) + // } pending } "merge cases, happy path with one organisation" in testApp { app => app[Database].tryTransaction { implicit graph => def case21 = app[CaseSrv].get(EntityName("21")).clone() + def case22 = app[CaseSrv].get(EntityName("22")).clone() + def case23 = app[CaseSrv].get(EntityName("23")).clone() // Procedures case21.procedure.toSeq.size mustEqual 1 @@ -491,6 +495,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder { } must beASuccessfulTry.which { richCase => app[Database].roTransaction { implicit graph => def mergedCase = app[CaseSrv].get(EntityName(richCase.number.toString)).clone() + mergedCase.procedure.toSeq.size mustEqual 3 mergedCase.customFields.toSeq.size mustEqual 2 mergedCase.tasks.toSeq.size mustEqual 3 @@ -504,58 +509,50 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder { } } + "refuse to merge cases with different shares" in testApp { app => + app[Database].tryTransaction { implicit graph => + val case21 = app[CaseSrv].getOrFail(EntityName("21")).get + val case24 = app[CaseSrv].getOrFail(EntityName("24")).get + val case26 = app[CaseSrv].getOrFail(EntityName("26")).get + app[CaseSrv].merge(Seq(case21, case24, case26)) + } must beFailedTry.withThrowable[BadRequestError] + } + "merge cases, happy path with three organisations" in testApp { app => + implicit val authContext: AuthContext = + DummyUserSrv(organisation = "soc", permissions = Profile.analyst.permissions).authContext + + def getCase(number: Int)(implicit graph: Graph): Traversal.V[Case] = app[CaseSrv].getByName(number.toString) + app[Database].tryTransaction { implicit graph => - def case21 = app[CaseSrv].get(EntityName("21")).clone() - def case24 = app[CaseSrv].get(EntityName("24")).clone() - def case26 = app[CaseSrv].get(EntityName("26")).clone() // Tasks - case21.tasks.toSeq.size mustEqual 2 - case24.tasks.toSeq.size mustEqual 0 - case26.tasks.toSeq.size mustEqual 0 + getCase(24).share(EntityName("cert")).tasks.getCount mustEqual 1 + getCase(24).share(EntityName("soc")).tasks.getCount mustEqual 2 + getCase(25).share(EntityName("cert")).tasks.getCount mustEqual 0 + getCase(25).share(EntityName("soc")).tasks.getCount mustEqual 0 + // Observables - case21.observables.toSeq.size mustEqual 1 - case24.observables.toSeq.size mustEqual 0 - case26.observables.toSeq.size mustEqual 0 + getCase(24).share(EntityName("cert")).observables.getCount mustEqual 0 + getCase(24).share(EntityName("soc")).observables.getCount mustEqual 0 + getCase(25).share(EntityName("cert")).observables.getCount mustEqual 2 + getCase(25).share(EntityName("soc")).observables.getCount mustEqual 1 for { - c21 <- case21.getOrFail("Case") - c24 <- case24.getOrFail("Case") - c26 <- case26.getOrFail("Case") - newCase <- app[CaseSrv].merge(Seq(c21, c24, c26)) + c24 <- getCase(24).getOrFail("Case") + c25 <- getCase(25).getOrFail("Case") + newCase <- app[CaseSrv].merge(Seq(c24, c25)) } yield newCase } must beASuccessfulTry.which { richCase => app[Database].roTransaction { implicit graph => - def mergedCase = app[CaseSrv].get(EntityName(richCase.number.toString)).clone() - mergedCase.tasks.toSeq.size mustEqual 2 - mergedCase.observables.toSeq.size mustEqual 1 - - app[CaseSrv].get(EntityName("21")).getOrFail("Case") must beAFailedTry - app[CaseSrv].get(EntityName("24")).getOrFail("Case") must beAFailedTry - app[CaseSrv].get(EntityName("26")).getOrFail("Case") must beAFailedTry - } + getCase(richCase.number).share(EntityName("cert")).tasks.getCount mustEqual 1 + getCase(richCase.number).share(EntityName("soc")).tasks.getCount mustEqual 2 + getCase(richCase.number).share(EntityName("cert")).observables.getCount mustEqual 2 + getCase(richCase.number).share(EntityName("soc")).observables.getCount mustEqual 1 - app[Database].roTransaction { implicit graph => - implicit val authContext: AuthContext = - DummyUserSrv(userId = "socuser@thehive.local", organisation = "soc", permissions = Profile.analyst.permissions).authContext - - def mergedCase = app[CaseSrv].get(EntityName(richCase.number.toString)).clone() - mergedCase.getOrFail("Case") must beASuccessfulTry - mergedCase.tasks.toSeq.size mustEqual 1 - mergedCase.observables.toSeq.size mustEqual 1 - } - - app[Database].roTransaction { implicit graph => - implicit val authContext: AuthContext = - DummyUserSrv(userId = "puguser@thehive.local", organisation = "pug", permissions = Profile.analyst.permissions).authContext - - def mergedCase = app[CaseSrv].get(EntityName(richCase.number.toString)).clone() - mergedCase.getOrFail("Case") must beASuccessfulTry - mergedCase.tasks.toSeq.size mustEqual 0 - mergedCase.observables.toSeq.size mustEqual 0 + getCase(24).getOrFail("Case") must beAFailedTry + getCase(25).getOrFail("Case") must beAFailedTry } } } - } } diff --git a/thehive/test/resources/data/Observable.json b/thehive/test/resources/data/Observable.json index cc6989ee1b..4f127e735c 100644 --- a/thehive/test/resources/data/Observable.json +++ b/thehive/test/resources/data/Observable.json @@ -81,5 +81,25 @@ "data": "127.0.0.1", "sighted": true, "relatedId": "" + }, + { + "id": "mergeObs251", + "message": "merge Obs 251", + "tlp": 4, + "ioc": true, + "dataType": "ip", + "data": "127.0.0.1", + "sighted": true, + "relatedId": "" + }, + { + "id": "mergeObs252", + "message": "merge Obs 252", + "tlp": 4, + "ioc": true, + "dataType": "ip", + "data": "127.0.0.1", + "sighted": true, + "relatedId": "" } ] diff --git a/thehive/test/resources/data/ObservableType.json b/thehive/test/resources/data/ObservableType.json deleted file mode 100644 index 0637a088a0..0000000000 --- a/thehive/test/resources/data/ObservableType.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/thehive/test/resources/data/OrganisationShare.json b/thehive/test/resources/data/OrganisationShare.json index c662183547..753816328c 100644 --- a/thehive/test/resources/data/OrganisationShare.json +++ b/thehive/test/resources/data/OrganisationShare.json @@ -11,5 +11,6 @@ {"from": "cert", "to": "case24-merge-cert"}, {"from": "soc", "to": "case24-merge-soc"}, {"from": "cert", "to": "case25-merge-cert"}, + {"from": "soc", "to": "case25-merge-soc"}, {"from": "pug", "to": "case26-merge-pug"} -] \ No newline at end of file +] diff --git a/thehive/test/resources/data/Share.json b/thehive/test/resources/data/Share.json index 6edfc53e81..a867b7ac3a 100644 --- a/thehive/test/resources/data/Share.json +++ b/thehive/test/resources/data/Share.json @@ -9,7 +9,8 @@ {"id": "case22-merge-cert", "owner": true}, {"id": "case23-merge-cert", "owner": true}, {"id": "case24-merge-soc", "owner": true}, - {"id": "case24-merge-cert", "owner": true}, + {"id": "case24-merge-cert", "owner": false}, {"id": "case25-merge-cert", "owner": true}, + {"id": "case25-merge-soc", "owner": false}, {"id": "case26-merge-pug", "owner": true} ] diff --git a/thehive/test/resources/data/ShareCase.json b/thehive/test/resources/data/ShareCase.json index b0d0c970c3..416910f0e2 100644 --- a/thehive/test/resources/data/ShareCase.json +++ b/thehive/test/resources/data/ShareCase.json @@ -9,6 +9,8 @@ {"from": "case22-merge-cert", "to": "caseMerge22"}, {"from": "case23-merge-cert", "to": "caseMerge23"}, {"from": "case24-merge-soc", "to": "caseMerge24"}, + {"from": "case24-merge-cert", "to": "caseMerge24"}, {"from": "case25-merge-cert", "to": "caseMerge25"}, + {"from": "case25-merge-soc", "to": "caseMerge25"}, {"from": "case26-merge-pug", "to": "caseMerge26"} -] \ No newline at end of file +] diff --git a/thehive/test/resources/data/ShareObservable.json b/thehive/test/resources/data/ShareObservable.json index a425d768c2..4575e4497b 100644 --- a/thehive/test/resources/data/ShareObservable.json +++ b/thehive/test/resources/data/ShareObservable.json @@ -5,5 +5,7 @@ {"from": "case21-merge-cert", "to": "mergeObs211"}, {"from": "case23-merge-cert", "to": "mergeObs231"}, {"from": "case23-merge-cert", "to": "mergeObs232"}, - {"from": "case24-merge-soc", "to": "mergeObs211"} -] \ No newline at end of file + {"from": "case25-merge-soc", "to": "mergeObs251"}, + {"from": "case25-merge-cert", "to": "mergeObs251"}, + {"from": "case25-merge-cert", "to": "mergeObs252"} +] diff --git a/thehive/test/resources/data/ShareProfile.json b/thehive/test/resources/data/ShareProfile.json index a58379ea2c..b48ac8c1ec 100644 --- a/thehive/test/resources/data/ShareProfile.json +++ b/thehive/test/resources/data/ShareProfile.json @@ -9,5 +9,6 @@ {"from": "case24-merge-soc", "to": "org-admin"}, {"from": "case24-merge-cert", "to": "read-only"}, {"from": "case25-merge-cert", "to": "read-only"}, + {"from": "case25-merge-soc", "to": "org-admin"}, {"from": "case26-merge-pug", "to": "read-only"} -] \ No newline at end of file +] diff --git a/thehive/test/resources/data/ShareTask.json b/thehive/test/resources/data/ShareTask.json index 8f4a804323..6934d27a25 100644 --- a/thehive/test/resources/data/ShareTask.json +++ b/thehive/test/resources/data/ShareTask.json @@ -11,5 +11,7 @@ {"from": "case21-merge-cert", "to": "taskMerge211", "actionRequired": false}, {"from": "case21-merge-cert", "to": "taskMerge212", "actionRequired": false}, {"from": "case23-merge-cert", "to": "taskMerge231", "actionRequired": false}, - {"from": "case24-merge-soc", "to": "taskMerge211", "actionRequired": false} -] \ No newline at end of file + {"from": "case24-merge-soc", "to": "taskMerge241", "actionRequired": false}, + {"from": "case24-merge-soc", "to": "taskMerge242", "actionRequired": false}, + {"from": "case24-merge-cert", "to": "taskMerge242", "actionRequired": false} +] diff --git a/thehive/test/resources/data/Task.json b/thehive/test/resources/data/Task.json index af9342f2cc..bc5d5b5ff0 100644 --- a/thehive/test/resources/data/Task.json +++ b/thehive/test/resources/data/Task.json @@ -100,5 +100,25 @@ "flag": true, "order": 0, "relatedId": "" + }, + { + "id": "taskMerge241", + "title": "taskMerge241", + "group": "task merge", + "description": "description task merge 24 1", + "status": "Waiting", + "flag": true, + "order": 0, + "relatedId": "" + }, + { + "id": "taskMerge242", + "title": "taskMerge242", + "group": "task merge", + "description": "description task merge 24 2", + "status": "Waiting", + "flag": true, + "order": 0, + "relatedId": "" } ]