All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.touk.nussknacker.ui.security.api.LoggedUser.scala Maven / Gradle / Ivy

package pl.touk.nussknacker.ui.security.api

import pl.touk.nussknacker.ui.security.api.AuthenticationConfiguration.ConfigRule
import GlobalPermission.GlobalPermission
import pl.touk.nussknacker.security.Permission
import pl.touk.nussknacker.security.Permission.Permission
import pl.touk.nussknacker.ui.security.api.CreationError.ImpersonationNotAllowed

sealed trait LoggedUser {
  val id: String
  val username: String
  def can(category: String, permission: Permission): Boolean
}

object LoggedUser {

  def create(
      authenticatedUser: AuthenticatedUser,
      rules: List[ConfigRule],
      isAdminImpersonationPossible: Boolean = false
  ): Either[CreationError, LoggedUser] = {
    val loggedUser = RealLoggedUser(authenticatedUser, rules)
    authenticatedUser.impersonatedAuthenticationUser match {
      case None =>
        Right(loggedUser)
      case Some(impersonatedUser) if loggedUser.canImpersonate =>
        createImpersonatedUser(
          loggedUser,
          RealLoggedUser(impersonatedUser, rules),
          isAdminImpersonationPossible
        )
      case Some(_) =>
        Left(ImpersonationNotAllowed)
    }
  }

  private def createImpersonatedUser(
      impersonatingUser: RealLoggedUser,
      impersonatedLoggedUser: RealLoggedUser,
      isAdminImpersonationPossible: Boolean
  ): Either[CreationError, LoggedUser] = impersonatedLoggedUser match {
    case _: CommonUser =>
      Right(ImpersonatedUser(impersonatedLoggedUser, impersonatingUser))
    case _: AdminUser if isAdminImpersonationPossible =>
      Right(ImpersonatedUser(impersonatedLoggedUser, impersonatingUser))
    case _: AdminUser =>
      Left(ImpersonationNotAllowed)
  }

  implicit class UserImpersonationSyntax(val user: LoggedUser) extends AnyVal {

    def canImpersonate: Boolean = user match {
      case _: AdminUser        => true
      case _: ImpersonatedUser => false
      case commonUser: CommonUser =>
        commonUser.globalPermissions
          .map(_.toLowerCase)
          .contains(Permission.Impersonate.toString.toLowerCase)
    }

    def isAdmin: Boolean = user match {
      case _: AdminUser        => true
      case _: CommonUser       => false
      case u: ImpersonatedUser => u.impersonatedUser.isAdmin
    }

    def impersonatingUserId: Option[String] = user match {
      case _: RealLoggedUser   => None
      case u: ImpersonatedUser => Some(u.impersonatingUser.id)
    }

    def impersonatingUserName: Option[String] = user match {
      case _: RealLoggedUser   => None
      case u: ImpersonatedUser => Some(u.impersonatingUser.username)
    }

  }

}

sealed trait RealLoggedUser extends LoggedUser

object RealLoggedUser {

  def apply(authenticatedUser: AuthenticatedUser, rules: List[ConfigRule]): RealLoggedUser = {
    val rulesSet = RulesSet.getOnlyMatchingRules(authenticatedUser.roles.toList, rules)
    RealLoggedUser(id = authenticatedUser.id, username = authenticatedUser.username, rulesSet = rulesSet)
  }

  def apply(
      id: String,
      username: String,
      categoryPermissions: Map[String, Set[Permission]] = Map.empty,
      globalPermissions: List[GlobalPermission] = Nil,
      isAdmin: Boolean = false
  ): RealLoggedUser = {
    if (isAdmin) {
      AdminUser(id, username)
    } else {
      CommonUser(id, username, categoryPermissions, globalPermissions)
    }
  }

  private def apply(id: String, username: String, rulesSet: RulesSet): RealLoggedUser = {
    if (rulesSet.isAdmin) {
      RealLoggedUser(id = id, username = username, isAdmin = true)
    } else {
      RealLoggedUser(
        id = id,
        username = username,
        categoryPermissions = rulesSet.permissions,
        globalPermissions = rulesSet.globalPermissions
      )
    }
  }

}

final case class CommonUser(
    id: String,
    username: String,
    categoryPermissions: Map[String, Set[Permission]] = Map.empty,
    globalPermissions: List[GlobalPermission] = Nil
) extends RealLoggedUser {

  override def can(category: String, permission: Permission): Boolean = {
    categoryPermissions.get(category).exists(_ contains permission)
  }

  def categories(permission: Permission): Set[String] = categoryPermissions.collect {
    case (category, permissions) if permissions contains permission => category
  }.toSet

}

final case class AdminUser(id: String, username: String) extends RealLoggedUser {
  override def can(category: String, permission: Permission): Boolean = true
}

final case class ImpersonatedUser(impersonatedUser: RealLoggedUser, impersonatingUser: RealLoggedUser)
    extends LoggedUser {
  override val id: String                                             = impersonatedUser.id
  override val username: String                                       = impersonatedUser.username
  override def can(category: String, permission: Permission): Boolean = impersonatedUser.can(category, permission)
}

sealed trait CreationError

object CreationError {
  case object ImpersonationNotAllowed extends CreationError
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy