Skip to content

Commit

Permalink
#20 Add initial webhook feature
Browse files Browse the repository at this point in the history
Audit trail elements are sent in JSON format to an URL using http POST. A new
configuration section "webhooks" has been added. The format is:
webhooks {
  webhook-name-1 {
    url = "http://my.webhook.url"
  }
  webhook-name-2 {
    url = "http://my.other.webhook.url"
  }
}
HTTP client configuration (timeout, proxy, SSL, ...) can be configured in each
level like MISP and Cortex configuration.
  • Loading branch information
To-om committed Aug 24, 2017
1 parent fae95cb commit b55e942
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 10 deletions.
26 changes: 16 additions & 10 deletions thehive-backend/app/services/AuditSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import javax.inject.{ Inject, Singleton }
import scala.concurrent.ExecutionContext

import play.api.Logger
import play.api.libs.json.{ JsBoolean, JsObject, Json }
import play.api.libs.json.{ JsObject, Json }

import akka.actor.Actor
import models.{ Audit, AuditModel }
Expand Down Expand Up @@ -39,7 +39,9 @@ class AuditActor @Inject() (
auditModel: AuditModel,
createSrv: CreateSrv,
eventSrv: EventSrv,
webHooks: WebHooks,
implicit val ec: ExecutionContext) extends Actor {

object EntityExtractor {
def unapply(e: BaseEntity) = Some((e.model, e.id, e.routing))
}
Expand All @@ -61,16 +63,20 @@ class AuditActor @Inject() (
currentRequestIds = currentRequestIds - Instance.getRequestId(request)
case AuditOperation(EntityExtractor(model: AuditedModel, id, routing), action, details, authContext, date)
val requestId = authContext.requestId
createSrv[AuditModel, Audit](auditModel, Fields.empty
.set("operation", action.toString)
.set("details", model.selectAuditedAttributes(details))
.set("objectType", model.name)
.set("objectId", id)
.set("base", JsBoolean(!currentRequestIds.contains(requestId)))
.set("startDate", Json.toJson(date))
.set("rootId", routing)
.set("requestId", requestId))(authContext)
val audit = Json.obj(
"operation" action,
"details" model.selectAuditedAttributes(details),
"objectType" model.name,
"objectId" id,
"base" !currentRequestIds.contains(requestId),
"startDate" date,
"rootId" routing,
"requestId" requestId)

createSrv[AuditModel, Audit](auditModel, Fields(audit))(authContext)
.failed.foreach(t logger.error("Audit error", t))
currentRequestIds = currentRequestIds + requestId

webHooks.send(audit)
}
}
40 changes: 40 additions & 0 deletions thehive-backend/app/services/WebHook.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package services

import javax.inject.Inject

import scala.concurrent.ExecutionContext
import scala.util.{ Failure, Success, Try }

import play.api.{ Configuration, Logger }
import play.api.libs.json.JsObject
import play.api.libs.ws.WSRequest

case class WebHook(name: String, ws: WSRequest)(implicit ec: ExecutionContext) {
private[WebHook] lazy val logger = Logger(getClass.getName + "." + name)

def send(obj: JsObject) = ws.post(obj).onComplete {
case Success(resp) if resp.status / 100 != 2 logger.error(s"WebHook returns status ${resp.status} ${resp.statusText}")
case Failure(error) logger.error("WebHook call error", error)
case _
}
}

class WebHooks(
webhooks: Seq[WebHook]) {
@Inject() def this(
configuration: Configuration,
globalWS: CustomWSAPI,
ec: ExecutionContext) = {
this(
for {
cfg configuration.getOptional[Configuration]("webhooks").toSeq
whWS = globalWS.withConfig(cfg)
name cfg.subKeys
whConfig Try(cfg.get[Configuration](name)).toOption
url whConfig.getOptional[String]("url")
instanceWS = whWS.withConfig(whConfig).url(url)
} yield WebHook(name, instanceWS)(ec))
}

def send(obj: JsObject): Unit = webhooks.foreach(_.send(obj))
}

0 comments on commit b55e942

Please sign in to comment.