mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 11:06:49 +00:00
Merge upstream/develop into develop after conflict resolution
This commit is contained in:
parent
e0f747a64c
commit
79ea9231a1
@ -13,7 +13,7 @@ import net.liftweb.util.Helpers.tryo
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.collection.concurrent
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.concurrent.Await
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
@ -112,221 +112,190 @@ object AbacRuleEngine {
|
||||
transactionId: Option[String] = None,
|
||||
transactionRequestId: Option[String] = None,
|
||||
customerId: Option[String] = None
|
||||
): Future[Box[Boolean]] = {
|
||||
val ruleBox = MappedAbacRuleProvider.getAbacRuleById(ruleId)
|
||||
ruleBox match {
|
||||
case Failure(msg, ex, chain) => Future.successful(Failure(msg, ex, chain))
|
||||
case Empty => Future.successful(Empty)
|
||||
case Full(rule) =>
|
||||
if (!rule.isActive) {
|
||||
Future.successful(Failure(s"ABAC Rule ${rule.ruleName} is not active"))
|
||||
} else {
|
||||
// Fetch authenticated user
|
||||
val authenticatedUserBox = Users.users.vend.getUserByUserId(authenticatedUserId)
|
||||
authenticatedUserBox match {
|
||||
case Failure(msg, ex, chain) => Future.successful(Failure(msg, ex, chain))
|
||||
case Empty => Future.successful(Empty)
|
||||
case Full(authenticatedUser) =>
|
||||
|
||||
// Create futures for all async operations
|
||||
val authenticatedUserAttributesFuture =
|
||||
code.api.util.NewStyle.function.getNonPersonalUserAttributes(authenticatedUserId, Some(callContext)).map(_._1)
|
||||
|
||||
val authenticatedUserAuthContextFuture =
|
||||
code.api.util.NewStyle.function.getUserAuthContexts(authenticatedUserId, Some(callContext)).map(_._1)
|
||||
|
||||
val authenticatedUserEntitlementsFuture =
|
||||
code.api.util.NewStyle.function.getEntitlementsByUserId(authenticatedUserId, Some(callContext))
|
||||
|
||||
val onBehalfOfUserFuture = onBehalfOfUserId match {
|
||||
case Some(obUserId) => Future.successful(Users.users.vend.getUserByUserId(obUserId).map(Some(_)))
|
||||
case None => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val onBehalfOfUserAttributesFuture = onBehalfOfUserId match {
|
||||
case Some(obUserId) =>
|
||||
code.api.util.NewStyle.function.getNonPersonalUserAttributes(obUserId, Some(callContext)).map(_._1)
|
||||
case None => Future.successful(List.empty[UserAttributeTrait])
|
||||
}
|
||||
|
||||
val onBehalfOfUserAuthContextFuture = onBehalfOfUserId match {
|
||||
case Some(obUserId) =>
|
||||
code.api.util.NewStyle.function.getUserAuthContexts(obUserId, Some(callContext)).map(_._1)
|
||||
case None => Future.successful(List.empty[UserAuthContext])
|
||||
}
|
||||
|
||||
val onBehalfOfUserEntitlementsFuture = onBehalfOfUserId match {
|
||||
case Some(obUserId) =>
|
||||
code.api.util.NewStyle.function.getEntitlementsByUserId(obUserId, Some(callContext))
|
||||
case None => Future.successful(List.empty[Entitlement])
|
||||
}
|
||||
|
||||
val userFuture = userId match {
|
||||
case Some(uId) => Future.successful(Users.users.vend.getUserByUserId(uId).map(Some(_)))
|
||||
case None => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val userAttributesFuture = userId match {
|
||||
case Some(uId) =>
|
||||
code.api.util.NewStyle.function.getNonPersonalUserAttributes(uId, Some(callContext)).map(_._1)
|
||||
case None => Future.successful(List.empty[UserAttributeTrait])
|
||||
}
|
||||
|
||||
val bankFuture = bankId match {
|
||||
case Some(bId) =>
|
||||
code.api.util.NewStyle.function.getBank(BankId(bId), Some(callContext)).map(_._1).map(bank => Full(Some(bank))).recover {
|
||||
case _ => Full(None)
|
||||
}
|
||||
case None => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val bankAttributesFuture = bankId match {
|
||||
case Some(bId) =>
|
||||
code.api.util.NewStyle.function.getBankAttributesByBank(BankId(bId), Some(callContext)).map(_._1)
|
||||
case None => Future.successful(List.empty[BankAttributeTrait])
|
||||
}
|
||||
|
||||
val accountFuture = (bankId, accountId) match {
|
||||
case (Some(bId), Some(aId)) =>
|
||||
code.api.util.NewStyle.function.getBankAccount(BankId(bId), AccountId(aId), Some(callContext)).map(_._1).map(account => Full(Some(account))).recover {
|
||||
case _ => Full(None)
|
||||
}
|
||||
case _ => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val accountAttributesFuture = (bankId, accountId) match {
|
||||
case (Some(bId), Some(aId)) =>
|
||||
code.api.util.NewStyle.function.getAccountAttributesByAccount(BankId(bId), AccountId(aId), Some(callContext)).map(_._1)
|
||||
case _ => Future.successful(List.empty[AccountAttribute])
|
||||
}
|
||||
|
||||
val transactionFuture = (bankId, accountId, transactionId) match {
|
||||
case (Some(bId), Some(aId), Some(tId)) =>
|
||||
code.api.util.NewStyle.function.getTransaction(BankId(bId), AccountId(aId), TransactionId(tId), Some(callContext)).map(_._1).map(trans => Full(Some(trans))).recover {
|
||||
case _ => Full(None)
|
||||
}
|
||||
case _ => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val transactionAttributesFuture = (bankId, transactionId) match {
|
||||
case (Some(bId), Some(tId)) =>
|
||||
code.api.util.NewStyle.function.getTransactionAttributes(BankId(bId), TransactionId(tId), Some(callContext)).map(_._1)
|
||||
case _ => Future.successful(List.empty[TransactionAttribute])
|
||||
}
|
||||
|
||||
val transactionRequestFuture = transactionRequestId match {
|
||||
case Some(trId) =>
|
||||
code.api.util.NewStyle.function.getTransactionRequestImpl(TransactionRequestId(trId), Some(callContext)).map(_._1).map(tr => Full(Some(tr))).recover {
|
||||
case _ => Full(None)
|
||||
}
|
||||
case _ => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val transactionRequestAttributesFuture = (bankId, transactionRequestId) match {
|
||||
case (Some(bId), Some(trId)) =>
|
||||
code.api.util.NewStyle.function.getTransactionRequestAttributes(BankId(bId), TransactionRequestId(trId), Some(callContext)).map(_._1)
|
||||
case _ => Future.successful(List.empty[TransactionRequestAttributeTrait])
|
||||
}
|
||||
|
||||
val customerFuture = (bankId, customerId) match {
|
||||
case (Some(bId), Some(cId)) =>
|
||||
code.api.util.NewStyle.function.getCustomerByCustomerId(cId, Some(callContext)).map(_._1).map(cust => Full(Some(cust))).recover {
|
||||
case _ => Full(None)
|
||||
}
|
||||
case _ => Future.successful(Full(None))
|
||||
}
|
||||
|
||||
val customerAttributesFuture = (bankId, customerId) match {
|
||||
case (Some(bId), Some(cId)) =>
|
||||
code.api.util.NewStyle.function.getCustomerAttributes(BankId(bId), CustomerId(cId), Some(callContext)).map(_._1)
|
||||
case _ => Future.successful(List.empty[CustomerAttribute])
|
||||
}
|
||||
|
||||
// Combine all futures
|
||||
for {
|
||||
authenticatedUserAttributes <- authenticatedUserAttributesFuture
|
||||
authenticatedUserAuthContext <- authenticatedUserAuthContextFuture
|
||||
authenticatedUserEntitlements <- authenticatedUserEntitlementsFuture
|
||||
onBehalfOfUserOpt <- onBehalfOfUserFuture
|
||||
onBehalfOfUserAttributes <- onBehalfOfUserAttributesFuture
|
||||
onBehalfOfUserAuthContext <- onBehalfOfUserAuthContextFuture
|
||||
onBehalfOfUserEntitlements <- onBehalfOfUserEntitlementsFuture
|
||||
userOpt <- userFuture
|
||||
userAttributes <- userAttributesFuture
|
||||
bankOpt <- bankFuture
|
||||
bankAttributes <- bankAttributesFuture
|
||||
accountOpt <- accountFuture
|
||||
accountAttributes <- accountAttributesFuture
|
||||
transactionOpt <- transactionFuture
|
||||
transactionAttributes <- transactionAttributesFuture
|
||||
transactionRequestOpt <- transactionRequestFuture
|
||||
transactionRequestAttributes <- transactionRequestAttributesFuture
|
||||
customerOpt <- customerFuture
|
||||
customerAttributes <- customerAttributesFuture
|
||||
} yield {
|
||||
// Compile and execute the rule
|
||||
val compiledFuncBox = compileRule(ruleId, rule.ruleCode)
|
||||
compiledFuncBox.flatMap { compiledFunc =>
|
||||
(for {
|
||||
onBehalfOfUser <- onBehalfOfUserOpt
|
||||
user <- userOpt
|
||||
bank <- bankOpt
|
||||
account <- accountOpt
|
||||
transaction <- transactionOpt
|
||||
transactionRequest <- transactionRequestOpt
|
||||
customer <- customerOpt
|
||||
} yield {
|
||||
tryo {
|
||||
compiledFunc(authenticatedUser, authenticatedUserAttributes, authenticatedUserAuthContext, authenticatedUserEntitlements, onBehalfOfUser, onBehalfOfUserAttributes, onBehalfOfUserAuthContext, onBehalfOfUserEntitlements, user, userAttributes, bank, bankAttributes, account, accountAttributes, transaction, transactionAttributes, transactionRequest, transactionRequestAttributes, customer, customerAttributes, Some(callContext))
|
||||
}
|
||||
}).flatten
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous wrapper for executeRule - DEPRECATED
|
||||
* This function blocks the thread and should be avoided. Use the async version instead.
|
||||
*
|
||||
* @deprecated Use the async executeRule that returns Future[Box[Boolean]] instead
|
||||
*/
|
||||
@deprecated("Use async executeRule that returns Future[Box[Boolean]]", "6.0.0")
|
||||
def executeRuleSync(
|
||||
ruleId: String,
|
||||
authenticatedUserId: String,
|
||||
onBehalfOfUserId: Option[String] = None,
|
||||
userId: Option[String] = None,
|
||||
callContext: CallContext,
|
||||
bankId: Option[String] = None,
|
||||
accountId: Option[String] = None,
|
||||
viewId: Option[String] = None,
|
||||
transactionId: Option[String] = None,
|
||||
transactionRequestId: Option[String] = None,
|
||||
customerId: Option[String] = None
|
||||
): Box[Boolean] = {
|
||||
try {
|
||||
Await.result(executeRule(
|
||||
ruleId = ruleId,
|
||||
authenticatedUserId = authenticatedUserId,
|
||||
onBehalfOfUserId = onBehalfOfUserId,
|
||||
userId = userId,
|
||||
callContext = callContext,
|
||||
bankId = bankId,
|
||||
accountId = accountId,
|
||||
viewId = viewId,
|
||||
transactionId = transactionId,
|
||||
transactionRequestId = transactionRequestId,
|
||||
customerId = customerId
|
||||
), 30.seconds)
|
||||
} catch {
|
||||
case _: java.util.concurrent.TimeoutException =>
|
||||
Failure("ABAC rule execution timed out")
|
||||
case ex: Exception =>
|
||||
Failure(s"ABAC rule execution failed: ${ex.getMessage}")
|
||||
}
|
||||
for {
|
||||
rule <- MappedAbacRuleProvider.getAbacRuleById(ruleId)
|
||||
_ <- if (rule.isActive) Full(true) else Failure(s"ABAC Rule ${rule.ruleName} is not active")
|
||||
|
||||
// Fetch authenticated user (the actual person logged in)
|
||||
authenticatedUser <- Users.users.vend.getUserByUserId(authenticatedUserId)
|
||||
|
||||
// Fetch non-personal attributes for authenticated user
|
||||
authenticatedUserAttributes = Await.result(
|
||||
code.api.util.NewStyle.function.getNonPersonalUserAttributes(authenticatedUserId, Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
|
||||
// Fetch auth context for authenticated user
|
||||
authenticatedUserAuthContext = Await.result(
|
||||
code.api.util.NewStyle.function.getUserAuthContexts(authenticatedUserId, Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
|
||||
// Fetch entitlements for authenticated user
|
||||
authenticatedUserEntitlements = Await.result(
|
||||
code.api.util.NewStyle.function.getEntitlementsByUserId(authenticatedUserId, Some(callContext)),
|
||||
5.seconds
|
||||
)
|
||||
|
||||
// Fetch onBehalfOf user if provided (delegation scenario)
|
||||
onBehalfOfUserOpt <- onBehalfOfUserId match {
|
||||
case Some(obUserId) => Users.users.vend.getUserByUserId(obUserId).map(Some(_))
|
||||
case None => Full(None)
|
||||
}
|
||||
|
||||
// Fetch attributes for onBehalfOf user if provided
|
||||
onBehalfOfUserAttributes = onBehalfOfUserId match {
|
||||
case Some(obUserId) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getNonPersonalUserAttributes(obUserId, Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case None => List.empty[UserAttributeTrait]
|
||||
}
|
||||
|
||||
// Fetch auth context for onBehalfOf user if provided
|
||||
onBehalfOfUserAuthContext = onBehalfOfUserId match {
|
||||
case Some(obUserId) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getUserAuthContexts(obUserId, Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case None => List.empty[UserAuthContext]
|
||||
}
|
||||
|
||||
// Fetch entitlements for onBehalfOf user if provided
|
||||
onBehalfOfUserEntitlements = onBehalfOfUserId match {
|
||||
case Some(obUserId) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getEntitlementsByUserId(obUserId, Some(callContext)),
|
||||
5.seconds
|
||||
)
|
||||
case None => List.empty[Entitlement]
|
||||
}
|
||||
|
||||
// Fetch target user if userId is provided
|
||||
userOpt <- userId match {
|
||||
case Some(uId) => Users.users.vend.getUserByUserId(uId).map(Some(_))
|
||||
case None => Full(None)
|
||||
}
|
||||
|
||||
// Fetch attributes for target user if provided
|
||||
userAttributes = userId match {
|
||||
case Some(uId) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getNonPersonalUserAttributes(uId, Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case None => List.empty[UserAttributeTrait]
|
||||
}
|
||||
|
||||
// Fetch bank if bankId is provided
|
||||
bankOpt <- bankId match {
|
||||
case Some(bId) =>
|
||||
tryo(Await.result(
|
||||
code.api.util.NewStyle.function.getBank(BankId(bId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)).map(Some(_))
|
||||
case None => Full(None)
|
||||
}
|
||||
|
||||
// Fetch bank attributes if bank is provided
|
||||
bankAttributes = bankId match {
|
||||
case Some(bId) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getBankAttributesByBank(BankId(bId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case None => List.empty[BankAttributeTrait]
|
||||
}
|
||||
|
||||
// Fetch account if accountId and bankId are provided
|
||||
accountOpt <- (bankId, accountId) match {
|
||||
case (Some(bId), Some(aId)) =>
|
||||
tryo(Await.result(
|
||||
code.api.util.NewStyle.function.getBankAccount(BankId(bId), AccountId(aId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)).map(Some(_))
|
||||
case _ => Full(None)
|
||||
}
|
||||
|
||||
// Fetch account attributes if account is provided
|
||||
accountAttributes = (bankId, accountId) match {
|
||||
case (Some(bId), Some(aId)) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getAccountAttributesByAccount(BankId(bId), AccountId(aId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case _ => List.empty[AccountAttribute]
|
||||
}
|
||||
|
||||
// Fetch transaction if transactionId, accountId, and bankId are provided
|
||||
transactionOpt <- (bankId, accountId, transactionId) match {
|
||||
case (Some(bId), Some(aId), Some(tId)) =>
|
||||
tryo(Await.result(
|
||||
code.api.util.NewStyle.function.getTransaction(BankId(bId), AccountId(aId), TransactionId(tId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)).map(trans => Some(trans))
|
||||
case _ => Full(None)
|
||||
}
|
||||
|
||||
// Fetch transaction attributes if transaction is provided
|
||||
transactionAttributes = (bankId, transactionId) match {
|
||||
case (Some(bId), Some(tId)) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getTransactionAttributes(BankId(bId), TransactionId(tId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case _ => List.empty[TransactionAttribute]
|
||||
}
|
||||
|
||||
// Fetch transaction request if transactionRequestId is provided
|
||||
transactionRequestOpt <- transactionRequestId match {
|
||||
case Some(trId) =>
|
||||
tryo(Await.result(
|
||||
code.api.util.NewStyle.function.getTransactionRequestImpl(TransactionRequestId(trId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)).map(tr => Some(tr))
|
||||
case _ => Full(None)
|
||||
}
|
||||
|
||||
// Fetch transaction request attributes if transaction request is provided
|
||||
transactionRequestAttributes = (bankId, transactionRequestId) match {
|
||||
case (Some(bId), Some(trId)) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getTransactionRequestAttributes(BankId(bId), TransactionRequestId(trId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case _ => List.empty[TransactionRequestAttributeTrait]
|
||||
}
|
||||
|
||||
// Fetch customer if customerId and bankId are provided
|
||||
customerOpt <- (bankId, customerId) match {
|
||||
case (Some(bId), Some(cId)) =>
|
||||
tryo(Await.result(
|
||||
code.api.util.NewStyle.function.getCustomerByCustomerId(cId, Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)).map(cust => Some(cust))
|
||||
case _ => Full(None)
|
||||
}
|
||||
|
||||
// Fetch customer attributes if customer is provided
|
||||
customerAttributes = (bankId, customerId) match {
|
||||
case (Some(bId), Some(cId)) =>
|
||||
Await.result(
|
||||
code.api.util.NewStyle.function.getCustomerAttributes(BankId(bId), CustomerId(cId), Some(callContext)).map(_._1),
|
||||
5.seconds
|
||||
)
|
||||
case _ => List.empty[CustomerAttribute]
|
||||
}
|
||||
|
||||
// Compile and execute the rule
|
||||
compiledFunc <- compileRule(ruleId, rule.ruleCode)
|
||||
result <- tryo {
|
||||
compiledFunc(authenticatedUser, authenticatedUserAttributes, authenticatedUserAuthContext, authenticatedUserEntitlements, onBehalfOfUserOpt, onBehalfOfUserAttributes, onBehalfOfUserAuthContext, onBehalfOfUserEntitlements, userOpt, userAttributes, bankOpt, bankAttributes, accountOpt, accountAttributes, transactionOpt, transactionAttributes, transactionRequestOpt, transactionRequestAttributes, customerOpt, customerAttributes, Some(callContext))
|
||||
}
|
||||
} yield result
|
||||
}
|
||||
|
||||
|
||||
@ -360,15 +329,15 @@ object AbacRuleEngine {
|
||||
transactionId: Option[String] = None,
|
||||
transactionRequestId: Option[String] = None,
|
||||
customerId: Option[String] = None
|
||||
): Future[Box[Boolean]] = {
|
||||
): Box[Boolean] = {
|
||||
val rules = MappedAbacRuleProvider.getActiveAbacRulesByPolicy(policy)
|
||||
|
||||
if (rules.isEmpty) {
|
||||
// No rules for this policy - default to allow
|
||||
Future.successful(Full(true))
|
||||
Full(true)
|
||||
} else {
|
||||
// Execute all rules and check if at least one passes
|
||||
val ruleFutures = rules.map { rule =>
|
||||
val results = rules.map { rule =>
|
||||
executeRule(
|
||||
ruleId = rule.abacRuleId,
|
||||
authenticatedUserId = authenticatedUserId,
|
||||
@ -384,59 +353,14 @@ object AbacRuleEngine {
|
||||
)
|
||||
}
|
||||
|
||||
// Wait for all rule executions to complete
|
||||
Future.sequence(ruleFutures).map { results =>
|
||||
// Count successes and failures
|
||||
val successes = results.filter {
|
||||
case Full(true) => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
// At least one rule must pass (OR logic)
|
||||
Full(successes.nonEmpty)
|
||||
// Count successes and failures
|
||||
val successes = results.filter {
|
||||
case Full(true) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous wrapper for executeRulesByPolicy - DEPRECATED
|
||||
* This function blocks the thread and should be avoided. Use the async version instead.
|
||||
*
|
||||
* @deprecated Use async executeRulesByPolicy that returns Future[Box[Boolean]] instead
|
||||
*/
|
||||
@deprecated("Use async executeRulesByPolicy that returns Future[Box[Boolean]]", "6.0.0")
|
||||
def executeRulesByPolicySync(
|
||||
policy: String,
|
||||
authenticatedUserId: String,
|
||||
onBehalfOfUserId: Option[String] = None,
|
||||
userId: Option[String] = None,
|
||||
callContext: CallContext,
|
||||
bankId: Option[String] = None,
|
||||
accountId: Option[String] = None,
|
||||
viewId: Option[String] = None,
|
||||
transactionId: Option[String] = None,
|
||||
transactionRequestId: Option[String] = None,
|
||||
customerId: Option[String] = None
|
||||
): Box[Boolean] = {
|
||||
try {
|
||||
Await.result(executeRulesByPolicy(
|
||||
policy = policy,
|
||||
authenticatedUserId = authenticatedUserId,
|
||||
onBehalfOfUserId = onBehalfOfUserId,
|
||||
userId = userId,
|
||||
callContext = callContext,
|
||||
bankId = bankId,
|
||||
accountId = accountId,
|
||||
viewId = viewId,
|
||||
transactionId = transactionId,
|
||||
transactionRequestId = transactionRequestId,
|
||||
customerId = customerId
|
||||
), 30.seconds)
|
||||
} catch {
|
||||
case _: java.util.concurrent.TimeoutException =>
|
||||
Failure("ABAC rules execution timed out")
|
||||
case ex: Exception =>
|
||||
Failure(s"ABAC rules execution failed: ${ex.getMessage}")
|
||||
// At least one rule must pass (OR logic)
|
||||
Full(successes.nonEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -177,54 +177,18 @@ val ruleCode = """user.emailAddress.contains("admin")"""
|
||||
val compiled = AbacRuleEngine.compileRule("rule123", ruleCode)
|
||||
```
|
||||
|
||||
### Execute a Rule (Async - Recommended)
|
||||
```scala
|
||||
import code.abacrule.AbacRuleEngine
|
||||
import com.openbankproject.commons.model._
|
||||
import scala.concurrent.Future
|
||||
|
||||
val resultFuture: Future[Box[Boolean]] = AbacRuleEngine.executeRule(
|
||||
ruleId = "rule123",
|
||||
authenticatedUserId = currentUser.userId,
|
||||
onBehalfOfUserId = None,
|
||||
userId = Some(targetUser.userId),
|
||||
callContext = callContext,
|
||||
bankId = Some(bank.bankId.value),
|
||||
accountId = Some(account.accountId.value),
|
||||
viewId = None,
|
||||
transactionId = None,
|
||||
transactionRequestId = None,
|
||||
customerId = None
|
||||
)
|
||||
|
||||
resultFuture.map { result =>
|
||||
result match {
|
||||
case Full(true) => println("Access granted")
|
||||
case Full(false) => println("Access denied")
|
||||
case Failure(msg, _, _) => println(s"Error: $msg")
|
||||
case Empty => println("Rule not found")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Execute a Rule (Sync - Deprecated)
|
||||
### Execute a Rule
|
||||
```scala
|
||||
import code.abacrule.AbacRuleEngine
|
||||
import com.openbankproject.commons.model._
|
||||
|
||||
// This is deprecated and blocks the thread - use async version above instead
|
||||
val result = AbacRuleEngine.executeRuleSync(
|
||||
val result = AbacRuleEngine.executeRule(
|
||||
ruleId = "rule123",
|
||||
authenticatedUserId = currentUser.userId,
|
||||
onBehalfOfUserId = None,
|
||||
userId = Some(targetUser.userId),
|
||||
callContext = callContext,
|
||||
bankId = Some(bank.bankId.value),
|
||||
accountId = Some(account.accountId.value),
|
||||
viewId = None,
|
||||
transactionId = None,
|
||||
transactionRequestId = None,
|
||||
customerId = None
|
||||
user = currentUser,
|
||||
bankOpt = Some(bank),
|
||||
accountOpt = Some(account),
|
||||
transactionOpt = None,
|
||||
customerOpt = None
|
||||
)
|
||||
|
||||
result match {
|
||||
@ -235,56 +199,24 @@ result match {
|
||||
}
|
||||
```
|
||||
|
||||
### Execute Rules by Policy (Async - Recommended)
|
||||
Execute all active rules associated with a policy (OR logic - at least one must pass):
|
||||
### Execute Multiple Rules (AND Logic)
|
||||
All rules must pass:
|
||||
```scala
|
||||
val resultFuture: Future[Box[Boolean]] = AbacRuleEngine.executeRulesByPolicy(
|
||||
policy = "account_access_policy",
|
||||
authenticatedUserId = currentUser.userId,
|
||||
onBehalfOfUserId = None,
|
||||
userId = Some(targetUser.userId),
|
||||
callContext = callContext,
|
||||
bankId = Some(bank.bankId.value),
|
||||
accountId = Some(account.accountId.value),
|
||||
viewId = None,
|
||||
transactionId = None,
|
||||
transactionRequestId = None,
|
||||
customerId = None
|
||||
val result = AbacRuleEngine.executeRulesAnd(
|
||||
ruleIds = List("rule1", "rule2", "rule3"),
|
||||
user = currentUser,
|
||||
bankOpt = Some(bank)
|
||||
)
|
||||
|
||||
resultFuture.map { result =>
|
||||
result match {
|
||||
case Full(true) => println("Access granted by policy")
|
||||
case Full(false) => println("Access denied by policy")
|
||||
case Failure(msg, _, _) => println(s"Error: $msg")
|
||||
case Empty => println("Policy not found")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Execute Rules by Policy (Sync - Deprecated)
|
||||
### Execute Multiple Rules (OR Logic)
|
||||
At least one rule must pass:
|
||||
```scala
|
||||
// This is deprecated and blocks the thread - use async version above instead
|
||||
val result = AbacRuleEngine.executeRulesByPolicySync(
|
||||
policy = "account_access_policy",
|
||||
authenticatedUserId = currentUser.userId,
|
||||
onBehalfOfUserId = None,
|
||||
userId = Some(targetUser.userId),
|
||||
callContext = callContext,
|
||||
bankId = Some(bank.bankId.value),
|
||||
accountId = Some(account.accountId.value),
|
||||
viewId = None,
|
||||
transactionId = None,
|
||||
transactionRequestId = None,
|
||||
customerId = None
|
||||
val result = AbacRuleEngine.executeRulesOr(
|
||||
ruleIds = List("rule1", "rule2", "rule3"),
|
||||
user = currentUser,
|
||||
bankOpt = Some(bank)
|
||||
)
|
||||
|
||||
result match {
|
||||
case Full(true) => println("Access granted by policy")
|
||||
case Full(false) => println("Access denied by policy")
|
||||
case Failure(msg, _, _) => println(s"Error: $msg")
|
||||
case Empty => println("Policy not found")
|
||||
}
|
||||
```
|
||||
|
||||
### Validate Rule Code
|
||||
@ -409,19 +341,16 @@ for {
|
||||
(account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
|
||||
|
||||
// Check ABAC rules
|
||||
allowed <- AbacRuleEngine.executeRulesByPolicy(
|
||||
policy = "bank_access_policy",
|
||||
authenticatedUserId = user.userId,
|
||||
onBehalfOfUserId = None,
|
||||
userId = Some(user.userId),
|
||||
callContext = callContext,
|
||||
bankId = Some(bank.bankId.value),
|
||||
accountId = Some(account.accountId.value),
|
||||
viewId = None,
|
||||
transactionId = None,
|
||||
transactionRequestId = None,
|
||||
customerId = None
|
||||
)
|
||||
allowed <- Future {
|
||||
AbacRuleEngine.executeRulesAnd(
|
||||
ruleIds = List("bank_access_rule", "account_limit_rule"),
|
||||
user = user,
|
||||
bankOpt = Some(bank),
|
||||
accountOpt = Some(account)
|
||||
)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, "ABAC access check failed", 403)
|
||||
}
|
||||
|
||||
_ <- Helper.booleanToFuture(s"Access denied by ABAC rules", cc = callContext) {
|
||||
allowed
|
||||
|
||||
Loading…
Reference in New Issue
Block a user