From 41889520646b7ff4ba492b6456a31cda79bd10e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Thu, 30 Mar 2023 12:51:23 +0200 Subject: [PATCH] feature/Just in Time Entitlements --- .../resources/props/sample.props.template | 7 ++++ .../main/scala/code/api/util/APIUtil.scala | 37 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index e372d61f4..ddaf179b9 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -838,6 +838,13 @@ featured_apis=elasticSearchWarehouseV300 # i.e. instead of asking every user to have a Role, you can give the Role(s) to a Consumer in the form of a Scope # allow_entitlements_or_scopes=false # --------------------------------------------------------------- + +# -- Just in Time Entitlements ------------------------------- +create_just_in_time_entitlements=false +# if create_just_in_time_entitlements==true then do the following: +# If a user is trying to use a Role and the user could grant them selves the required Role(s), +# then just automatically grant the Role(s)! +# ------------------------------------------------------------- # -- Database scheduler ----------------------------- # Database scheduler interval in seconds. diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala index 226b0aded..d05109fb1 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -2213,21 +2213,48 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ // i.e. does user has assigned at least one role from the list // when roles is empty, that means no access control, treat as pass auth check def handleEntitlementsAndScopes(bankId: String, userId: String, consumerId: String, roles: List[ApiRole]): Boolean = { - // Consumer AND User has the Role + val requireScopesForListedRoles: List[String] = getPropsValue("require_scopes_for_listed_roles", "").split(",").toList val requireScopesForRoles: immutable.Seq[String] = roles.map(_.toString()) intersect requireScopesForListedRoles + + def userHasTheRoles: Boolean = { + val userHasTheRole: Boolean = roles.isEmpty || roles.exists(hasEntitlement(bankId, userId, _)) + userHasTheRole match { + case true => userHasTheRole // Just forward + case false => + // If a user is trying to use a Role and the user could grant them selves the required Role(s), + // then just automatically grant the Role(s)! + getPropsAsBoolValue("create_just_in_time_entitlements", false) match { + case false => userHasTheRole // Just forward + case true => // Try to add missing roles + if (hasEntitlement(bankId, userId, ApiRole.canCreateEntitlementAtOneBank) || + hasEntitlement("", userId, ApiRole.canCreateEntitlementAtAnyBank)) { + // Add missing roles + roles.map { + role => + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement(bankId, userId, role.toString()) + logger.info(s"Just in Time Entitlements: $addedEntitlement") + addedEntitlement + }.forall(_.isDefined) + } else { + userHasTheRole // Just forward + } + } + } + } + // Consumer AND User has the Role if(ApiPropsWithAlias.requireScopesForAllRoles || !requireScopesForRoles.isEmpty) { - roles.isEmpty || (roles.exists(hasEntitlement(bankId, userId, _)) && roles.exists(hasScope(bankId, consumerId, _))) + roles.isEmpty || (userHasTheRoles && roles.exists(hasScope(bankId, consumerId, _))) } // Consumer OR User has the Role else if(getPropsAsBoolValue("allow_entitlements_or_scopes", false)) { - roles.isEmpty || - roles.exists(hasEntitlement(bankId, userId, _)) || + roles.isEmpty || + userHasTheRoles || roles.exists(role => hasScope(if (role.requiresBankId) bankId else "", consumerId, role)) } // User has the Role else { - roles.isEmpty || roles.exists(hasEntitlement(bankId, userId, _)) + userHasTheRoles } }