Skip to content

Commit

Permalink
Merge pull request #2369 from hongwei1/develop
Browse files Browse the repository at this point in the history
feature/OBPv510 added new endpoint grantUserAccessToViewById
  • Loading branch information
simonredfern authored Mar 27, 2024
2 parents 851d5f5 + ae0e5c2 commit 3344a78
Show file tree
Hide file tree
Showing 24 changed files with 360 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object ObpActorConfig {
"code.model.dataAccess.ViewImpl" = kryo,
"com.openbankproject.commons.model.User" = kryo,
"com.openbankproject.commons.model.ViewId" = kryo,
"com.openbankproject.commons.model.ViewIdBankIdAccountId" = kryo,
"com.openbankproject.commons.model.BankIdAccountIdViewId" = kryo,
"com.openbankproject.commons.model.Permission" = kryo,
"scala.Unit" = kryo,
"scala.Boolean" = kryo,
Expand Down
25 changes: 20 additions & 5 deletions obp-api/src/main/scala/code/api/util/APIUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4069,24 +4069,39 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
case _ => false
}

def canGrantAccessToView(bankId: BankId, accountId: AccountId, viewIdTobeGranted : ViewId, user: User, callContext: Option[CallContext]): Boolean = {
def canGrantAccessToView(bankId: BankId, accountId: AccountId, targetViewId : ViewId, user: User, callContext: Option[CallContext]): Boolean = {
//all the permission this user have for the bankAccount
val permission: Box[Permission] = Views.views.vend.permission(BankIdAccountId(bankId, accountId), user)

//1. if viewIdTobeGranted is systemView. just compare all the permissions
if(checkSystemViewIdOrName(viewIdTobeGranted.value)){
//1. if targetViewId is systemView. just compare all the permissions
if(checkSystemViewIdOrName(targetViewId.value)){
val allCanGrantAccessToViewsPermissions: List[String] = permission
.map(_.views.map(_.canGrantAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct

allCanGrantAccessToViewsPermissions.contains(viewIdTobeGranted.value)
allCanGrantAccessToViewsPermissions.contains(targetViewId.value)
} else{
//2. if viewIdTobeGranted is customView, we only need to check the `canGrantAccessToCustomViews`.
//2. if targetViewId is customView, we only need to check the `canGrantAccessToCustomViews`.
val allCanGrantAccessToCustomViewsPermissions: List[Boolean] = permission.map(_.views.map(_.canGrantAccessToCustomViews)).getOrElse(Nil)

allCanGrantAccessToCustomViewsPermissions.contains(true)
}
}

def canGrantAccessToView(bankIdAccountIdViewId: BankIdAccountIdViewId, targetViewId : ViewId, user: User, callContext: Option[CallContext]): Boolean = {

//1st: get the view
val view: Box[View] = Views.views.vend.getViewByBankIdAccountIdViewIdUserPrimaryKey(bankIdAccountIdViewId, user.userPrimaryKey)

//2rd: f targetViewId is systemView. we need to check `view.canGrantAccessToViews` field.
if(checkSystemViewIdOrName(targetViewId.value)){
val canGrantAccessToView: Box[List[String]] = view.map(_.canGrantAccessToViews.getOrElse(Nil))
canGrantAccessToView.getOrElse(Nil).contains(targetViewId.value)
} else{
//3rd. if targetViewId is customView, we need to check `view.canGrantAccessToCustomViews` field.
view.map(_.canGrantAccessToCustomViews).getOrElse(false)
}
}

def canGrantAccessToMultipleViews(bankId: BankId, accountId: AccountId, viewIdsTobeGranted : List[ViewId], user: User, callContext: Option[CallContext]): Boolean = {
//all the permission this user have for the bankAccount
val permissionBox = Views.views.vend.permission(BankIdAccountId(bankId, accountId), user)
Expand Down
8 changes: 4 additions & 4 deletions obp-api/src/main/scala/code/api/util/ConsentUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -252,20 +252,20 @@ object Consent {
for {
view <- consent.views
} yield {
val viewIdBankIdAccountId = ViewIdBankIdAccountId(ViewId(view.view_id), BankId(view.bank_id), AccountId(view.account_id))
Views.views.vend.revokeAccess(viewIdBankIdAccountId, user)
val bankIdAccountIdViewId = BankIdAccountIdViewId(BankId(view.bank_id), AccountId(view.account_id),ViewId(view.view_id))
Views.views.vend.revokeAccess(bankIdAccountIdViewId, user)
}
val result =
for {
view <- consent.views
} yield {
val viewIdBankIdAccountId = ViewIdBankIdAccountId(ViewId(view.view_id), BankId(view.bank_id), AccountId(view.account_id))
val bankIdAccountIdViewId = BankIdAccountIdViewId(BankId(view.bank_id), AccountId(view.account_id),ViewId(view.view_id))
Views.views.vend.systemView(ViewId(view.view_id)) match {
case Full(systemView) =>
Views.views.vend.grantAccessToSystemView(BankId(view.bank_id), AccountId(view.account_id), systemView, user)
case _ =>
// It's not system view
Views.views.vend.grantAccessToCustomView(viewIdBankIdAccountId, user)
Views.views.vend.grantAccessToCustomView(bankIdAccountIdViewId, user)
}
"Added"
}
Expand Down
11 changes: 7 additions & 4 deletions obp-api/src/main/scala/code/api/util/ErrorMessages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,13 @@ object ErrorMessages {
val GatewayLoginNoJwtForResponse = "OBP-20046: There is no useful value for JWT."

val UserLacksPermissionCanGrantAccessToViewForTargetAccount =
s"OBP-20047: The current user does not have access to a view which lists the target account in ${ViewDefinition.canGrantAccessToViews_.dbColumnName} permissions"
val UserLacksPermissionCanRevokeAccessToViewForTargetAccount =
s"OBP-20048: The current user does not have access to a view which lists the target account in ${ViewDefinition.canRevokeAccessToViews_.dbColumnName} permissions"

s"OBP-20047: If target viewId is system view, the current view.can_grant_access_to_views does not contains it. Or" +
s"if target viewId is custom view, the current view.can_grant_access_to_custom_views is false."

val UserLacksPermissionCanRevokeAccessToViewForTargetAccount =
s"OBP-20047: If target viewId is system view, the current view.can_revoke_access_to_views does not contains it. Or" +
s"if target viewId is custom view, the current view.can_revoke_access_to_custom_views is false."

val UserNotSuperAdmin = "OBP-20050: Current User is not a Super Admin!"

val ElasticSearchIndexNotFound = "OBP-20051: Elasticsearch index or indices not found."
Expand Down
22 changes: 11 additions & 11 deletions obp-api/src/main/scala/code/api/util/NewStyle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -464,38 +464,38 @@ object NewStyle extends MdcLoggable{
} map { fullBoxOrException(_)
} map { unboxFull(_) }

def grantAccessToView(account: BankAccount, u: User, viewIdBankIdAccountId : ViewIdBankIdAccountId, provider : String, providerId: String, callContext: Option[CallContext]) = Future {
account.grantAccessToView(u, viewIdBankIdAccountId, provider, providerId, callContext: Option[CallContext])
def grantAccessToView(account: BankAccount, u: User, bankIdAccountIdViewId : BankIdAccountIdViewId, provider : String, providerId: String, callContext: Option[CallContext]) = Future {
account.grantAccessToView(u, bankIdAccountIdViewId, provider, providerId, callContext: Option[CallContext])
} map {
x => (unboxFullOrFail(
x,
callContext,
UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${viewIdBankIdAccountId.viewId.value}) and current UserId(${u.userId})",
UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewId(${bankIdAccountIdViewId.viewId.value}) and current UserId(${u.userId})",
403),
callContext
)
}

def grantAccessToMultipleViews(account: BankAccount, u: User, viewIdBankIdAccountIds : List[ViewIdBankIdAccountId], provider : String, providerId: String, callContext: Option[CallContext]) = Future {
account.grantAccessToMultipleViews(u, viewIdBankIdAccountIds, provider, providerId, callContext: Option[CallContext])
def grantAccessToMultipleViews(account: BankAccount, u: User, bankIdAccountIdViewIds : List[BankIdAccountIdViewId], provider : String, providerId: String, callContext: Option[CallContext]) = Future {
account.grantAccessToMultipleViews(u, bankIdAccountIdViewIds, provider, providerId, callContext: Option[CallContext])
} map {
x =>
(unboxFullOrFail(
x,
callContext,
UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${viewIdBankIdAccountIds}) and current UserId(${u.userId})",
UserLacksPermissionCanGrantAccessToViewForTargetAccount + s"Current ViewIds(${bankIdAccountIdViewIds}) and current UserId(${u.userId})",
403),
callContext
)
}
def revokeAccessToView(account: BankAccount, u: User, viewIdBankIdAccountId : ViewIdBankIdAccountId, provider : String, providerId: String, callContext: Option[CallContext]) = Future {
account.revokeAccessToView(u, viewIdBankIdAccountId, provider, providerId, callContext: Option[CallContext])
def revokeAccessToView(account: BankAccount, u: User, bankIdAccountIdViewId : BankIdAccountIdViewId, provider : String, providerId: String, callContext: Option[CallContext]) = Future {
account.revokeAccessToView(u, bankIdAccountIdViewId, provider, providerId, callContext: Option[CallContext])
} map {
x =>
(unboxFullOrFail(
x,
callContext,
UserLacksPermissionCanRevokeAccessToViewForTargetAccount + s"Current ViewId(${viewIdBankIdAccountId.viewId.value}) and current UserId(${u.userId})",
UserLacksPermissionCanRevokeAccessToViewForTargetAccount + s"Current ViewId(${bankIdAccountIdViewId.viewId.value}) and current UserId(${u.userId})",
403),
callContext
)
Expand Down Expand Up @@ -611,7 +611,7 @@ object NewStyle extends MdcLoggable{
def grantAccessToCustomView(view : View, user: User, callContext: Option[CallContext]) : Future[View] = {
view.isSystem match {
case false =>
Future(Views.views.vend.grantAccessToCustomView(ViewIdBankIdAccountId(view.viewId, view.bankId, view.accountId), user)) map {
Future(Views.views.vend.grantAccessToCustomView(BankIdAccountIdViewId(view.bankId, view.accountId, view.viewId), user)) map {
unboxFullOrFail(_, callContext, s"$CannotGrantAccountAccess Current ViewId is ${view.viewId.value}")
}
case true =>
Expand All @@ -623,7 +623,7 @@ object NewStyle extends MdcLoggable{
def revokeAccessToCustomView(view : View, user: User, callContext: Option[CallContext]) : Future[Boolean] = {
view.isSystem match {
case false =>
Future(Views.views.vend.revokeAccess(ViewIdBankIdAccountId(view.viewId, view.bankId, view.accountId), user)) map {
Future(Views.views.vend.revokeAccess(BankIdAccountIdViewId(view.bankId, view.accountId, view.viewId), user)) map {
unboxFullOrFail(_, callContext, s"$CannotRevokeAccountAccess Current ViewId is ${view.viewId.value}")
}
case true =>
Expand Down
6 changes: 3 additions & 3 deletions obp-api/src/main/scala/code/api/v1_2/OBPAPI1.2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@
// account <- BankAccount(bankId, accountId)
// u <- user ?~ "user not found"
// viewIds <- tryo{json.extract[ViewIdsJson]} ?~ "wrong format JSON"
// addedViews <- account addPermissions(u, viewIds.views.map(viewIdString => ViewIdBankIdAccountId(ViewId(viewIdString), bankId, accountId)), authProvider, userId)
// addedViews <- account addPermissions(u, viewIds.views.map(viewIdString => BankIdAccountIdViewId(bankId, accountId,ViewId(viewIdString))), authProvider, userId)
// } yield {
// val viewJson = JSONFactory.createViewsJSON(addedViews)
// successJsonResponse(Extraction.decompose(viewJson), 201)
Expand All @@ -301,7 +301,7 @@
// for {
// account <- BankAccount(bankId, accountId)
// u <- user ?~ "user not found"
// addedView <- account addPermission(u, ViewIdBankIdAccountId(viewId, bankId, accountId), authProvider, userId)
// addedView <- account addPermission(u, BankIdAccountIdViewId(bankId, accountId, viewId), authProvider, userId)
// } yield {
// val viewJson = JSONFactory.createViewJSON(addedView)
// successJsonResponse(Extraction.decompose(viewJson), 201)
Expand All @@ -316,7 +316,7 @@
// for {
// account <- BankAccount(bankId, accountId)
// u <- user ?~ "user not found"
// isRevoked <- account revokePermission(u, ViewIdBankIdAccountId(viewId, bankId, accountId), authProvider, userId)
// isRevoked <- account revokePermission(u, BankIdAccountIdViewId(bankId, accountId, viewId), authProvider, userId)
// if(isRevoked)
// } yield noContentJsonResponse
// }
Expand Down
12 changes: 9 additions & 3 deletions obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,13 @@ trait APIMethods121 {
(account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
failMsg = "wrong format JSON"
viewIds <- NewStyle.function.tryons(failMsg, 400, callContext) { json.extract[ViewIdsJson] }
(addedViews, callContext) <- NewStyle.function.grantAccessToMultipleViews(account, u, viewIds.views.map(viewIdString => ViewIdBankIdAccountId(ViewId(viewIdString), bankId, accountId)), provider, providerId,callContext)
(addedViews, callContext) <- NewStyle.function.grantAccessToMultipleViews(
account, u,
viewIds.views.map(viewIdString => BankIdAccountIdViewId(bankId, accountId,ViewId(viewIdString))),
provider,
providerId,
callContext
)
} yield {
(JSONFactory.createViewsJSON(addedViews), HttpCode.`201`(callContext))
}
Expand Down Expand Up @@ -889,7 +895,7 @@ trait APIMethods121 {
(Full(u), callContext) <- authenticatedAccess(cc)
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
(account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
(addedView, callContext) <- NewStyle.function.grantAccessToView(account, u, ViewIdBankIdAccountId(viewId, bankId, accountId), provider, providerId, callContext)
(addedView, callContext) <- NewStyle.function.grantAccessToView(account, u, BankIdAccountIdViewId(bankId, accountId, viewId), provider, providerId, callContext)
} yield {
val viewJson = JSONFactory.createViewJSON(addedView)
(viewJson, HttpCode.`201`(callContext))
Expand Down Expand Up @@ -949,7 +955,7 @@ trait APIMethods121 {
(Full(u), callContext) <- authenticatedAccess(cc)
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
(account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
_ <- NewStyle.function.revokeAccessToView(account, u, ViewIdBankIdAccountId(viewId, bankId, accountId), provider, providerId, callContext)
_ <- NewStyle.function.revokeAccessToView(account, u, BankIdAccountIdViewId(bankId, accountId, viewId), provider, providerId, callContext)
} yield {
(Full(""), HttpCode.`204`(callContext))
}
Expand Down
15 changes: 1 addition & 14 deletions obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4576,7 +4576,7 @@ trait APIMethods400 extends MdcLoggable {
_ <- Future(Views.views.vend.revokeAccountAccessByUser(bankId, accountId, u, callContext)) map {
unboxFullOrFail(_, callContext, s"Cannot revoke")
}
grantViews = for (viewId <- postJson.views) yield ViewIdBankIdAccountId(ViewId(viewId), bankId, accountId)
grantViews = for (viewId <- postJson.views) yield BankIdAccountIdViewId(bankId, accountId, ViewId(viewId))
_ <- Future(Views.views.vend.grantAccessToMultipleViews(grantViews, u, callContext)) map {
unboxFullOrFail(_, callContext, s"Cannot grant the views: ${postJson.views.mkString(",")}")
}
Expand Down Expand Up @@ -12678,25 +12678,12 @@ trait APIMethods400 extends MdcLoggable {
Future.sequence(postJsonBody.roles.map(checkRoleName(callContext,_)))
}

private def grantAccountAccessToUser(bankId: BankId, accountId: AccountId, user: User, view: View, callContext: Option[CallContext]) = {
view.isSystem match {
case true => NewStyle.function.grantAccessToSystemView(bankId, accountId, view, user, callContext)
case false => NewStyle.function.grantAccessToCustomView(view, user, callContext)
}
}
private def grantMultpleAccountAccessToUser(bankId: BankId, accountId: AccountId, user: User, views: List[View], callContext: Option[CallContext]) = {
Future.sequence(views.map(view =>
grantAccountAccessToUser(bankId: BankId, accountId: AccountId, user: User, view, callContext: Option[CallContext])
))
}

private def getView(bankId: BankId, accountId: AccountId, postView: PostViewJsonV400, callContext: Option[CallContext]) = {
postView.is_system match {
case true => NewStyle.function.systemView(ViewId(postView.view_id), callContext)
case false => NewStyle.function.customView(ViewId(postView.view_id), BankIdAccountId(bankId, accountId), callContext)
}
}

private def getViews(bankId: BankId, accountId: AccountId, postJson: PostCreateUserAccountAccessJsonV400, callContext: Option[CallContext]) = {
Future.sequence(postJson.views.map(view => getView(bankId: BankId, accountId: AccountId, view: PostViewJsonV400, callContext: Option[CallContext])))
}
Expand Down
17 changes: 15 additions & 2 deletions obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import java.util.Date

import code.api.Constant
import code.api.attributedefinition.AttributeDefinition
import code.api.util.APIUtil
import code.api.util.{APIUtil, CallContext, NewStyle}
import code.api.util.APIUtil.{DateWithDay, DateWithSeconds, gitCommit, stringOptionOrNull, stringOrNull}
import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON}
import code.api.v1_2_1.{BankRoutingJsonV121, JSONFactory, UserJSONV121, ViewJSONV121}
Expand Down Expand Up @@ -2049,6 +2049,19 @@ object JSONFactory400 {
created_by_user_id = wh.createdByUserId
)
}


def getView(bankId: BankId, accountId: AccountId, postView: PostViewJsonV400, callContext: Option[CallContext]) = {
postView.is_system match {
case true => NewStyle.function.systemView(ViewId(postView.view_id), callContext)
case false => NewStyle.function.customView(ViewId(postView.view_id), BankIdAccountId(bankId, accountId), callContext)
}
}

def grantAccountAccessToUser(bankId: BankId, accountId: AccountId, user: User, view: View, callContext: Option[CallContext]) = {
view.isSystem match {
case true => NewStyle.function.grantAccessToSystemView(bankId, accountId, view, user, callContext)
case false => NewStyle.function.grantAccessToCustomView(view, user, callContext)
}
}
}

Loading

0 comments on commit 3344a78

Please sign in to comment.