diff --git a/README.md b/README.md index fc6f915774..ea3771e6f1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ ![](images/thehive-logo.png) + +[![Join the chat at https://gitter.im/TheHive-Project/TheHive](https://badges.gitter.im/TheHive-Project/TheHive.svg)](https://gitter.im/TheHive-Project/TheHive?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + + [TheHive](https://thehive-project.org/) is a scalable 3-in-1 open source and free security incident response platform designed to make life easier for SOCs, CSIRTs, CERTs and any information security practitioner dealing with security incidents that need to be investigated and acted upon swiftly. ![Current Cases View](images/Current_cases.png) diff --git a/thehive-cortex/app/connectors/cortex/services/CortexClient.scala b/thehive-cortex/app/connectors/cortex/services/CortexClient.scala index 1a8c0d0ab1..a3ca683cc7 100644 --- a/thehive-cortex/app/connectors/cortex/services/CortexClient.scala +++ b/thehive-cortex/app/connectors/cortex/services/CortexClient.scala @@ -1,11 +1,11 @@ package connectors.cortex.services import akka.stream.scaladsl.Source -import connectors.cortex.models.{ Analyzer, CortexArtifact, DataArtifact, FileArtifact } import connectors.cortex.models.JsonFormat._ +import connectors.cortex.models.{ Analyzer, CortexArtifact, DataArtifact, FileArtifact } import play.api.Logger import play.api.libs.json.{ JsObject, JsValue, Json } -import play.api.libs.ws.{ WSRequest, WSResponse } +import play.api.libs.ws.{ WSAuthScheme, WSRequest, WSResponse } import play.api.mvc.MultipartFormData.{ DataPart, FilePart } import services.CustomWSAPI @@ -13,12 +13,17 @@ import scala.concurrent.duration.Duration import scala.concurrent.{ ExecutionContext, Future } case class CortexError(status: Int, requestUrl: String, message: String) extends Exception(s"Cortex error on $requestUrl ($status) \n$message") -class CortexClient(val name: String, baseUrl: String, key: String, ws: CustomWSAPI) { +class CortexClient(val name: String, baseUrl: String, key: String, authentication: Option[(String, String)], ws: CustomWSAPI) { private[CortexClient] lazy val logger = Logger(getClass) + logger.info(s"new Cortex($name, $baseUrl, $key) Basic Auth enabled: ${authentication.isDefined}") def request[A](uri: String, f: WSRequest ⇒ Future[WSResponse], t: WSResponse ⇒ A)(implicit ec: ExecutionContext): Future[A] = { - f(ws.url(s"$baseUrl/$uri").withHeaders("auth" → key)).map { + val requestBuilder = ws.url(s"$baseUrl/$uri").withHeaders("auth" → key) + val authenticatedRequestBuilder = authentication.fold(requestBuilder) { + case (username, password) ⇒ requestBuilder.withAuth(username, password, WSAuthScheme.BASIC) + } + f(authenticatedRequestBuilder).map { case response if response.status / 100 == 2 ⇒ t(response) case error ⇒ throw CortexError(error.status, s"$baseUrl/$uri", error.body) } @@ -67,4 +72,4 @@ class CortexClient(val name: String, baseUrl: String, key: String, ws: CustomWSA def waitReport(jobId: String, atMost: Duration)(implicit ec: ExecutionContext): Future[JsObject] = { request(s"api/job/$jobId/waitreport", _.withQueryString("atMost" → atMost.toString).get, r ⇒ r.json.as[JsObject]) } -} \ No newline at end of file +} diff --git a/thehive-cortex/app/connectors/cortex/services/CortexSrv.scala b/thehive-cortex/app/connectors/cortex/services/CortexSrv.scala index 734c0611d0..cb05873255 100644 --- a/thehive-cortex/app/connectors/cortex/services/CortexSrv.scala +++ b/thehive-cortex/app/connectors/cortex/services/CortexSrv.scala @@ -27,16 +27,15 @@ import scala.util.{ Failure, Success, Try } object CortexConfig { def getCortexClient(name: String, configuration: Configuration, ws: CustomWSAPI): Option[CortexClient] = { - try { - val url = configuration.getString("url").getOrElse(sys.error("url is missing")).replaceFirst("/*$", "") - val key = "" // configuration.getString("key").getOrElse(sys.error("key is missing")) - Some(new CortexClient(name, url, key, ws)) - } - catch { - case NonFatal(e) ⇒ - Logger.error("Error while loading cortex configuration", e) - None - } + val url = configuration.getString("url").getOrElse(sys.error("url is missing")).replaceFirst("/*$", "") + val key = "" // configuration.getString("key").getOrElse(sys.error("key is missing")) + val authentication = for { + basicEnabled ← configuration.getBoolean("basicAuth") + if basicEnabled + username ← configuration.getString("username") + password ← configuration.getString("password") + } yield username → password + Some(new CortexClient(name, url, key, authentication, ws)) } def getInstances(configuration: Configuration, globalWS: CustomWSAPI): Seq[CortexClient] = { @@ -274,4 +273,4 @@ class CortexSrv @Inject() ( case None ⇒ Future.failed(NotFoundError(s"Cortex $cortexId not found")) } } -} \ No newline at end of file +} diff --git a/thehive-cortex/conf/reference.conf b/thehive-cortex/conf/reference.conf index 30cd1867ca..1cb687720b 100644 --- a/thehive-cortex/conf/reference.conf +++ b/thehive-cortex/conf/reference.conf @@ -6,5 +6,9 @@ cortex { #"CORTEX-SERVER-ID" { # # URL of MISP server # url = "" + # # If Cortex instance behind Basic Auth, set it here + # basicAuth = "true" + # username = "" + # password = "" #} }