diff --git a/obp-api/src/main/scala/code/actorsystem/ObpActorConfig.scala b/obp-api/src/main/scala/code/actorsystem/ObpActorConfig.scala index 0498882048..974c10e305 100644 --- a/obp-api/src/main/scala/code/actorsystem/ObpActorConfig.scala +++ b/obp-api/src/main/scala/code/actorsystem/ObpActorConfig.scala @@ -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, 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 bb7070f21f..c2bc7b8e80 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -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) diff --git a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala index aaa2b75f67..86949f8dd4 100644 --- a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala +++ b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala @@ -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" } diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index 429cddc2c0..5d4cb704b6 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -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." diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index af2a498072..399aed7b4d 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -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 ) @@ -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 => @@ -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 => diff --git a/obp-api/src/main/scala/code/api/v1_2/OBPAPI1.2.scala b/obp-api/src/main/scala/code/api/v1_2/OBPAPI1.2.scala index 83727b4b88..43d28fdcba 100644 --- a/obp-api/src/main/scala/code/api/v1_2/OBPAPI1.2.scala +++ b/obp-api/src/main/scala/code/api/v1_2/OBPAPI1.2.scala @@ -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) @@ -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) @@ -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 // } diff --git a/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala b/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala index 70c5edf036..891b4eb630 100644 --- a/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala +++ b/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala @@ -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)) } @@ -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)) @@ -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)) } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 04e503d180..4f5fe911cd 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -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(",")}") } @@ -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]))) } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala index 61730a237a..f8f813a57d 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala @@ -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} @@ -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) + } + } } diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index d05fe45747..a2145470d4 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -19,7 +19,7 @@ import code.api.v3_0_0.JSONFactory300 import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson import code.api.v3_1_0.ConsentJsonV310 import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson -import code.api.v4_0_0.{JSONFactory400, PostApiCollectionJson400} +import code.api.v4_0_0.{JSONFactory400, PostAccountAccessJsonV400, PostApiCollectionJson400} import code.api.v5_1_0.JSONFactory510.{createRegulatedEntitiesJson, createRegulatedEntityJson} import code.atmattribute.AtmAttribute import code.bankconnectors.Connector @@ -1919,6 +1919,57 @@ trait APIMethods510 { } } + staticResourceDocs += ResourceDoc( + grantUserAccessToViewById, + implementedInApiVersion, + nameOf(grantUserAccessToViewById), + "POST", + "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account-access/grant", + "Grant User access to View By Id", + s"""Grants the User identified by USER_ID access to the view identified by VIEW_ID. + | + |${authenticationRequiredMessage(true)} and the user needs to be account holder. + | + |""", + postAccountAccessJsonV400, + viewJsonV300, + List( + $UserNotLoggedIn, + UserLacksPermissionCanGrantAccessToViewForTargetAccount, + InvalidJsonFormat, + UserNotFoundById, + SystemViewNotFound, + ViewNotFound, + CannotGrantAccountAccess, + UnknownError + ), + List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired)) + + lazy val grantUserAccessToViewById: OBPEndpoint = { + //add access for specific user to a specific system view + case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId):: "account-access" :: "grant" :: Nil JsonPost json -> _ => { + cc => + implicit val ec = EndpointContext(Some(cc)) + val failMsg = s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 " + for { + (Full(u), callContext) <- SS.user + postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) { + json.extract[PostAccountAccessJsonV400] + } + _ <- Helper.booleanToFuture(s"$UserLacksPermissionCanGrantAccessToViewForTargetAccount Current ViewId(${viewId.value}), Target ViewId(${postJson.view.view_id}))", cc = cc.callContext) { + APIUtil.canGrantAccessToView(BankIdAccountIdViewId(bankId,accountId,viewId),ViewId(postJson.view.view_id), u, callContext) + } + (user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, callContext) + view <- JSONFactory400.getView(bankId, accountId, postJson.view, callContext) + addedView <- JSONFactory400.grantAccountAccessToUser(bankId, accountId, user, view, callContext) + + } yield { + val viewJson = JSONFactory300.createViewJSON(addedView) + (viewJson, HttpCode.`201`(callContext)) + } + } + } + } } diff --git a/obp-api/src/main/scala/code/bankconnectors/akka/actor/AkkaConnectorActorConfig.scala b/obp-api/src/main/scala/code/bankconnectors/akka/actor/AkkaConnectorActorConfig.scala index 7be5e55fe1..2b2d3b2762 100644 --- a/obp-api/src/main/scala/code/bankconnectors/akka/actor/AkkaConnectorActorConfig.scala +++ b/obp-api/src/main/scala/code/bankconnectors/akka/actor/AkkaConnectorActorConfig.scala @@ -56,7 +56,7 @@ object AkkaConnectorActorConfig { "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, diff --git a/obp-api/src/main/scala/code/model/BankingData.scala b/obp-api/src/main/scala/code/model/BankingData.scala index ab7028b2b7..e6469bf38a 100644 --- a/obp-api/src/main/scala/code/model/BankingData.scala +++ b/obp-api/src/main/scala/code/model/BankingData.scala @@ -40,7 +40,7 @@ import code.util.Helper import code.util.Helper.MdcLoggable import code.views.Views import code.views.system.AccountAccess -import com.openbankproject.commons.model.{AccountId, AccountRouting, Attribute, Bank, BankAccount, BankAccountCommons, BankId, BankIdAccountId, Counterparty, CounterpartyId, CounterpartyTrait, CreateViewJson, Customer, Permission, TransactionId, UpdateViewJSON, User, UserPrimaryKey, View, ViewId, ViewIdBankIdAccountId} +import com.openbankproject.commons.model.{AccountId, AccountRouting, Attribute, Bank, BankAccount, BankAccountCommons, BankId, BankIdAccountId, Counterparty, CounterpartyId, CounterpartyTrait, CreateViewJson, Customer, Permission, TransactionId, UpdateViewJSON, User, UserPrimaryKey, View, ViewId, BankIdAccountIdViewId} import net.liftweb.common._ import net.liftweb.json.JsonDSL._ import net.liftweb.json.{JArray, JObject} @@ -218,9 +218,9 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable * @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to the view will be granted * @return a Full(true) if everything is okay, a Failure otherwise */ - final def grantAccessToView(user : User, viewUID : ViewIdBankIdAccountId, otherUserProvider : String, otherUserIdGivenByProvider: String, callContext: Option[CallContext]) : Box[View] = { + final def grantAccessToView(user : User, viewUID : BankIdAccountIdViewId, otherUserProvider : String, otherUserIdGivenByProvider: String, callContext: Option[CallContext]) : Box[View] = { def grantAccessToCustomOrSystemView(user: User): Box[View] = { - val ViewIdBankIdAccountId(viewId, bankId, accountId) = viewUID + val BankIdAccountIdViewId(bankId, accountId, viewId) = viewUID Views.views.vend.systemView(viewId) match { case Full(systemView) => Views.views.vend.grantAccessToSystemView(bankId, accountId, systemView, user) case _ => Views.views.vend.grantAccessToCustomView(viewUID, user) @@ -242,7 +242,7 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable * @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to the views will be granted * @return a the list of the granted views if everything is okay, a Failure otherwise */ - final def grantAccessToMultipleViews(user : User, viewUIDs : List[ViewIdBankIdAccountId], otherUserProvider : String, otherUserIdGivenByProvider: String, + final def grantAccessToMultipleViews(user : User, viewUIDs : List[BankIdAccountIdViewId], otherUserProvider : String, otherUserIdGivenByProvider: String, callContext: Option[CallContext]) : Box[List[View]] = { if(canGrantAccessToMultipleViews(bankId, accountId, viewUIDs.map(_.viewId), user, callContext)) for{ @@ -260,9 +260,9 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable * @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to the view will be revoked * @return a Full(true) if everything is okay, a Failure otherwise */ - final def revokeAccessToView(user : User, viewUID : ViewIdBankIdAccountId, otherUserProvider : String, otherUserIdGivenByProvider: String, callContext: Option[CallContext]) : Box[Boolean] = { + final def revokeAccessToView(user : User, viewUID : BankIdAccountIdViewId, otherUserProvider : String, otherUserIdGivenByProvider: String, callContext: Option[CallContext]) : Box[Boolean] = { def revokeAccessToCustomOrSystemView(user: User): Box[Boolean] = { - val ViewIdBankIdAccountId(viewId, bankId, accountId) = viewUID + val BankIdAccountIdViewId(bankId, accountId, viewId) = viewUID Views.views.vend.systemView(viewId) match { case Full(systemView) => Views.views.vend.revokeAccessToSystemView(bankId, accountId, systemView, user) case _ => Views.views.vend.revokeAccess(viewUID, user) diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index 38e785b229..3b9d1de5c7 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -1511,8 +1511,8 @@ def restoreSomeSessions(): Unit = { cbsRemovedViewsForAccount = obpViewsForAccount diff cbsViewsForAccount _ = logger.debug("refreshViewsAccountAccessAndHolders.cbsRemovedViewsForAccount-------" + cbsRemovedViewsForAccount) _ = if(cbsRemovedViewsForAccount.nonEmpty){ - val cbsRemovedViewIdBankIdAccountIds = cbsRemovedViewsForAccount.map(view => ViewIdBankIdAccountId(ViewId(view), bankAccountId.bankId, bankAccountId.accountId)) - Views.views.vend.revokeAccessToMultipleViews(cbsRemovedViewIdBankIdAccountIds, user) + val cbsRemovedBankIdAccountIdViewIds = cbsRemovedViewsForAccount.map(view => BankIdAccountIdViewId(bankAccountId.bankId, bankAccountId.accountId, ViewId(view))) + Views.views.vend.revokeAccessToMultipleViews(cbsRemovedBankIdAccountIdViewIds, user) cbsRemovedViewsForAccount.map(view =>Views.views.vend.removeCustomView(ViewId(view), bankAccountId)) UserRefreshes.UserRefreshes.vend.createOrUpdateRefreshUser(user.userId) } diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataViews.scala b/obp-api/src/main/scala/code/remotedata/RemotedataViews.scala index 12e155d93e..cef608ac0f 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataViews.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataViews.scala @@ -15,32 +15,36 @@ object RemotedataViews extends ObpActorInit with Views { val cc = RemotedataViewsCaseClasses - def grantAccessToMultipleViews(views: List[ViewIdBankIdAccountId], user: User, callContext: Option[CallContext]): Box[List[View]] = getValueFromFuture( + def grantAccessToMultipleViews(views: List[BankIdAccountIdViewId], user: User, callContext: Option[CallContext]): Box[List[View]] = getValueFromFuture( (actor ? cc.grantAccessToMultipleViews(views, user, callContext)).mapTo[Box[List[View]]] ) - def revokeAccessToMultipleViews(views: List[ViewIdBankIdAccountId], user: User): Box[List[View]] = getValueFromFuture( + def revokeAccessToMultipleViews(views: List[BankIdAccountIdViewId], user: User): Box[List[View]] = getValueFromFuture( (actor ? cc.revokeAccessToMultipleViews(views, user)).mapTo[Box[List[View]]] ) def permission(account: BankIdAccountId, user: User): Box[Permission] = getValueFromFuture( (actor ? cc.permission(account, user)).mapTo[Box[Permission]] ) + + def getViewByBankIdAccountIdViewIdUserPrimaryKey(bankIdAccountIdViewId: BankIdAccountIdViewId, userPrimaryKey: UserPrimaryKey): Box[View] = getValueFromFuture( + (actor ? cc.getViewBydBankIdAccountIdViewIdAndUser(bankIdAccountIdViewId: BankIdAccountIdViewId, userPrimaryKey: UserPrimaryKey)).mapTo[Box[View]] + ) def getPermissionForUser(user: User): Box[Permission] = getValueFromFuture( (actor ? cc.getPermissionForUser(user)).mapTo[Box[Permission]] ) - def grantAccessToCustomView(viewIdBankIdAccountId: ViewIdBankIdAccountId, user: User): Box[View] = getValueFromFuture( - (actor ? cc.addPermission(viewIdBankIdAccountId, user)).mapTo[Box[View]] + def grantAccessToCustomView(bankIdAccountIdViewId: BankIdAccountIdViewId, user: User): Box[View] = getValueFromFuture( + (actor ? cc.addPermission(bankIdAccountIdViewId, user)).mapTo[Box[View]] ) def grantAccessToSystemView(bankId: BankId, accountId: AccountId, view: View, user: User): Box[View] = getValueFromFuture( (actor ? cc.addSystemViewPermission(bankId, accountId, view, user)).mapTo[Box[View]] ) - def revokeAccess(viewIdBankIdAccountId : ViewIdBankIdAccountId, user : User) : Box[Boolean] = getValueFromFuture( - (actor ? cc.revokeAccess(viewIdBankIdAccountId, user)).mapTo[Box[Boolean]] + def revokeAccess(bankIdAccountIdViewId : BankIdAccountIdViewId, user : User) : Box[Boolean] = getValueFromFuture( + (actor ? cc.revokeAccess(bankIdAccountIdViewId, user)).mapTo[Box[Boolean]] ) def revokeAccessToSystemView(bankId: BankId, accountId: AccountId, view : View, user : User) : Box[Boolean] = getValueFromFuture( diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataViewsActor.scala b/obp-api/src/main/scala/code/remotedata/RemotedataViewsActor.scala index da5a0562e8..84b4d6cff1 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataViewsActor.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataViewsActor.scala @@ -18,9 +18,9 @@ class RemotedataViewsActor extends Actor with ObpActorHelper with MdcLoggable { def receive: PartialFunction[Any, Unit] = { - case cc.addPermission(viewIdBankIdAccountId : ViewIdBankIdAccountId, user : User) => - logger.debug("addPermission(" + viewIdBankIdAccountId +"," + user +")") - sender ! (mapper.grantAccessToCustomView(viewIdBankIdAccountId, user)) + case cc.addPermission(bankIdAccountIdViewId : BankIdAccountIdViewId, user : User) => + logger.debug("addPermission(" + bankIdAccountIdViewId +"," + user +")") + sender ! (mapper.grantAccessToCustomView(bankIdAccountIdViewId, user)) case cc.addSystemViewPermission(bankId: BankId, accountId: AccountId, view : View, user : User) => logger.debug("addSystemViewPermission(" + bankId +"," + accountId +"," + view +"," + user +")") diff --git a/obp-api/src/main/scala/code/views/MapperViews.scala b/obp-api/src/main/scala/code/views/MapperViews.scala index aa2e6980c0..242dd6d563 100644 --- a/obp-api/src/main/scala/code/views/MapperViews.scala +++ b/obp-api/src/main/scala/code/views/MapperViews.scala @@ -86,6 +86,16 @@ object MapperViews extends Views with MdcLoggable { Full(Permission(user, getViewsForUserAndAccount(user, account))) } + def getViewByBankIdAccountIdViewIdUserPrimaryKey(bankIdAccountIdViewId: BankIdAccountIdViewId, userPrimaryKey: UserPrimaryKey): Box[View] = { + val accountAccessList = AccountAccess.findByBankIdAccountIdViewIdUserPrimaryKey( + bankId = bankIdAccountIdViewId.bankId, + accountId = bankIdAccountIdViewId.accountId, + viewId = bankIdAccountIdViewId.viewId, + userPrimaryKey = userPrimaryKey + ) + accountAccessList.map(getViewFromAccountAccess).flatten + } + def getPermissionForUser(user: User): Box[Permission] = { Full(Permission(user, getViewsForUser(user))) } @@ -124,11 +134,11 @@ object MapperViews extends Views with MdcLoggable { getOrGrantAccessToViewCommon(user, view, bankId.value, accountId.value) } // TODO Accept the whole view as a parameter so we don't have to select it here. - def grantAccessToCustomView(viewIdBankIdAccountId: ViewIdBankIdAccountId, user: User): Box[View] = { - logger.debug(s"addPermission says viewUID is $viewIdBankIdAccountId user is $user") - val viewId = viewIdBankIdAccountId.viewId.value - val bankId = viewIdBankIdAccountId.bankId.value - val accountId = viewIdBankIdAccountId.accountId.value + def grantAccessToCustomView(bankIdAccountIdViewId: BankIdAccountIdViewId, user: User): Box[View] = { + logger.debug(s"addPermission says viewUID is $bankIdAccountIdViewId user is $user") + val viewId = bankIdAccountIdViewId.viewId.value + val bankId = bankIdAccountIdViewId.bankId.value + val accountId = bankIdAccountIdViewId.accountId.value val viewDefinition = ViewDefinition.findCustomView(bankId, accountId, viewId) viewDefinition match { @@ -136,10 +146,10 @@ object MapperViews extends Views with MdcLoggable { if(v.isPublic && !allowPublicViews) return Failure(PublicViewsNotAllowedOnThisInstance) // SQL Select Count AccountAccessList where // This is idempotent - getOrGrantAccessToViewCommon(user, v, viewIdBankIdAccountId.bankId.value, viewIdBankIdAccountId.accountId.value) //accountAccess already exists, no need to create one + getOrGrantAccessToViewCommon(user, v, bankIdAccountIdViewId.bankId.value, bankIdAccountIdViewId.accountId.value) //accountAccess already exists, no need to create one } case _ => { - Empty ~> APIFailure(s"View $viewIdBankIdAccountId. not found", 404) //TODO: move message + code logic to api level + Empty ~> APIFailure(s"View $bankIdAccountIdViewId. not found", 404) //TODO: move message + code logic to api level } } } @@ -150,8 +160,8 @@ object MapperViews extends Views with MdcLoggable { } } - def grantAccessToMultipleViews(views: List[ViewIdBankIdAccountId], user: User, callContext: Option[CallContext]): Box[List[View]] = { - val viewDefinitions: List[(ViewDefinition, ViewIdBankIdAccountId)] = views.map { + def grantAccessToMultipleViews(views: List[BankIdAccountIdViewId], user: User, callContext: Option[CallContext]): Box[List[View]] = { + val viewDefinitions: List[(ViewDefinition, BankIdAccountIdViewId)] = views.map { uid => ViewDefinition.findCustomView(uid.bankId.value,uid.accountId.value, uid.viewId.value).map((_, uid)) .or(ViewDefinition.findSystemView(uid.viewId.value).map((_, uid))) }.collect { case Full(v) => v} @@ -166,15 +176,15 @@ object MapperViews extends Views with MdcLoggable { viewDefinitions.foreach(v => { if(v._1.isPublic && !allowPublicViews) return Failure(PublicViewsNotAllowedOnThisInstance) val viewDefinition = v._1 - val viewIdBankIdAccountId = v._2 + val bankIdAccountIdViewId = v._2 // This is idempotent - getOrGrantAccessToViewCommon(user, viewDefinition, viewIdBankIdAccountId.bankId.value, viewIdBankIdAccountId.accountId.value) + getOrGrantAccessToViewCommon(user, viewDefinition, bankIdAccountIdViewId.bankId.value, bankIdAccountIdViewId.accountId.value) }) Full(viewDefinitions.map(_._1)) } } - def revokeAccessToMultipleViews(views: List[ViewIdBankIdAccountId], user: User): Box[List[View]] = { - val viewDefinitions: List[(ViewDefinition, ViewIdBankIdAccountId)] = views.map { + def revokeAccessToMultipleViews(views: List[BankIdAccountIdViewId], user: User): Box[List[View]] = { + val viewDefinitions: List[(ViewDefinition, BankIdAccountIdViewId)] = views.map { uid => ViewDefinition.findCustomView(uid.bankId.value,uid.accountId.value, uid.viewId.value).map((_, uid)) .or(ViewDefinition.findSystemView(uid.viewId.value).map((_, uid))) }.collect { case Full(v) => v} @@ -195,14 +205,14 @@ object MapperViews extends Views with MdcLoggable { } } - def revokeAccess(viewUID : ViewIdBankIdAccountId, user : User) : Box[Boolean] = { + def revokeAccess(bankIdAccountIdViewId : BankIdAccountIdViewId, user : User) : Box[Boolean] = { val isRevokedCustomViewAccess = for { - customViewDefinition <- ViewDefinition.findCustomView(viewUID.bankId.value, viewUID.accountId.value, viewUID.viewId.value) + customViewDefinition <- ViewDefinition.findCustomView(bankIdAccountIdViewId.bankId.value, bankIdAccountIdViewId.accountId.value, bankIdAccountIdViewId.viewId.value) accountAccess <- AccountAccess.findByBankIdAccountIdViewIdUserPrimaryKey( - viewUID.bankId, - viewUID.accountId, - viewUID.viewId, + bankIdAccountIdViewId.bankId, + bankIdAccountIdViewId.accountId, + bankIdAccountIdViewId.viewId, user.userPrimaryKey ) ?~! CannotFindAccountAccess } yield { @@ -211,15 +221,15 @@ object MapperViews extends Views with MdcLoggable { val isRevokedSystemViewAccess = for { - systemViewDefinition <- ViewDefinition.findSystemView(viewUID.viewId.value) + systemViewDefinition <- ViewDefinition.findSystemView(bankIdAccountIdViewId.viewId.value) accountAccess <- AccountAccess.findByBankIdAccountIdViewIdUserPrimaryKey( - viewUID.bankId, - viewUID.accountId, - viewUID.viewId, + bankIdAccountIdViewId.bankId, + bankIdAccountIdViewId.accountId, + bankIdAccountIdViewId.viewId, user.userPrimaryKey ) ?~! CannotFindAccountAccess // Check if we are allowed to remove the View from the User - _ <- canRevokeOwnerAccessAsBox(viewUID.bankId, viewUID.accountId,systemViewDefinition, user) + _ <- canRevokeOwnerAccessAsBox(bankIdAccountIdViewId.bankId, bankIdAccountIdViewId.accountId,systemViewDefinition, user) } yield { accountAccess.delete_! } diff --git a/obp-api/src/main/scala/code/views/Views.scala b/obp-api/src/main/scala/code/views/Views.scala index 4abd2c425c..49360e0576 100644 --- a/obp-api/src/main/scala/code/views/Views.scala +++ b/obp-api/src/main/scala/code/views/Views.scala @@ -34,16 +34,16 @@ trait Views { def permissions(account : BankIdAccountId) : List[Permission] def permission(account : BankIdAccountId, user: User) : Box[Permission] def getPermissionForUser(user: User) : Box[Permission] - /** + /** * This is for @ViewPrivileges. - * It will first find the view object by `viewIdBankIdAccountId` + * It will first find the view object by `bankIdAccountIdViewId` * And then, call @getOrCreateViewPrivilege(view: View, user: User) for the view and user. */ - def grantAccessToCustomView(viewIdBankIdAccountId : ViewIdBankIdAccountId, user : User) : Box[View] + def grantAccessToCustomView(bankIdAccountIdViewId : BankIdAccountIdViewId, user : User) : Box[View] def grantAccessToSystemView(bankId: BankId, accountId: AccountId, view : View, user : User) : Box[View] - def grantAccessToMultipleViews(views : List[ViewIdBankIdAccountId], user : User, callContext: Option[CallContext]) : Box[List[View]] - def revokeAccessToMultipleViews(views : List[ViewIdBankIdAccountId], user : User) : Box[List[View]] - def revokeAccess(viewIdBankIdAccountId : ViewIdBankIdAccountId, user : User) : Box[Boolean] + def grantAccessToMultipleViews(views : List[BankIdAccountIdViewId], user : User, callContext: Option[CallContext]) : Box[List[View]] + def revokeAccessToMultipleViews(views : List[BankIdAccountIdViewId], user : User) : Box[List[View]] + def revokeAccess(bankIdAccountIdViewId : BankIdAccountIdViewId, user : User) : Box[Boolean] def revokeAccessToSystemView(bankId: BankId, accountId: AccountId, view : View, user : User) : Box[Boolean] def revokeAllAccountAccess(bankId : BankId, accountId : AccountId, user : User) : Box[Boolean] def revokeAccountAccessByUser(bankId : BankId, accountId : AccountId, user : User, callContext: Option[CallContext]) : Box[Boolean] @@ -56,6 +56,7 @@ trait Views { def customViewFuture(viewId : ViewId, bankAccountId: BankIdAccountId) : Future[Box[View]] def systemViewFuture(viewId : ViewId) : Future[Box[View]] def getSystemViews(): Future[List[View]] + def getViewByBankIdAccountIdViewIdUserPrimaryKey(bankIdAccountIdViewId : BankIdAccountIdViewId, userPrimaryKey: UserPrimaryKey) : Box[View] //always return a view id String, not error here. def getMetadataViewId(bankAccountId: BankIdAccountId, viewId : ViewId) = Views.views.vend.customView(viewId, bankAccountId).map(_.metadataView).openOr(viewId.value) @@ -128,11 +129,12 @@ class RemotedataViewsCaseClasses { case class permissions(account: BankIdAccountId) case class getPermissionForUser(user: User) case class permission(account: BankIdAccountId, user: User) - case class addPermission(viewUID: ViewIdBankIdAccountId, user: User) + case class getViewBydBankIdAccountIdViewIdAndUser(bankIdAccountIdViewId: BankIdAccountIdViewId, userPrimaryKey: UserPrimaryKey) + case class addPermission(viewUID: BankIdAccountIdViewId, user: User) case class addSystemViewPermission(bankId: BankId, accountId: AccountId, view : View, user : User) - case class revokeAccess(viewIdBankIdAccountId: ViewIdBankIdAccountId, user : User) - case class grantAccessToMultipleViews(views: List[ViewIdBankIdAccountId], user: User, callContext: Option[CallContext]) - case class revokeAccessToMultipleViews(views: List[ViewIdBankIdAccountId], user: User) + case class revokeAccess(bankIdAccountIdViewId: BankIdAccountIdViewId, user : User) + case class grantAccessToMultipleViews(views: List[BankIdAccountIdViewId], user: User, callContext: Option[CallContext]) + case class revokeAccessToMultipleViews(views: List[BankIdAccountIdViewId], user: User) case class revokeSystemViewPermission(bankId: BankId, accountId: AccountId, view : View, user : User) case class revokeAllAccountAccess(bankId: BankId, accountId: AccountId, user: User) case class revokeAccountAccessByUser(bankId: BankId, accountId: AccountId, user: User, callContext: Option[CallContext]) diff --git a/obp-api/src/test/scala/code/api/v1_2_0/API12Test.scala b/obp-api/src/test/scala/code/api/v1_2_0/API12Test.scala index b020191aa8..056d6dbf89 100644 --- a/obp-api/src/test/scala/code/api/v1_2_0/API12Test.scala +++ b/obp-api/src/test/scala/code/api/v1_2_0/API12Test.scala @@ -1396,7 +1396,7 @@ // val bankId = randomBank // val bankAccount : AccountJSON = randomPrivateAccount(bankId) // val viewId = ViewId("owner") -// val view = Views.views.vend.view(ViewIdBankIdAccountId(viewId, BankId(bankId), AccountId(bankAccount.id))).get +// val view = Views.views.vend.view(BankIdAccountIdViewId(BankId(bankId), AccountId(bankAccount.id), viewId)).get // if(Views.views.vend.getOwners(view).toList.length == 0){ // val userId = resourceUser2.idGivenByProvider // grantUserAccessToView(bankId, bankAccount.id, userId, viewId.value, user1) diff --git a/obp-api/src/test/scala/code/api/v2_2_0/CreateCounterpartyTest.scala b/obp-api/src/test/scala/code/api/v2_2_0/CreateCounterpartyTest.scala index 0ed14088e1..b6035be7c1 100644 --- a/obp-api/src/test/scala/code/api/v2_2_0/CreateCounterpartyTest.scala +++ b/obp-api/src/test/scala/code/api/v2_2_0/CreateCounterpartyTest.scala @@ -7,7 +7,7 @@ import code.api.util.APIUtil.OAuth._ import code.api.util.ErrorMessages import code.setup.DefaultUsers import code.views.Views -import com.openbankproject.commons.model.{AccountId, BankId, ViewId, ViewIdBankIdAccountId} +import com.openbankproject.commons.model.{AccountId, BankId, ViewId, BankIdAccountIdViewId} import net.liftweb.json.JsonAST._ import net.liftweb.json.Serialization.write @@ -90,7 +90,7 @@ class CreateCounterpartyTest extends V220ServerSetup with DefaultUsers { val bankId = testBank.bankId val accountId = AccountId("notExistingAccountId") val viewId =ViewId(SYSTEM_OWNER_VIEW_ID) - Views.views.vend.grantAccessToCustomView(ViewIdBankIdAccountId(viewId, bankId, accountId), resourceUser1) + Views.views.vend.grantAccessToCustomView(BankIdAccountIdViewId(bankId, accountId, viewId), resourceUser1) val counterpartyPostJSON = SwaggerDefinitionsJSON.postCounterpartyJSON.copy(other_bank_routing_address=bankId.value,other_account_routing_address=accountId.value) diff --git a/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala index e7ffd607f1..75007ee992 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/CounterpartyTest.scala @@ -9,7 +9,7 @@ import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0 import code.entitlement.Entitlement import code.views.Views import com.github.dwickern.macros.NameOf.nameOf -import com.openbankproject.commons.model.{AccountId, ErrorMessage, ViewId, ViewIdBankIdAccountId} +import com.openbankproject.commons.model.{AccountId, ErrorMessage, ViewId, BankIdAccountIdViewId} import com.openbankproject.commons.util.ApiVersion import net.liftweb.json.Serialization.write import org.scalatest.Tag diff --git a/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala new file mode 100644 index 0000000000..0722da1551 --- /dev/null +++ b/obp-api/src/test/scala/code/api/v5_1_0/AccountAccessTest.scala @@ -0,0 +1,138 @@ +package code.api.v5_1_0 + +import code.api.Constant.{SYSTEM_AUDITOR_VIEW_ID, SYSTEM_MANAGE_CUSTOM_VIEWS_VIEW_ID, SYSTEM_OWNER_VIEW_ID} +import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON +import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createViewJsonV300 +import code.api.util.APIUtil.OAuth._ +import code.api.util.ApiRole +import code.api.util.ErrorMessages.{UserLacksPermissionCanGrantAccessToViewForTargetAccount, UserNotLoggedIn} +import code.api.v3_0_0.ViewJsonV300 +import code.api.v3_1_0.CreateAccountResponseJsonV310 +import code.api.v4_0_0.{PostAccountAccessJsonV400, PostViewJsonV400} +import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0 +import code.entitlement.Entitlement +import com.github.dwickern.macros.NameOf.nameOf +import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage} +import com.openbankproject.commons.util.ApiVersion +import net.liftweb.common.Box +import net.liftweb.json.Serialization.write +import org.scalatest.Tag + +class AccountAccessTest extends V510ServerSetup { + /** + * Test tags + * Example: To run tests with tag "getPermissions": + * mvn test -D tagsToInclude + * + * This is made possible by the scalatest maven plugin + */ + object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString) + object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.grantUserAccessToViewById)) + + + lazy val bankId = randomBankId + lazy val bankAccount = randomPrivateAccountViaEndpoint(bankId) + lazy val ownerView = SYSTEM_OWNER_VIEW_ID + lazy val managerCustomView = SYSTEM_MANAGE_CUSTOM_VIEWS_VIEW_ID + lazy val postAccountAccessJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400("_test_view", false)) + lazy val postBodyViewJson = createViewJsonV300.toCreateViewJson + + def createAnAccount(bankId: String, user: Option[(Consumer,Token)]): CreateAccountResponseJsonV310 = { + val addAccountJson = SwaggerDefinitionsJSON.createAccountRequestJsonV310.copy(user_id = resourceUser1.userId, balance = AmountOfMoneyJsonV121("EUR","0")) + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" ).POST <@(user1) + val response510 = makePostRequest(request510, write(addAccountJson)) + Then("We should get a 201") + + response510.code should equal(201) + response510.body.extract[CreateAccountResponseJsonV310] + } + + def createViewForAnAccount(bankId: String, accountId: String): ViewJsonV300 = { + createViewViaEndpoint(bankId, accountId, postBodyViewJson, user1) + } + + feature(s"test $ApiEndpoint1 Authorized access") { + + scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) { + When("We make a request v4.0.0") + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / bankAccount.id / ownerView /"account-access" / "grant").POST + val response510 = makePostRequest(request510, write(postAccountAccessJson)) + Then("We should get a 401") + response510.code should equal(401) + response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) + } + + scenario("We will call the endpoint with user credentials and system view, but try to grant custom view access", VersionOfApi, ApiEndpoint1) { + val addedEntitlement: Box[Entitlement] = Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, ApiRole.CanCreateAccount.toString) + val account = try { + createAnAccount(bankId, user1) + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + val view = createViewForAnAccount(bankId, account.account_id) + val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(view.id, view.is_system)) + When("We send the request") + val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / ownerView / "account-access" / "grant").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + Then("We should get a 400 and check the response body") + response.code should equal(400) + response.body.toString.contains(UserLacksPermissionCanGrantAccessToViewForTargetAccount) + } + + scenario("We will call the endpoint with user credentials and managerCustomView view, but try to grant system view access", VersionOfApi, ApiEndpoint1) { + val addedEntitlement: Box[Entitlement] = Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, ApiRole.CanCreateAccount.toString) + val account = try { + createAnAccount(bankId, user1) + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(SYSTEM_AUDITOR_VIEW_ID, true)) + When("We send the request") + val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / managerCustomView / "account-access" / "grant").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + Then("We should get a 400 and check the response body") + response.code should equal(400) + response.body.toString.contains(UserLacksPermissionCanGrantAccessToViewForTargetAccount) + } + + scenario("We will call the endpoint with user credentials and system view permission", VersionOfApi, ApiEndpoint1) { + val addedEntitlement: Box[Entitlement] = Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, ApiRole.CanCreateAccount.toString) + val account = try { + createAnAccount(bankId, user1) + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(SYSTEM_AUDITOR_VIEW_ID, true)) + When("We send the request") + val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / ownerView / "account-access" / "grant").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + Then("We should get a 201 and check the response body") + response.code should equal(201) + response.body.extract[ViewJsonV300] + } + + scenario("We will call the endpoint with user credentials and custom view permission", VersionOfApi, ApiEndpoint1) { + val addedEntitlement: Box[Entitlement] = Entitlement.entitlement.vend.addEntitlement(bankId, resourceUser1.userId, ApiRole.CanCreateAccount.toString) + val account = try { + createAnAccount(bankId, user1) + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + val view = createViewForAnAccount(bankId, account.account_id) + val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(view.id, view.is_system)) + When("We send the request") + val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / managerCustomView / "account-access" / "grant").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + Then("We should get a 201 and check the response body") + response.code should equal(201) + response.body.extract[ViewJsonV300] + } + } + + + +} diff --git a/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala b/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala index 32a54de625..0d93447152 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/V510ServerSetup.scala @@ -1,15 +1,19 @@ package code.api.v5_1_0 +import code.api.Constant.SYSTEM_OWNER_VIEW_ID import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON import code.api.util.APIUtil.OAuth.{Consumer, Token, _} import code.api.util.ApiRole import code.api.util.ApiRole.CanCreateCustomer +import code.api.v1_2_1.{AccountJSON, AccountsJSON, ViewsJSONV121} import code.api.v2_0_0.BasicAccountsJSON +import code.api.v3_0_0.ViewJsonV300 import code.api.v3_1_0.CustomerJsonV310 import code.api.v4_0_0.{AtmJsonV400, BanksJson400} import code.api.v5_0_0.PostCustomerJsonV500 import code.entitlement.Entitlement import code.setup.{APIResponse, DefaultUsers, ServerSetupWithTestData} +import com.openbankproject.commons.model.CreateViewJson import com.openbankproject.commons.util.ApiShortVersions import dispatch.Req import net.liftweb.json.Serialization.write @@ -34,6 +38,26 @@ trait V510ServerSetup extends ServerSetupWithTestData with DefaultUsers { val bank = banksJson.banks(randomPosition) bank.id } + + def getPrivateAccountsViaEndpoint(bankId : String, consumerAndToken: Option[(Consumer, Token)]) : APIResponse = { + val request = v5_1_0_Request / "banks" / bankId / "accounts" / "private" <@(consumerAndToken) + makeGetRequest(request) + } + + def randomPrivateAccountViaEndpoint(bankId : String): AccountJSON = { + val accountsJson = getPrivateAccountsViaEndpoint(bankId, user1).body.extract[AccountsJSON].accounts + val randomPosition = nextInt(accountsJson.size) + accountsJson(randomPosition) + } + + def createViewViaEndpoint(bankId: String, accountId: String, createViewJson: CreateViewJson, consumerAndToken: Option[(Consumer, Token)]): ViewJsonV300 = { + def postView(bankId: String, accountId: String, view: CreateViewJson, consumerAndToken: Option[(Consumer, Token)]): APIResponse = { + val request = (v4_0_0_Request / "banks" / bankId / "accounts" / accountId / "views").POST <@(consumerAndToken) + makePostRequest(request, write(view)) + } + val reply = postView(bankId, accountId, createViewJson, consumerAndToken) + reply.body.extract[ViewJsonV300] + } def createAtmAtBank(bankId: String): AtmJsonV400 = { val postAtmJson = SwaggerDefinitionsJSON.atmJsonV400.copy(bank_id = bankId) diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala index 113de64f9b..05b4ae2adb 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala @@ -65,8 +65,8 @@ trait Bank { /** * Uniquely identifies a view */ -case class ViewIdBankIdAccountId(viewId : ViewId, bankId : BankId, accountId : AccountId) { - override def toString = s"view $viewId, for account: $accountId at bank $bankId" +case class BankIdAccountIdViewId(bankId : BankId, accountId : AccountId, viewId : ViewId) { + override def toString = s"BankIdAccountIdViewId($bankId,$accountId,$viewId)" } /* diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala index cb15827286..ccdee4fb19 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala @@ -218,7 +218,7 @@ trait View { def bankId: BankId //and here is the unique identifier - def uid: ViewIdBankIdAccountId = ViewIdBankIdAccountId(viewId, bankId, accountId) + def uid: BankIdAccountIdViewId = BankIdAccountIdViewId(bankId, accountId, viewId) //The name is the orignal value from developer, when they create the views. // It can be any string value, also see the viewId,