Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Marko Milić 2024-03-27 14:52:41 +01:00
commit 345deb4ed2
24 changed files with 359 additions and 106 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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"
}

View File

@ -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."

View File

@ -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 =>

View File

@ -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
// }

View File

@ -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))
}

View File

@ -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])))
}

View File

@ -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)
}
}
}

View File

@ -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))
}
}
}
}
}

View File

@ -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,

View File

@ -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)

View File

@ -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)
}

View File

@ -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(

View File

@ -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 +")")

View File

@ -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_!
}

View File

@ -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])

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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]
}
}
}

View File

@ -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)

View File

@ -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)"
}
/*

View File

@ -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,