-
Notifications
You must be signed in to change notification settings - Fork 640
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#170 Add support of alerts Convert MISP into alert
- Loading branch information
Showing
12 changed files
with
861 additions
and
492 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package controllers | ||
|
||
import javax.inject.{ Inject, Singleton } | ||
|
||
import akka.stream.Materializer | ||
import org.elastic4play.controllers.{ Authenticated, FieldsBodyParser, Renderer } | ||
import org.elastic4play.models.JsonFormat.baseModelEntityWrites | ||
import org.elastic4play.services.JsonFormat.{ aggReads, queryReads } | ||
import org.elastic4play.services._ | ||
import org.elastic4play.{ BadRequestError, Timed } | ||
import play.api.Logger | ||
import play.api.http.Status | ||
import play.api.libs.json.JsArray | ||
import play.api.mvc.Controller | ||
import services.AlertSrv | ||
|
||
import scala.concurrent.{ ExecutionContext, Future } | ||
import scala.util.Try | ||
|
||
@Singleton | ||
class AlertCtrl @Inject() ( | ||
alertSrv: AlertSrv, | ||
auxSrv: AuxSrv, | ||
authenticated: Authenticated, | ||
renderer: Renderer, | ||
fieldsBodyParser: FieldsBodyParser, | ||
implicit val ec: ExecutionContext, | ||
implicit val mat: Materializer) extends Controller with Status { | ||
|
||
val log = Logger(getClass) | ||
|
||
@Timed | ||
def create() = authenticated(Role.write).async(fieldsBodyParser) { implicit request ⇒ | ||
alertSrv.create(request.body) | ||
.map(alert ⇒ renderer.toOutput(CREATED, alert)) | ||
} | ||
|
||
@Timed | ||
def get(id: String) = authenticated(Role.read).async { implicit request ⇒ | ||
val withStats = for { | ||
statsValues ← request.queryString.get("nstats") | ||
firstValue ← statsValues.headOption | ||
} yield Try(firstValue.toBoolean).getOrElse(firstValue == "1") | ||
|
||
for { | ||
alert ← alertSrv.get(id) | ||
alertsWithStats ← auxSrv.apply(alert, 0, withStats.getOrElse(false), removeUnaudited = false) | ||
} yield renderer.toOutput(OK, alertsWithStats) | ||
} | ||
|
||
@Timed | ||
def update(id: String) = authenticated(Role.write).async(fieldsBodyParser) { implicit request ⇒ | ||
alertSrv.update(id, request.body) | ||
.map { alert ⇒ renderer.toOutput(OK, alert) } | ||
} | ||
|
||
@Timed | ||
def bulkUpdate() = authenticated(Role.write).async(fieldsBodyParser) { implicit request ⇒ | ||
request.body.getStrings("ids").fold(Future.successful(Ok(JsArray()))) { ids ⇒ | ||
alertSrv.bulkUpdate(ids, request.body.unset("ids")).map(multiResult ⇒ renderer.toMultiOutput(OK, multiResult)) | ||
} | ||
} | ||
|
||
@Timed | ||
def delete(id: String) = authenticated(Role.write).async { implicit request ⇒ | ||
alertSrv.delete(id) | ||
.map(_ ⇒ NoContent) | ||
} | ||
|
||
@Timed | ||
def find() = authenticated(Role.read).async(fieldsBodyParser) { implicit request ⇒ | ||
val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) | ||
val range = request.body.getString("range") | ||
val sort = request.body.getStrings("sort").getOrElse(Nil) | ||
val nparent = request.body.getLong("nparent").getOrElse(0L).toInt | ||
val withStats = request.body.getBoolean("nstats").getOrElse(false) | ||
|
||
val (alerts, total) = alertSrv.find(query, range, sort) | ||
val alertsWithStats = auxSrv.apply(alerts, nparent, withStats, removeUnaudited = false) | ||
renderer.toOutput(OK, alertsWithStats, total) | ||
} | ||
|
||
@Timed | ||
def stats() = authenticated(Role.read).async(fieldsBodyParser) { implicit request ⇒ | ||
val query = request.body.getValue("query") | ||
.fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) | ||
val aggs = request.body.getValue("stats") | ||
.getOrElse(throw BadRequestError("Parameter \"stats\" is missing")).as[Seq[Agg]] | ||
alertSrv.stats(query, aggs).map(s ⇒ Ok(s)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package models | ||
|
||
import javax.inject.{ Inject, Singleton } | ||
|
||
import models.JsonFormat.alertStatusFormat | ||
import org.elastic4play.models.{ Attribute, AttributeDef, BaseEntity, EntityDef, HiveEnumeration, ModelDef } | ||
import org.elastic4play.models.{ AttributeFormat ⇒ F, AttributeOption ⇒ O } | ||
import play.api.Logger | ||
import play.api.libs.json.{ JsObject, JsString, Json } | ||
import services.AuditedModel | ||
|
||
import scala.concurrent.Future | ||
|
||
object AlertStatus extends Enumeration with HiveEnumeration { | ||
type Type = Value | ||
val New, Update, Ignore, Imported = Value | ||
} | ||
|
||
trait AlertAttributes { | ||
_: AttributeDef ⇒ | ||
def artifactAttributes: Seq[Attribute[_]] | ||
|
||
val alertId = attribute("_id", F.stringFmt, "Alert id", O.readonly) | ||
val tpe = attribute("type", F.stringFmt, "Type of the alert", O.readonly) | ||
val source = attribute("source", F.stringFmt, "Source of the alert", O.readonly) | ||
val sourceRef = attribute("sourceRef", F.stringFmt, "Source reference of the alert", O.readonly) | ||
val date = attribute("date", F.dateFmt, "Date of the alert", O.readonly) | ||
val lastSyncDate = attribute("lastSyncDate", F.dateFmt, "Date of the last synchronization") | ||
val caze = optionalAttribute("case", F.stringFmt, "Id of the case, if created") | ||
val title = attribute("title", F.textFmt, "Title of the alert") | ||
val description = attribute("description", F.textFmt, "Description of the alert") | ||
val severity = attribute("severity", F.numberFmt, "Severity if the alert (0-5)", 3L) | ||
val tags = multiAttribute("tags", F.stringFmt, "Alert tags") | ||
val tlp = attribute("tlp", F.numberFmt, "TLP level", 2L) | ||
val artifacts = multiAttribute("artifacts", F.objectFmt(artifactAttributes), "Artifact of the alert") | ||
val caseTemplate = optionalAttribute("caseTemplate", F.stringFmt, "Case template to use") | ||
val status = attribute("status", F.enumFmt(AlertStatus), "Status of the alert", AlertStatus.New) | ||
val follow = attribute("follow", F.booleanFmt, "", true) | ||
} | ||
|
||
@Singleton | ||
class AlertModel @Inject() (artifactModel: ArtifactModel) | ||
extends ModelDef[AlertModel, Alert]("alert") | ||
with AlertAttributes | ||
with AuditedModel { | ||
|
||
private[AlertModel] lazy val logger = Logger(getClass) | ||
override val defaultSortBy: Seq[String] = Seq("-date") | ||
override val removeAttribute: JsObject = Json.obj("status" → AlertStatus.Ignore) | ||
|
||
override def artifactAttributes: Seq[Attribute[_]] = artifactModel.attributes | ||
|
||
override def creationHook(parent: Option[BaseEntity], attrs: JsObject): Future[JsObject] = { | ||
Future.successful { | ||
if (attrs.keys.contains("_id")) | ||
attrs | ||
else { | ||
val tpe = (attrs \ "tpe").asOpt[String].getOrElse("<null>") | ||
val source = (attrs \ "source").asOpt[String].getOrElse("<null>") | ||
val sourceRef = (attrs \ "sourceRef").asOpt[String].getOrElse("<null>") | ||
attrs + ("_id" → JsString(s"$tpe|$source|$sourceRef")) | ||
} | ||
} | ||
} | ||
} | ||
|
||
class Alert(model: AlertModel, attributes: JsObject) | ||
extends EntityDef[AlertModel, Alert](model, attributes) | ||
with AlertAttributes { | ||
|
||
override def artifactAttributes: Seq[Attribute[_]] = Nil | ||
|
||
def toCaseJson: JsObject = Json.obj( | ||
//"caseId" -> caseId, | ||
"title" → title(), | ||
"description" → description(), | ||
"severity" → severity(), | ||
//"owner" -> owner, | ||
"startDate" → date(), | ||
"tags" → tags(), | ||
"tlp" → tlp(), | ||
"status" → CaseStatus.Open) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
|
||
|
||
package object models { | ||
val version = 8 | ||
val version = 9 | ||
} |
Oops, something went wrong.