Skip to content

Commit

Permalink
Reformat code
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Sep 20, 2023
1 parent f7fdcdf commit 5da91c8
Showing 1 changed file with 34 additions and 36 deletions.
70 changes: 34 additions & 36 deletions app/org/thp/cortex/services/mappers/GroupUserMapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package org.thp.cortex.services.mappers

import scala.concurrent.{ExecutionContext, Future}
import scala.util.parsing.combinator._

import play.api.{Configuration, Logger}
import play.api.libs.json._
import play.api.libs.ws.WSClient

import javax.inject.Inject

import org.elastic4play.{AuthenticationError, AuthorizationError}
import org.elastic4play.controllers.Fields

import scala.util.matching.Regex

class GroupUserMapper(
loginAttrName: String,
nameAttrName: String,
Expand Down Expand Up @@ -44,68 +44,65 @@ class GroupUserMapper(
private[GroupUserMapper] lazy val logger = Logger(getClass)

private class RoleListParser extends RegexParsers {
val str = "[a-zA-Z0-9_]+".r
val strSpc = "[a-zA-Z0-9_ ]+".r
val realStr = ("\""~>strSpc<~"\"" | "'"~>strSpc<~"'" | str)
val str: Regex = "[a-zA-Z0-9_]+".r
val strSpc: Regex = "[a-zA-Z0-9_ ]+".r
val realStr: Parser[String] = "\"" ~> strSpc <~ "\"" | "'" ~> strSpc <~ "'" | str

def expr: Parser[Seq[String]] = {
def expr: Parser[Seq[String]] =
"[" ~ opt(realStr ~ rep("," ~ realStr)) ~ "]" ^^ {
case _ ~ Some(firstRole ~ list) ~ _ list.foldLeft(Seq(firstRole)) {
case (queue, _ ~ role) role +: queue
}
case _ ~ _ Seq.empty[String]
case _ ~ Some(firstRole ~ list) ~ _ =>
list.foldLeft(Seq(firstRole)) {
case (queue, _ ~ role) => role +: queue
}
case _ ~ _ => Seq.empty[String]
} | opt(realStr) ^^ {
case Some(role) Seq(role)
case None Seq.empty[String]
case Some(role) => Seq(role)
case None => Seq.empty[String]
}
}
}

override def getUserFields(jsValue: JsValue, authHeader: Option[(String, String)]): Future[Fields] = {

override def getUserFields(jsValue: JsValue, authHeader: Option[(String, String)]): Future[Fields] =
groupsUrl match {
case Some(groupsEndpointUrl) {
logger.debug(s"Retreiving groups from ${groupsEndpointUrl}")
val apiCall = authHeader.fold(ws.url(groupsEndpointUrl))(headers ws.url(groupsEndpointUrl).addHttpHeaders(headers))
apiCall.get.flatMap { r extractGroupsThenBuildUserFields(jsValue, r.json) }
}
case None {
case Some(groupsEndpointUrl) =>
logger.debug(s"Retreiving groups from $groupsEndpointUrl")
val apiCall = authHeader.fold(ws.url(groupsEndpointUrl))(headers => ws.url(groupsEndpointUrl).addHttpHeaders(headers))
apiCall.get.flatMap { r =>
extractGroupsThenBuildUserFields(jsValue, r.json)
}
case None =>
logger.debug(s"Extracting groups from user info")
extractGroupsThenBuildUserFields(jsValue, jsValue)
}
}
}

private def extractGroupsThenBuildUserFields(jsValue: JsValue, groupsContainer: JsValue): Future[Fields] = {
(groupsContainer \ groupsAttrName) match {
private def extractGroupsThenBuildUserFields(jsValue: JsValue, groupsContainer: JsValue): Future[Fields] =
groupsContainer \ groupsAttrName match {
// Groups received as valid JSON array
case JsDefined(JsArray(groupsList)) mapGroupsAndBuildUserFields(jsValue, groupsList.map(_.as[String]).toList)
case JsDefined(JsArray(groupsList)) => mapGroupsAndBuildUserFields(jsValue, groupsList.map(_.as[String]).toList)

// Groups list received as string (invalid JSON, for example: "ROLE" or "['Role 1', ROLE2, 'Role_3']")
case JsDefined(JsString(groupsStr)) {
case JsDefined(JsString(groupsStr)) =>
val parser = new RoleListParser
parser.parseAll(parser.expr, groupsStr) match {
case parser.Success(result, _) mapGroupsAndBuildUserFields(jsValue, result)
case err: parser.NoSuccess Future.failed(AuthenticationError(s"User info fails: can't parse groups list (${err.msg})"))
case parser.Success(result, _) => mapGroupsAndBuildUserFields(jsValue, result)
case err: parser.NoSuccess => Future.failed(AuthenticationError(s"User info fails: can't parse groups list (${err.msg})"))
}
}

// Invalid group list
case JsDefined(error)
Future.failed(AuthenticationError(s"User info fails: invalid groups list received in user info ('${error}' of type ${error.getClass})"))
case JsDefined(error) =>
Future.failed(AuthenticationError(s"User info fails: invalid groups list received in user info ('$error' of type ${error.getClass})"))

// Groups field is undefined
case _: JsUndefined
Future.failed(AuthenticationError(s"User info fails: groups attribute ${groupsAttrName} doesn't exist in user info"))
case _: JsUndefined =>
Future.failed(AuthenticationError(s"User info fails: groups attribute $groupsAttrName doesn't exist in user info"))
}
}

private def mapGroupsAndBuildUserFields(jsValue: JsValue, jsonGroups: Seq[String]): Future[Fields] = {
val mappedRoles = jsonGroups.flatMap(mappings.get).flatten.toSet
val roles = if (mappedRoles.nonEmpty) mappedRoles else defaultRoles

if (roles.isEmpty) {
Future.failed(AuthorizationError(s"No matched roles for user"))

} else {
logger.debug(s"Computed roles: ${roles.mkString(", ")}")

Expand All @@ -119,7 +116,8 @@ class GroupUserMapper(
} yield Fields(Json.obj("login" -> login.toLowerCase, "name" -> name, "roles" -> roles, "organization" -> organization))
fields match {
case JsSuccess(f, _) => Future.successful(f)
case JsError(errors) Future.failed(AuthenticationError(s"User info fails: ${errors.map(_._2).map(_.map(_.messages.mkString(", ")).mkString("; ")).mkString}"))
case JsError(errors) =>
Future.failed(AuthenticationError(s"User info fails: ${errors.map(_._2).map(_.map(_.messages.mkString(", ")).mkString("; ")).mkString}"))
}
}
}
Expand Down

0 comments on commit 5da91c8

Please sign in to comment.