Skip to content

Commit

Permalink
#1355 Attach audits to share
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Jul 6, 2020
1 parent 1bc030e commit 2a940df
Show file tree
Hide file tree
Showing 23 changed files with 125 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ import org.thp.scalligraph.{CreateError, EntitySteps}
import org.thp.thehive.connector.cortex.controllers.v0.Conversion._
import org.thp.thehive.connector.cortex.models.AnalyzerTemplate
import org.thp.thehive.controllers.v0.Conversion._
import org.thp.thehive.services.OrganisationSrv
import play.api.libs.json.{JsObject, Json}

import scala.collection.JavaConverters._
import scala.io.Source
import scala.util.{Failure, Try}

@Singleton
class AnalyzerTemplateSrv @Inject() (
implicit @Named("with-thehive-cortex-schema") db: Database,
auditSrv: CortexAuditSrv
auditSrv: CortexAuditSrv,
organisationSrv: OrganisationSrv
) extends VertexSrv[AnalyzerTemplate, AnalyzerTemplateSteps] {

override def steps(raw: GremlinScala[Vertex])(implicit graph: Graph): AnalyzerTemplateSteps = new AnalyzerTemplateSteps(raw)
Expand Down Expand Up @@ -60,10 +63,11 @@ class AnalyzerTemplateSrv @Inject() (
.flatMap(auditSrv.analyzerTemplate.update(_, updatedFields))
}

def remove(analyzerTemplate: AnalyzerTemplate with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {
get(analyzerTemplate).remove()
auditSrv.analyzerTemplate.delete(analyzerTemplate)
}
def remove(analyzerTemplate: AnalyzerTemplate with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
organisationSrv.getOrFail(authContext.organisation).flatMap { organisation =>
get(analyzerTemplate).remove()
auditSrv.analyzerTemplate.delete(analyzerTemplate, organisation)
}

/**
* Creates or updates if found templates contained in a zip file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class MispCtrl @Inject() (
.has("type", "misp")
.visible
.toIterator
.toTry(alertSrv.cascadeRemove(_))
.toTry(alertSrv.remove(_))
.map(_ => Results.NoContent)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ class MispImportSrv @Inject() (
.toIterator
.toTry { obs =>
logger.info(s"Remove $obs")
observableSrv.cascadeRemove(obs)
observableSrv.remove(obs)
}
}
.map(_ => ())
Expand Down
2 changes: 1 addition & 1 deletion thehive/app/org/thp/thehive/ClusterSetup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ class ClusterSetup @Inject() (
logger.info("Initialising cluster")
val cluster = Cluster(system)
cluster.join(cluster.system.provider.getDefaultAddress)
GuiceAkkaExtension(system).set(injector)
}
GuiceAkkaExtension(system).set(injector)
}
4 changes: 2 additions & 2 deletions thehive/app/org/thp/thehive/controllers/v0/AlertCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class AlertCtrl @Inject() (
.get(alertId)
.can(Permissions.manageAlert)
.getOrFail()
_ <- alertSrv.cascadeRemove(alert)
_ <- alertSrv.remove(alert)
} yield Results.NoContent
}

Expand All @@ -228,7 +228,7 @@ class AlertCtrl @Inject() (
.get(alertId)
.can(Permissions.manageAlert)
.getOrFail()
_ <- alertSrv.cascadeRemove(alert)
_ <- alertSrv.remove(alert)
} yield ()
}
.map(_ => Results.NoContent)
Expand Down
2 changes: 1 addition & 1 deletion thehive/app/org/thp/thehive/controllers/v0/CaseCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class CaseCtrl @Inject() (
.get(caseIdOrNumber)
.can(Permissions.manageCase)
.getOrFail()
_ <- caseSrv.cascadeRemove(c)
_ <- caseSrv.remove(c)
} yield Results.NoContent
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ class CaseTemplateCtrl @Inject() (
entrypoint("delete case template")
.authTransaction(db) { implicit request => implicit graph =>
for {
template <- caseTemplateSrv.get(caseTemplateNameOrId).can(Permissions.manageCaseTemplate).getOrFail()
organisation <- organisationSrv.getOrFail(request.organisation)
template <- caseTemplateSrv.get(caseTemplateNameOrId).can(Permissions.manageCaseTemplate).getOrFail()
_ = caseTemplateSrv.get(template).remove()
_ <- auditSrv.caseTemplate.delete(template)
_ <- auditSrv.caseTemplate.delete(template, organisation)
} yield Results.Ok
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class ObservableCtrl @Inject() (
.getByIds(obsId)
.can(Permissions.manageObservable)
.getOrFail("Observable")
_ <- observableSrv.cascadeRemove(observable)
_ <- observableSrv.remove(observable)
} yield Results.NoContent
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class ObservableCtrl @Inject() (
.getByIds(obsId)
.can(Permissions.manageObservable)
.getOrFail("Observable")
_ <- observableSrv.cascadeRemove(observable)
_ <- observableSrv.remove(observable)
} yield Results.NoContent
}
}
18 changes: 15 additions & 3 deletions thehive/app/org/thp/thehive/services/AlertSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ class AlertSrv @Inject() (
} yield ()
}

def removeObservable(alert: Alert with Entity, observable: Observable with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
observableSrv
.get(observable)
.inToE[AlertObservable]
.filter(_.outV().hasId(alert._id))
.getOrFail("Observable")
.flatMap { alertObservable =>
alertObservableSrv.get(alertObservable).remove()
auditSrv.observableInAlert.delete(observable, Some(alert))
}

def addObservable(alert: Alert with Entity, richObservable: RichObservable)(
implicit graph: Graph,
authContext: AuthContext
Expand Down Expand Up @@ -275,11 +286,12 @@ class AlertSrv @Inject() (
}
.map(_ => ())

def cascadeRemove(alert: Alert with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
def remove(alert: Alert with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
for {
_ <- get(alert).observables.toIterator.toTry(observableSrv.cascadeRemove(_))
organisation <- organisationSrv.getOrFail(authContext.organisation)
_ <- get(alert).observables.toIterator.toTry(observableSrv.remove(_))
_ = get(alert).remove()
_ <- auditSrv.alert.delete(alert)
_ <- auditSrv.alert.delete(alert, organisation)
} yield ()

override def steps(raw: GremlinScala[Vertex])(implicit graph: Graph): AlertSteps = new AlertSteps(raw)
Expand Down
7 changes: 3 additions & 4 deletions thehive/app/org/thp/thehive/services/AuditSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ class AuditSrv @Inject() (
if (details == JsObject.empty) Success(())
else auditSrv.create(Audit(Audit.update, entity, Some(details.toString)), Some(entity), Some(entity))

def delete(entity: E with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
auditSrv.create(Audit(Audit.delete, entity, None), None, None)
def delete(entity: E with Entity, context: Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
auditSrv.create(Audit(Audit.delete, entity, None), Some(context), None)
}

class UserAudit extends SelfContextObjectAudit[User] {
Expand Down Expand Up @@ -334,8 +334,7 @@ class AuditSteps(raw: GremlinScala[Vertex])(implicit @Named("with-thehive-schema
new CaseSteps(
raw
.outTo[AuditContext]
.in()
.hasLabel("Share")
.coalesce(_.in().hasLabel("Share"), _.hasLabel("Share"))
.outTo[ShareCase]
)

Expand Down
19 changes: 11 additions & 8 deletions thehive/app/org/thp/thehive/services/CaseSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,14 @@ class CaseSrv @Inject() (
} yield ()
}

def cascadeRemove(`case`: Case with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
def remove(`case`: Case with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
for {
_ <- get(`case`).tasks.toIterator.toTry(taskSrv.cascadeRemove(_))
_ <- get(`case`).observables.toIterator.toTry(observableSrv.cascadeRemove(_))
_ = get(`case`).share.remove()
_ = get(`case`).remove()
_ <- auditSrv.`case`.delete(`case`)
} yield ()
organisation <- organisationSrv.getOrFail(authContext.organisation)
_ <- auditSrv.`case`.delete(`case`, organisation)
} yield {
get(`case`).share.remove()
get(`case`).remove()
}

override def get(idOrNumber: String)(implicit graph: Graph): CaseSteps =
Success(idOrNumber)
Expand Down Expand Up @@ -441,7 +441,10 @@ class CaseSteps(raw: GremlinScala[Vertex])(implicit @Named("with-thehive-schema"
def audits(implicit authContext: AuthContext): AuditSteps = audits(authContext.organisation)

def audits(organisationName: String): AuditSteps = new AuditSteps(
this.union(_.visible(organisationName), _.observables(organisationName), _.tasks(organisationName)).inTo[AuditContext].raw
this
.union(_.visible(organisationName), _.observables(organisationName), _.tasks(organisationName), _.share(organisationName))
.inTo[AuditContext]
.raw
)

// Warning: this method doesn't generate audit log
Expand Down
6 changes: 4 additions & 2 deletions thehive/app/org/thp/thehive/services/CustomFieldSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import scala.collection.JavaConverters._
import scala.util.{Success, Try}

@Singleton
class CustomFieldSrv @Inject() (auditSrv: AuditSrv, @Named("integrity-check-actor") integrityCheckActor: ActorRef)(
class CustomFieldSrv @Inject() (auditSrv: AuditSrv, organisationSrv: OrganisationSrv, @Named("integrity-check-actor") integrityCheckActor: ActorRef)(
implicit @Named("with-thehive-schema") db: Database
) extends VertexSrv[CustomField, CustomFieldSteps] {

Expand All @@ -41,7 +41,9 @@ class CustomFieldSrv @Inject() (auditSrv: AuditSrv, @Named("integrity-check-acto

def delete(c: CustomField with Entity, force: Boolean)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {
get(c).remove() // TODO use force
auditSrv.customField.delete(c)
organisationSrv.getOrFail(authContext.organisation).flatMap { organisation =>
auditSrv.customField.delete(c, organisation)
}
}

def useCount(c: CustomField with Entity)(implicit graph: Graph): Map[String, Int] =
Expand Down
9 changes: 5 additions & 4 deletions thehive/app/org/thp/thehive/services/DashboardSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ class DashboardSrv @Inject() (organisationSrv: OrganisationSrv, userSrv: UserSrv
Success(()) // TODO add audit
}

def remove(dashboard: Dashboard with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {
get(dashboard).remove()
auditSrv.dashboard.delete(dashboard)
}
def remove(dashboard: Dashboard with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
organisationSrv.getOrFail(authContext.organisation).flatMap { organisation =>
get(dashboard).remove()
auditSrv.dashboard.delete(dashboard, organisation)
}
}

@EntitySteps[Dashboard]
Expand Down
23 changes: 11 additions & 12 deletions thehive/app/org/thp/thehive/services/ObservableSrv.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.thp.thehive.services

import java.lang.{Long => JLong}
import java.util.{Set => JSet}

import gremlin.scala.{KeyValue => _, _}
Expand All @@ -27,11 +26,13 @@ class ObservableSrv @Inject() (
attachmentSrv: AttachmentSrv,
tagSrv: TagSrv,
caseSrvProvider: Provider[CaseSrv],
auditSrv: AuditSrv
auditSrv: AuditSrv,
alertSrvProvider: Provider[AlertSrv]
)(
implicit @Named("with-thehive-schema") db: Database
) extends VertexSrv[Observable, ObservableSteps] {
lazy val caseSrv: CaseSrv = caseSrvProvider.get
lazy val alertSrv: AlertSrv = alertSrvProvider.get
val observableKeyValueSrv = new EdgeSrv[ObservableKeyValue, Observable, KeyValue]
val observableDataSrv = new EdgeSrv[ObservableData, Observable, Data]
val observableObservableType = new EdgeSrv[ObservableObservableType, Observable, ObservableType]
Expand Down Expand Up @@ -158,17 +159,15 @@ class ObservableSrv @Inject() (
// TODO copy or link key value ?
} yield richObservable.copy(observable = createdObservable)

def cascadeRemove(observable: Observable with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {
get(observable).data.filter(_.useCount.filter(_.is(P.eq[JLong](0L)))).remove()
get(observable).attachments.remove()
get(observable).keyValues.remove()
val maybeAlert = get(observable).alert.headOption()
get(observable).remove()
maybeAlert match {
case None => auditSrv.observable.delete(observable)
case ctx: Some[_] => auditSrv.observableInAlert.delete(observable, ctx)
def remove(observable: Observable with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
get(observable).alert.headOption() match {
case None =>
for {
share <- get(observable).share(authContext.organisation).getOrFail("Observable")
_ <- auditSrv.observable.delete(observable, share)
} yield get(observable).remove()
case Some(alert) => alertSrv.removeObservable(alert, observable)
}
}

override def update(
steps: ObservableSteps,
Expand Down
9 changes: 5 additions & 4 deletions thehive/app/org/thp/thehive/services/PageSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ class PageSrv @Inject() (implicit @Named("with-thehive-schema") db: Database, or
_ <- auditSrv.page.update(p, Json.obj("title" -> p.title))
} yield p

def delete(page: Page with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {
get(page).remove()
auditSrv.page.delete(page)
}
def delete(page: Page with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Unit] =
organisationSrv.getOrFail(authContext.organisation).flatMap { organisation =>
get(page).remove()
auditSrv.page.delete(page, organisation)
}
}

@EntitySteps[Page]
Expand Down
21 changes: 13 additions & 8 deletions thehive/app/org/thp/thehive/services/ProfileSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.thp.thehive.services

import akka.actor.ActorRef
import gremlin.scala._
import javax.inject.{Inject, Named, Singleton}
import javax.inject.{Inject, Named, Provider, Singleton}
import org.thp.scalligraph.auth.{AuthContext, Permission}
import org.thp.scalligraph.models._
import org.thp.scalligraph.query.PropertyUpdater
Expand All @@ -17,11 +17,15 @@ import play.api.libs.json.JsObject
import scala.util.{Failure, Success, Try}

@Singleton
class ProfileSrv @Inject() (auditSrv: AuditSrv, @Named("integrity-check-actor") integrityCheckActor: ActorRef)(
class ProfileSrv @Inject() (
auditSrv: AuditSrv,
organisationSrvProvider: Provider[OrganisationSrv],
@Named("integrity-check-actor") integrityCheckActor: ActorRef
)(
implicit @Named("with-thehive-schema") val db: Database
) extends VertexSrv[Profile, ProfileSteps] {

lazy val orgAdmin: Profile with Entity = db.roTransaction(graph => getOrFail(Profile.orgAdmin.name)(graph)).get
lazy val organisationSrv: OrganisationSrv = organisationSrvProvider.get
lazy val orgAdmin: Profile with Entity = db.roTransaction(graph => getOrFail(Profile.orgAdmin.name)(graph)).get

override def createEntity(e: Profile)(implicit graph: Graph, authContext: AuthContext): Try[Profile with Entity] = {
integrityCheckActor ! IntegrityCheckActor.EntityAdded("Profile")
Expand All @@ -47,10 +51,11 @@ class ProfileSrv @Inject() (auditSrv: AuditSrv, @Named("integrity-check-actor")
Failure(BadRequestError(s"Profile ${profile.name} cannot be removed"))
else if (get(profile).filter(_.or(_.roles, _.shares)).exists())
Failure(BadRequestError(s"Profile ${profile.name} is used"))
else {
get(profile).remove()
auditSrv.profile.delete(profile)
}
else
organisationSrv.getOrFail(authContext.organisation).flatMap { organisation =>
get(profile).remove()
auditSrv.profile.delete(profile, organisation)
}

override def update(
steps: ProfileSteps,
Expand Down
Loading

0 comments on commit 2a940df

Please sign in to comment.