mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 11:06:49 +00:00
Merge pull request #2371 from hongwei1/develop
Feature/OBPv510 refactor the Account Access endpoints
This commit is contained in:
commit
32e9fd2ea1
@ -647,7 +647,7 @@ trait OBPRestHelper extends RestHelper with MdcLoggable {
|
||||
apiPrefix:OBPEndpoint => OBPEndpoint,
|
||||
autoValidateAll: Boolean = false): Unit = {
|
||||
|
||||
def isAutoValidate(doc: ResourceDoc): Boolean = { //note: only support v5.0.0 and v4.0.0 at the moment.
|
||||
def isAutoValidate(doc: ResourceDoc): Boolean = { //note: only support v5.1.0, v5.0.0 and v4.0.0 at the moment.
|
||||
doc.isValidateEnabled || (autoValidateAll && !doc.isValidateDisabled && List(OBPAPI5_1_0.version,OBPAPI5_0_0.version,OBPAPI4_0_0.version).contains(doc.implementedInApiVersion))
|
||||
}
|
||||
|
||||
|
||||
@ -5399,6 +5399,9 @@ object SwaggerDefinitionsJSON {
|
||||
val atmsJsonV510 = AtmsJsonV510(
|
||||
atms = List(atmJsonV510)
|
||||
)
|
||||
|
||||
val postAccountAccessJsonV510 = PostAccountAccessJsonV510(userIdExample.value,viewIdExample.value)
|
||||
|
||||
//The common error or success format.
|
||||
//Just some helper format to use in Json
|
||||
case class NotSupportedYet()
|
||||
|
||||
@ -4059,22 +4059,29 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
|
||||
//we need set guard to easily distinguish the system view and custom view,
|
||||
// customer view must start with '_', system can not
|
||||
// viewName and viewId are the same value, just with different format, eg: createViewIdByName(view.name)
|
||||
def checkSystemViewIdOrName(viewId: String): Boolean = !checkCustomViewIdOrName(viewId: String)
|
||||
// viewId is created by viewName, please check method : createViewIdByName(view.name)
|
||||
// so here we can use isSystemViewName method to check viewId
|
||||
def isValidSystemViewId(viewId: String): Boolean = isValidSystemViewName(viewId: String)
|
||||
|
||||
def isValidSystemViewName(viewName: String): Boolean = !isValidCustomViewName(viewName: String)
|
||||
|
||||
// viewId is created by viewName, please check method : createViewIdByName(view.name)
|
||||
// so here we can use isCustomViewName method to check viewId
|
||||
def isValidCustomViewId(viewId: String): Boolean = isValidCustomViewName(viewId)
|
||||
|
||||
//customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
|
||||
// viewName and viewId are the same value, just with different format, eg: createViewIdByName(view.name)
|
||||
def checkCustomViewIdOrName(name: String): Boolean = name match {
|
||||
def isValidCustomViewName(name: String): Boolean = name match {
|
||||
case x if x.startsWith("_") => true // Allowed case
|
||||
case _ => false
|
||||
}
|
||||
|
||||
@deprecated("now need bankIdAccountIdViewId and targetViewId explicitly, please check the other `canGrantAccessToView` method","02-04-2024")
|
||||
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 targetViewId is systemView. just compare all the permissions
|
||||
if(checkSystemViewIdOrName(targetViewId.value)){
|
||||
//1. If targetViewId is systemView. just compare all the permissions
|
||||
if(isValidSystemViewId(targetViewId.value)){
|
||||
val allCanGrantAccessToViewsPermissions: List[String] = permission
|
||||
.map(_.views.map(_.canGrantAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct
|
||||
|
||||
@ -4092,75 +4099,100 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
//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)
|
||||
//2rd: If targetViewId is systemView. we need to check `view.canGrantAccessToViews` field.
|
||||
if(isValidSystemViewId(targetViewId.value)){
|
||||
val canGrantAccessToSystemViews: Box[List[String]] = view.map(_.canGrantAccessToViews.getOrElse(Nil))
|
||||
canGrantAccessToSystemViews.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 = {
|
||||
|
||||
@deprecated("now need bankIdAccountIdViewId and targetViewId explicitly","02-04-2024")
|
||||
def canGrantAccessToMultipleViews(bankId: BankId, accountId: AccountId, targetViewIds : 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)
|
||||
|
||||
//check if we can grant all systemViews Access
|
||||
val allCanGrantAccessToViewsPermissions: List[String] = permissionBox.map(_.views.map(_.canGrantAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct
|
||||
val allSystemViewsAccessTobeGranted: List[String] = viewIdsTobeGranted.map(_.value).distinct.filter(checkSystemViewIdOrName)
|
||||
val canGrantAccessToAllSystemViews = allSystemViewsAccessTobeGranted.forall(allCanGrantAccessToViewsPermissions.contains)
|
||||
//Retrieve all views from the 'canRevokeAccessToViews' list within each view from the permission views.
|
||||
val allCanGrantAccessToSystemViews: List[String] = permissionBox.map(_.views.map(_.canGrantAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct
|
||||
|
||||
val allSystemViewsIdsTobeGranted: List[String] = targetViewIds.map(_.value).distinct.filter(isValidSystemViewId)
|
||||
|
||||
val canGrantAllSystemViewsIdsTobeGranted = allSystemViewsIdsTobeGranted.forall(allCanGrantAccessToSystemViews.contains)
|
||||
|
||||
if (viewIdsTobeGranted.map(_.value).distinct.find(checkCustomViewIdOrName).isDefined){
|
||||
//check if we can grant all customViews Access
|
||||
//if the targetViewIds contains custom view ids, we need to check the both canGrantAccessToCustomViews and canGrantAccessToSystemViews
|
||||
if (targetViewIds.map(_.value).distinct.find(isValidCustomViewId).isDefined){
|
||||
//check if we can grant all customViews Access.
|
||||
val allCanGrantAccessToCustomViewsPermissions: List[Boolean] = permissionBox.map(_.views.map(_.canGrantAccessToCustomViews)).getOrElse(Nil)
|
||||
val canGrantAccessToAllCustomViews = allCanGrantAccessToCustomViewsPermissions.contains(true)
|
||||
//we need merge both system and custom access
|
||||
canGrantAccessToAllSystemViews && canGrantAccessToAllCustomViews
|
||||
canGrantAllSystemViewsIdsTobeGranted && canGrantAccessToAllCustomViews
|
||||
} else {// if targetViewIds only contains system view ids, we only need to check `canGrantAccessToSystemViews`
|
||||
canGrantAllSystemViewsIdsTobeGranted
|
||||
}
|
||||
}
|
||||
|
||||
def canRevokeAccessToView(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: If targetViewId is systemView. we need to check `view.canGrantAccessToViews` field.
|
||||
if (isValidSystemViewId(targetViewId.value)) {
|
||||
val canRevokeAccessToSystemViews: Box[List[String]] = view.map(_.canRevokeAccessToViews.getOrElse(Nil))
|
||||
canRevokeAccessToSystemViews.getOrElse(Nil).contains(targetViewId.value)
|
||||
} else {
|
||||
canGrantAccessToAllSystemViews
|
||||
//3rd. if targetViewId is customView, we need to check `view.canGrantAccessToCustomViews` field.
|
||||
view.map(_.canRevokeAccessToCustomViews).getOrElse(false)
|
||||
}
|
||||
}
|
||||
|
||||
def canRevokeAccessToView(bankId: BankId, accountId: AccountId, viewIdToBeRevoked : ViewId, user: User, callContext: Option[CallContext]): Boolean = {
|
||||
@deprecated("now need bankIdAccountIdViewId and targetViewId explicitly","02-04-2024")
|
||||
def canRevokeAccessToView(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 viewIdTobeRevoked is systemView. just compare all the permissions
|
||||
if (checkSystemViewIdOrName(viewIdToBeRevoked.value)) {
|
||||
val allCanRevokeAccessToViewsPermissions: List[String] = permission
|
||||
//1. If targetViewId is systemView. just compare all the permissions
|
||||
if (isValidSystemViewId(targetViewId.value)) {
|
||||
val allCanRevokeAccessToSystemViews: List[String] = permission
|
||||
.map(_.views.map(_.canRevokeAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct
|
||||
|
||||
allCanRevokeAccessToViewsPermissions.contains(viewIdToBeRevoked.value)
|
||||
allCanRevokeAccessToSystemViews.contains(targetViewId.value)
|
||||
} else {
|
||||
//2. if viewIdTobeRevoked is customView, we only need to check the `canRevokeAccessToCustomViews`.
|
||||
//2. if targetViewId is customView, we only need to check the `canRevokeAccessToCustomViews`.
|
||||
val allCanRevokeAccessToCustomViewsPermissions: List[Boolean] = permission.map(_.views.map(_.canRevokeAccessToCustomViews)).getOrElse(Nil)
|
||||
|
||||
allCanRevokeAccessToCustomViewsPermissions.contains(true)
|
||||
}
|
||||
}
|
||||
|
||||
def canRevokeAccessToAllViews(bankId: BankId, accountId: AccountId, user: User, callContext: Option[CallContext]): Boolean = {
|
||||
|
||||
val permissionBox = Views.views.vend.permission(BankIdAccountId(bankId, accountId), user)
|
||||
|
||||
//check if we can revoke all systemViews Access
|
||||
val allCanRevokeAccessToViewsPermissions: List[String] = permissionBox.map(_.views.map(_.canRevokeAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct
|
||||
val allAccountAccessSystemViews: List[String] = permissionBox.map(_.views.map(_.viewId.value)).getOrElse(Nil).distinct.filter(checkSystemViewIdOrName)
|
||||
val canRevokeAccessToAllSystemViews = allAccountAccessSystemViews.forall(allCanRevokeAccessToViewsPermissions.contains)
|
||||
|
||||
if (allAccountAccessSystemViews.find(checkCustomViewIdOrName).isDefined){
|
||||
@deprecated("now need bankIdAccountIdViewId and targetViewId explicitly","02-04-2024")
|
||||
def canRevokeAccessToAllViews(bankId: BankId, accountId: AccountId, user: User, callContext: Option[CallContext]): Boolean = {
|
||||
|
||||
val permissionBox = Views.views.vend.permission(BankIdAccountId(bankId, accountId), user)
|
||||
|
||||
//Retrieve all views from the 'canRevokeAccessToViews' list within each view from the permission views.
|
||||
val allCanRevokeAccessToViews: List[String] = permissionBox.map(_.views.map(_.canRevokeAccessToViews.getOrElse(Nil)).flatten).getOrElse(Nil).distinct
|
||||
|
||||
//All targetViewIds:
|
||||
val allTargetViewIds: List[String] = permissionBox.map(_.views.map(_.viewId.value)).getOrElse(Nil).distinct
|
||||
|
||||
val allSystemTargetViewIs: List[String] = allTargetViewIds.filter(isValidSystemViewId)
|
||||
|
||||
val canRevokeAccessToAllSystemTargetViews = allSystemTargetViewIs.forall(allCanRevokeAccessToViews.contains)
|
||||
|
||||
//if allTargetViewIds contains customViewId,we need to check both `canRevokeAccessToCustomViews` and `canRevokeAccessToSystemViews` fields
|
||||
if (allTargetViewIds.find(isValidCustomViewId).isDefined) {
|
||||
//check if we can revoke all customViews Access
|
||||
val allCanRevokeAccessToCustomViewsPermissions: List[Boolean] = permissionBox.map(_.views.map(_.canRevokeAccessToCustomViews)).getOrElse(Nil)
|
||||
val canRevokeAccessToAllCustomViews = allCanRevokeAccessToCustomViewsPermissions.contains(true)
|
||||
//we need merge both system and custom access
|
||||
canRevokeAccessToAllSystemViews && canRevokeAccessToAllCustomViews
|
||||
}else if(allAccountAccessSystemViews.find(checkSystemViewIdOrName).isDefined){
|
||||
canRevokeAccessToAllSystemViews
|
||||
}else{
|
||||
canRevokeAccessToAllSystemTargetViews && canRevokeAccessToAllCustomViews
|
||||
} else if (allTargetViewIds.find(isValidSystemViewId).isDefined) {
|
||||
canRevokeAccessToAllSystemTargetViews
|
||||
} else {//if both allCanRevokeAccessToViews and allSystemTargetViewIs are empty,
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def getJValueFromJsonFile(path: String) = {
|
||||
@ -4883,10 +4915,16 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
) = s"requestedApiVersionString:$requestedApiVersionString-bankId:$bankId-tags:$tags-partialFunctions:$partialFunctions-locale:${locale.toString}" +
|
||||
s"-contentParam:$contentParam-apiCollectionIdParam:$apiCollectionIdParam-isVersion4OrHigher:$isVersion4OrHigher-isStaticResource:$isStaticResource".intern()
|
||||
|
||||
def getUserLacksRevokePermissionErrorMessage(sourceViewId: ViewId, targetViewId: ViewId) =
|
||||
if (isValidSystemViewId(targetViewId.value))
|
||||
UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount + s"Current source viewId(${sourceViewId.value}) and target viewId (${targetViewId.value})"
|
||||
else
|
||||
UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount + s"Current source viewId(${sourceViewId.value}) and target viewId (${targetViewId.value})"
|
||||
|
||||
}
|
||||
def getUserLacksGrantPermissionErrorMessage(sourceViewId: ViewId, targetViewId: ViewId) =
|
||||
if (isValidSystemViewId(targetViewId.value))
|
||||
UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount + s"Current source viewId(${sourceViewId.value}) and target viewId (${targetViewId.value})"
|
||||
else
|
||||
UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount + s"Current source viewId(${sourceViewId.value}) and target viewId (${targetViewId.value})"
|
||||
|
||||
|
||||
object createDependentConnectorMethod extends App{
|
||||
|
||||
}
|
||||
@ -195,7 +195,7 @@ object ErrorMessages {
|
||||
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"OBP-20048: 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!"
|
||||
@ -232,6 +232,19 @@ object ErrorMessages {
|
||||
val MissingDirectLoginHeader = "OBP-20082: Missing DirectLogin or Authorization header."
|
||||
val InvalidDirectLoginHeader = "OBP-20083: Missing DirectLogin word at the value of Authorization header."
|
||||
|
||||
|
||||
val UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount =
|
||||
s"OBP-20084: The current source view.can_grant_access_to_views does not contains target view."
|
||||
|
||||
val UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount =
|
||||
s"OBP-20085: The current source view.can_grant_access_to_custom_views is false."
|
||||
|
||||
val UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount =
|
||||
s"OBP-20086: The current source view.can_revoke_access_to_views does not contains target view."
|
||||
|
||||
val UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount =
|
||||
s"OBP-20087: The current source view.can_revoke_access_to_custom_views is false."
|
||||
|
||||
val UserNotSuperAdminOrMissRole = "OBP-20101: Current User is not super admin or is missing entitlements:"
|
||||
val CannotGetOrCreateUser = "OBP-20102: Cannot get or create user."
|
||||
val InvalidUserProvider = "OBP-20103: Invalid DAuth User Provider."
|
||||
|
||||
@ -544,14 +544,14 @@ object NewStyle extends MdcLoggable{
|
||||
Future{
|
||||
APIUtil.checkViewAccessAndReturnView(viewId, bankAccountId, user, callContext)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView")
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView Current ViewId is ${viewId.value}")
|
||||
}
|
||||
}
|
||||
def checkAccountAccessAndGetView(viewId : ViewId, bankAccountId: BankIdAccountId, user: Option[User], callContext: Option[CallContext]) : Future[View] = {
|
||||
Future{
|
||||
APIUtil.checkViewAccessAndReturnView(viewId, bankAccountId, user, callContext)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView ${viewId.value}", 403)
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView Current ViewId is ${viewId.value}", 403)
|
||||
}
|
||||
}
|
||||
def checkViewsAccessAndReturnView(firstView : ViewId, secondView : ViewId, bankAccountId: BankIdAccountId, user: Option[User], callContext: Option[CallContext]) : Future[View] = {
|
||||
@ -560,7 +560,7 @@ object NewStyle extends MdcLoggable{
|
||||
APIUtil.checkViewAccessAndReturnView(secondView, bankAccountId, user, callContext)
|
||||
)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView")
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView Current ViewId is ${firstView.value} or ${secondView.value}")
|
||||
}
|
||||
}
|
||||
def checkBalancingTransactionAccountAccessAndReturnView(doubleEntryTransaction: DoubleEntryTransaction, user: Option[User], callContext: Option[CallContext]) : Future[View] = {
|
||||
@ -578,7 +578,7 @@ object NewStyle extends MdcLoggable{
|
||||
APIUtil.checkViewAccessAndReturnView(ownerViewId, creditBankAccountId, user, callContext)
|
||||
)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView")
|
||||
unboxFullOrFail(_, callContext, s"$UserNoPermissionAccessView Current ViewId is ${ownerViewId.value}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -595,7 +595,7 @@ trait APIMethods121 {
|
||||
u <- cc.user ?~ UserNotLoggedIn
|
||||
createViewJsonV121 <- tryo{json.extract[CreateViewJsonV121]} ?~ InvalidJsonFormat
|
||||
//customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
|
||||
_<- booleanToBox(checkCustomViewIdOrName(createViewJsonV121.name), InvalidCustomViewFormat+s"Current view_name (${createViewJsonV121.name})")
|
||||
_<- booleanToBox(isValidCustomViewName(createViewJsonV121.name), InvalidCustomViewFormat+s"Current view_name (${createViewJsonV121.name})")
|
||||
account <- BankAccountX(bankId, accountId) ?~! BankAccountNotFound
|
||||
createViewJson = CreateViewJson(
|
||||
createViewJsonV121.name,
|
||||
|
||||
@ -191,7 +191,7 @@ trait APIMethods220 {
|
||||
for {
|
||||
createViewJsonV121 <- tryo{json.extract[CreateViewJsonV121]} ?~!InvalidJsonFormat
|
||||
//customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
|
||||
_<- booleanToBox(checkCustomViewIdOrName(createViewJsonV121.name), InvalidCustomViewFormat+s"Current view_name (${createViewJsonV121.name})")
|
||||
_<- booleanToBox(isValidCustomViewName(createViewJsonV121.name), InvalidCustomViewFormat+s"Current view_name (${createViewJsonV121.name})")
|
||||
u <- cc.user ?~!UserNotLoggedIn
|
||||
account <- BankAccountX(bankId, accountId) ?~! BankAccountNotFound
|
||||
createViewJson = CreateViewJson(
|
||||
|
||||
@ -210,7 +210,7 @@ trait APIMethods300 {
|
||||
}
|
||||
//customer views are started ith `_`,eg _life, _work, and System views startWith letter, eg: owner
|
||||
_ <- Helper.booleanToFuture(failMsg = InvalidCustomViewFormat+s"Current view_name (${createViewJson.name})", cc=callContext) {
|
||||
checkCustomViewIdOrName(createViewJson.name)
|
||||
isValidCustomViewName(createViewJson.name)
|
||||
}
|
||||
(account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext)
|
||||
|
||||
|
||||
@ -3985,7 +3985,7 @@ trait APIMethods310 {
|
||||
}
|
||||
//System views can not startwith '_'
|
||||
_ <- Helper.booleanToFuture(failMsg = InvalidSystemViewFormat+s"Current view_name (${createViewJson.name})", cc = callContext) {
|
||||
checkSystemViewIdOrName(createViewJson.name)
|
||||
isValidSystemViewName(createViewJson.name)
|
||||
}
|
||||
_ <- Helper.booleanToFuture(SystemViewCannotBePublicError, failCode=400, cc=callContext) {
|
||||
createViewJson.is_public == false
|
||||
|
||||
@ -4492,7 +4492,7 @@ trait APIMethods400 extends MdcLoggable {
|
||||
revokedJsonV400,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
UserLacksPermissionCanGrantAccessToViewForTargetAccount,
|
||||
UserLacksPermissionCanRevokeAccessToViewForTargetAccount,
|
||||
InvalidJsonFormat,
|
||||
UserNotFoundById,
|
||||
SystemViewNotFound,
|
||||
|
||||
@ -1889,7 +1889,7 @@ trait APIMethods500 {
|
||||
}
|
||||
// custom views are started with `_`,eg _ life, _ work, and System views can not, eg: owner.
|
||||
_ <- Helper.booleanToFuture(failMsg = InvalidSystemViewFormat +s"Current view_name (${createViewJson.name})", cc = cc.callContext) {
|
||||
checkSystemViewIdOrName(createViewJson.name)
|
||||
isValidSystemViewName(createViewJson.name)
|
||||
}
|
||||
view <- NewStyle.function.createSystemView(createViewJson.toCreateViewJson, cc.callContext)
|
||||
} yield {
|
||||
|
||||
@ -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, PostAccountAccessJsonV400, PostApiCollectionJson400}
|
||||
import code.api.v4_0_0.{JSONFactory400, PostAccountAccessJsonV400, PostApiCollectionJson400, RevokedJsonV400}
|
||||
import code.api.v5_1_0.JSONFactory510.{createRegulatedEntitiesJson, createRegulatedEntityJson}
|
||||
import code.atmattribute.AtmAttribute
|
||||
import code.bankconnectors.Connector
|
||||
@ -1924,18 +1924,22 @@ trait APIMethods510 {
|
||||
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.
|
||||
"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/account-access/grant",
|
||||
"Grant User access to View",
|
||||
s"""Grants the User identified by USER_ID access to the view identified.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)} and the user needs to be account holder.
|
||||
|
|
||||
|""",
|
||||
postAccountAccessJsonV400,
|
||||
postAccountAccessJsonV510,
|
||||
viewJsonV300,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
UserLacksPermissionCanGrantAccessToViewForTargetAccount,
|
||||
$BankNotFound,
|
||||
$BankAccountNotFound,
|
||||
$UserNoPermissionAccessView,
|
||||
UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount,
|
||||
UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount,
|
||||
InvalidJsonFormat,
|
||||
UserNotFoundById,
|
||||
SystemViewNotFound,
|
||||
@ -1947,25 +1951,170 @@ trait APIMethods510 {
|
||||
|
||||
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 -> _ => {
|
||||
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) ::"views":: 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 $PostAccountAccessJsonV510 "
|
||||
for {
|
||||
(Full(u), callContext) <- SS.user
|
||||
postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
|
||||
json.extract[PostAccountAccessJsonV510]
|
||||
}
|
||||
targetViewId = ViewId(postJson.view_id)
|
||||
msg = getUserLacksGrantPermissionErrorMessage(viewId, targetViewId)
|
||||
_ <- Helper.booleanToFuture(msg, 403, cc = cc.callContext) {
|
||||
APIUtil.canGrantAccessToView(BankIdAccountIdViewId(bankId,accountId,viewId),targetViewId, u, callContext)
|
||||
}
|
||||
(user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, callContext)
|
||||
view <- isValidSystemViewId(targetViewId.value) match {
|
||||
case true => NewStyle.function.systemView(targetViewId, callContext)
|
||||
case false => NewStyle.function.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
|
||||
}
|
||||
addedView <- JSONFactory400.grantAccountAccessToUser(bankId, accountId, user, view, callContext)
|
||||
|
||||
} yield {
|
||||
val viewJson = JSONFactory300.createViewJSON(addedView)
|
||||
(viewJson, HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
revokeUserAccessToViewById,
|
||||
implementedInApiVersion,
|
||||
nameOf(revokeUserAccessToViewById),
|
||||
"POST",
|
||||
"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/account-access/revoke",
|
||||
"Revoke User access to View",
|
||||
s"""Revoke the User identified by USER_ID access to the view identified.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}.
|
||||
|
|
||||
|""",
|
||||
postAccountAccessJsonV510,
|
||||
revokedJsonV400,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
$BankNotFound,
|
||||
$BankAccountNotFound,
|
||||
$UserNoPermissionAccessView,
|
||||
UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount,
|
||||
UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount,
|
||||
InvalidJsonFormat,
|
||||
UserNotFoundById,
|
||||
SystemViewNotFound,
|
||||
ViewNotFound,
|
||||
CannotRevokeAccountAccess,
|
||||
CannotFindAccountAccess,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired))
|
||||
|
||||
lazy val revokeUserAccessToViewById: OBPEndpoint = {
|
||||
//add access for specific user to a specific system view
|
||||
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" ::ViewId(viewId) :: "account-access" :: "revoke" :: 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]
|
||||
json.extract[PostAccountAccessJsonV510]
|
||||
}
|
||||
_ <- 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)
|
||||
targetViewId = ViewId(postJson.view_id)
|
||||
|
||||
msg = getUserLacksRevokePermissionErrorMessage(viewId, targetViewId)
|
||||
|
||||
_ <- Helper.booleanToFuture(msg, 403, cc = cc.callContext) {
|
||||
APIUtil.canRevokeAccessToView(BankIdAccountIdViewId(bankId, accountId, viewId),targetViewId, u, callContext)
|
||||
}
|
||||
(user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, cc.callContext)
|
||||
view <- isValidSystemViewId(targetViewId.value) match {
|
||||
case true => NewStyle.function.systemView(targetViewId, callContext)
|
||||
case false => NewStyle.function.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
|
||||
}
|
||||
revoked <- isValidSystemViewId(targetViewId.value) match {
|
||||
case true => NewStyle.function.revokeAccessToSystemView(bankId, accountId, view, user, callContext)
|
||||
case false => NewStyle.function.revokeAccessToCustomView(view, user, callContext)
|
||||
}
|
||||
} yield {
|
||||
val viewJson = JSONFactory300.createViewJSON(addedView)
|
||||
(viewJson, HttpCode.`201`(callContext))
|
||||
(RevokedJsonV400(revoked), HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createUserWithAccountAccessById,
|
||||
implementedInApiVersion,
|
||||
nameOf(createUserWithAccountAccessById),
|
||||
"POST",
|
||||
"/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/user-account-access",
|
||||
"Create (DAuth) User with Account Access",
|
||||
s"""This endpoint is used as part of the DAuth solution to grant access to account and transaction data to a smart contract on the blockchain.
|
||||
|
|
||||
|Put the smart contract address in username
|
||||
|
|
||||
|For provider use "dauth"
|
||||
|
|
||||
|This endpoint will create the (DAuth) User with username and provider if the User does not already exist.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)} and the logged in user needs to be account holder.
|
||||
|
|
||||
|For information about DAuth see below:
|
||||
|
|
||||
|${Glossary.getGlossaryItem("DAuth")}
|
||||
|
|
||||
|""",
|
||||
postCreateUserAccountAccessJsonV400,
|
||||
List(viewJsonV300),
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
$BankNotFound,
|
||||
$BankAccountNotFound,
|
||||
$UserNoPermissionAccessView,
|
||||
UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount,
|
||||
UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount,
|
||||
InvalidJsonFormat,
|
||||
SystemViewNotFound,
|
||||
ViewNotFound,
|
||||
CannotGrantAccountAccess,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagAccountAccess, apiTagView, apiTagAccount, apiTagUser, apiTagOwnerRequired, apiTagDAuth))
|
||||
|
||||
lazy val createUserWithAccountAccessById: OBPEndpoint = {
|
||||
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" ::ViewId(viewId) :: "user-account-access" :: Nil JsonPost json -> _ => {
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
val failMsg = s"$InvalidJsonFormat The Json body should be the $PostCreateUserAccountAccessJsonV510 "
|
||||
for {
|
||||
(Full(u), callContext) <- SS.user
|
||||
postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
|
||||
json.extract[PostCreateUserAccountAccessJsonV510]
|
||||
}
|
||||
//provider must start with dauth., can not create other provider users.
|
||||
_ <- Helper.booleanToFuture(s"$InvalidUserProvider The user.provider must be start with 'dauth.'", cc = Some(cc)) {
|
||||
postJson.provider.startsWith("dauth.")
|
||||
}
|
||||
targetViewId = ViewId(postJson.view_id)
|
||||
msg = getUserLacksGrantPermissionErrorMessage(viewId, targetViewId)
|
||||
|
||||
_ <- Helper.booleanToFuture(msg, 403, cc = Some(cc)) {
|
||||
APIUtil.canGrantAccessToView(BankIdAccountIdViewId(bankId, accountId, viewId) ,targetViewId, u, callContext)
|
||||
}
|
||||
(targetUser, callContext) <- NewStyle.function.getOrCreateResourceUser(postJson.provider, postJson.username, cc.callContext)
|
||||
view <- isValidSystemViewId(targetViewId.value) match {
|
||||
case true => NewStyle.function.systemView(targetViewId, callContext)
|
||||
case false => NewStyle.function.customView(targetViewId, BankIdAccountId(bankId, accountId), callContext)
|
||||
}
|
||||
addedView <- isValidSystemViewId(targetViewId.value) match {
|
||||
case true => NewStyle.function.grantAccessToSystemView(bankId, accountId, view, targetUser, callContext)
|
||||
case false => NewStyle.function.grantAccessToCustomView(view, targetUser, callContext)
|
||||
}
|
||||
} yield {
|
||||
val viewsJson = JSONFactory300.createViewJSON(addedView)
|
||||
(viewsJson, HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ import code.api.v1_4_0.JSONFactory1_4_0.{LocationJsonV140, MetaJsonV140, transfo
|
||||
import code.api.v2_1_0.ResourceUserJSON
|
||||
import code.api.v3_0_0.JSONFactory300.{createLocationJson, createMetaJson, transformToAddressFromV300}
|
||||
import code.api.v3_0_0.{AccountIdJson, AccountsIdsJsonV300, AddressJsonV300, OpeningTimesV300}
|
||||
import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400}
|
||||
import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400, PostViewJsonV400}
|
||||
import code.atmattribute.AtmAttribute
|
||||
import code.atms.Atms.Atm
|
||||
import code.users.{UserAttribute, Users}
|
||||
@ -307,6 +307,10 @@ case class ConsumerJsonV510(consumer_id: String,
|
||||
created: Date
|
||||
)
|
||||
|
||||
case class PostCreateUserAccountAccessJsonV510(username: String, provider:String, view_id:String)
|
||||
|
||||
case class PostAccountAccessJsonV510(user_id: String, view_id: String)
|
||||
|
||||
object JSONFactory510 extends CustomJsonFormats {
|
||||
|
||||
def createCustomersIds(customers : List[Customer]): CustomersIdsJsonV510 =
|
||||
|
||||
@ -72,18 +72,22 @@ object OBPAPI5_1_0 extends OBPRestHelper
|
||||
// e.g getEndpoints(Implementations5_0_0) -- List(Implementations5_0_0.genericEndpoint, Implementations5_0_0.root)
|
||||
lazy val endpointsOf5_1_0 = getEndpoints(Implementations5_1_0)
|
||||
|
||||
lazy val bugEndpoints = // these endpoints miss Provider parameter in the URL, we introduce new ones in V510.
|
||||
nameOf(Implementations3_0_0.getUserByUsername) ::
|
||||
lazy val excludeEndpoints =
|
||||
nameOf(Implementations3_0_0.getUserByUsername) :: // following 4 endpoints miss Provider parameter in the URL, we introduce new ones in V510.
|
||||
nameOf(Implementations3_1_0.getBadLoginStatus) ::
|
||||
nameOf(Implementations3_1_0.unlockUser) ::
|
||||
nameOf(Implementations4_0_0.lockUser) ::
|
||||
nameOf(Implementations4_0_0.createUserWithAccountAccess) :: // following 3 endpoints miss ViewId parameter in the URL, we introduce new ones in V510.
|
||||
nameOf(Implementations4_0_0.grantUserAccessToView) ::
|
||||
nameOf(Implementations4_0_0.revokeUserAccessToView) ::
|
||||
nameOf(Implementations4_0_0.revokeGrantUserAccessToViews) ::// this endpoint is forbidden in V510, we do not support multi views in one endpoint from V510.
|
||||
Nil
|
||||
|
||||
// if old version ResourceDoc objects have the same name endpoint with new version, omit old version ResourceDoc.
|
||||
def allResourceDocs = collectResourceDocs(
|
||||
OBPAPI5_0_0.allResourceDocs,
|
||||
Implementations5_1_0.resourceDocs
|
||||
).filterNot(it => it.partialFunctionName.matches(bugEndpoints.mkString("|")))
|
||||
).filterNot(it => it.partialFunctionName.matches(excludeEndpoints.mkString("|")))
|
||||
|
||||
// all endpoints
|
||||
private val endpoints: List[OBPEndpoint] = OBPAPI5_0_0.routes ++ endpointsOf5_1_0
|
||||
|
||||
@ -209,7 +209,7 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable
|
||||
customerList.toSet
|
||||
}
|
||||
|
||||
private def viewNotAllowed(view : View ) = Failure(s"${UserNoPermissionAccessView} Current VIEW_ID (${view.viewId.value})")
|
||||
private def viewNotAllowed(view : View) = Failure(s"${UserNoPermissionAccessView} Current ViewId is ${view.viewId.value}")
|
||||
|
||||
/**
|
||||
* @param user the user that wants to grant another user access to a view on this account
|
||||
|
||||
@ -47,7 +47,7 @@ object MapperViews extends Views with MdcLoggable {
|
||||
}
|
||||
|
||||
private def getViewFromAccountAccess(accountAccess: AccountAccess) = {
|
||||
if (checkSystemViewIdOrName(accountAccess.view_id.get)) {
|
||||
if (isValidSystemViewId(accountAccess.view_id.get)) {
|
||||
ViewDefinition.findSystemView(accountAccess.view_id.get)
|
||||
.map(v => v.bank_id(accountAccess.bank_id.get).account_id(accountAccess.account_id.get)) // in case system view do not contains the bankId, and accountId.
|
||||
} else {
|
||||
@ -381,7 +381,7 @@ object MapperViews extends Views with MdcLoggable {
|
||||
def createSystemView(view: CreateViewJson) : Future[Box[View]] = Future {
|
||||
if(view.is_public) {
|
||||
Failure(SystemViewCannotBePublicError)
|
||||
}else if (!checkSystemViewIdOrName(view.name)) {
|
||||
}else if (!isValidSystemViewName(view.name)) {
|
||||
Failure(InvalidSystemViewFormat+s"Current view_name (${view.name})")
|
||||
} else {
|
||||
view.name.contentEquals("") match {
|
||||
@ -415,7 +415,7 @@ object MapperViews extends Views with MdcLoggable {
|
||||
* */
|
||||
def createCustomView(bankAccountId: BankIdAccountId, view: CreateViewJson): Box[View] = {
|
||||
|
||||
if(!checkCustomViewIdOrName(view.name)) {
|
||||
if(!isValidCustomViewName(view.name)) {
|
||||
return Failure(InvalidCustomViewFormat)
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
package code.views.system
|
||||
|
||||
import code.api.util.APIUtil.{checkCustomViewIdOrName, checkSystemViewIdOrName}
|
||||
import code.api.util.APIUtil.{isValidCustomViewId, isValidCustomViewName, isValidSystemViewId}
|
||||
import code.api.util.ErrorMessages.{CreateSystemViewError, InvalidCustomViewFormat, InvalidSystemViewFormat}
|
||||
import code.util.{AccountIdString, UUIDString}
|
||||
import com.openbankproject.commons.model._
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.common.Box.tryo
|
||||
import net.liftweb.mapper.{MappedBoolean, _}
|
||||
import net.liftweb.mapper._
|
||||
|
||||
import scala.collection.immutable.List
|
||||
|
||||
@ -51,12 +51,17 @@ class ViewDefinition extends View with LongKeyedMapper[ViewDefinition] with Many
|
||||
object hideOtherAccountMetadataIfAlias_ extends MappedBoolean(this){
|
||||
override def defaultValue = false
|
||||
}
|
||||
|
||||
//This is the system views list, custom views please check `canGrantAccessToCustomViews_` field
|
||||
object canGrantAccessToViews_ extends MappedText(this){
|
||||
override def defaultValue = ""
|
||||
}
|
||||
|
||||
//This is the system views list.custom views please check `canRevokeAccessToCustomViews_` field
|
||||
object canRevokeAccessToViews_ extends MappedText(this){
|
||||
override def defaultValue = ""
|
||||
}
|
||||
|
||||
object canRevokeAccessToCustomViews_ extends MappedBoolean(this){
|
||||
override def defaultValue = false
|
||||
}
|
||||
@ -599,10 +604,10 @@ object ViewDefinition extends ViewDefinition with LongKeyedMetaMapper[ViewDefini
|
||||
t.composite_unique_key(compositeUniqueKey)
|
||||
}
|
||||
|
||||
if (t.isSystem && !checkSystemViewIdOrName(t.view_id.get)) {
|
||||
if (t.isSystem && !isValidSystemViewId(t.view_id.get)) {
|
||||
throw new RuntimeException(InvalidSystemViewFormat+s"Current view_id (${t.view_id.get})")
|
||||
}
|
||||
if (!t.isSystem && !checkCustomViewIdOrName(t.view_id.get)) {
|
||||
if (!t.isSystem && !isValidCustomViewId(t.view_id.get)) {
|
||||
throw new RuntimeException(InvalidCustomViewFormat+s"Current view_id (${t.view_id.get})")
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ import _root_.net.liftweb.json.Serialization.write
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.util.APIUtil
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.APIUtil.checkSystemViewIdOrName
|
||||
import code.api.util.APIUtil.isValidSystemViewId
|
||||
import code.bankconnectors.Connector
|
||||
import code.setup.{APIResponse, DefaultUsers, PrivateUser2AccountsAndSetUpWithTestData, ServerSetupWithTestData}
|
||||
import code.views.Views
|
||||
@ -165,7 +165,7 @@ class API1_2_1Test extends ServerSetupWithTestData with DefaultUsers with Privat
|
||||
val reply = makeGetRequest(request)
|
||||
val possibleViewsPermalinks = reply.body.extract[ViewsJSONV121].views
|
||||
.filterNot(_.is_public==true)
|
||||
.filterNot(view=> checkSystemViewIdOrName(view.id))
|
||||
.filterNot(view=> isValidSystemViewId(view.id))
|
||||
val randomPosition = nextInt(possibleViewsPermalinks.size)
|
||||
possibleViewsPermalinks(randomPosition).id
|
||||
}
|
||||
@ -6505,7 +6505,7 @@ class API1_2_1Test extends ServerSetupWithTestData with DefaultUsers with Privat
|
||||
Then("we should get a 403 code")
|
||||
reply.code should equal (403)
|
||||
And("we should get an error message")
|
||||
reply.body.extract[ErrorMessage].message should equal (UserNoPermissionAccessView)
|
||||
reply.body.extract[ErrorMessage].message contains (UserNoPermissionAccessView) shouldBe (true)
|
||||
}
|
||||
|
||||
scenario("we will not get get the other bank account of a random transaction because the transaction does not exist", API1_2_1, GetTransactionAccount){
|
||||
|
||||
@ -5,10 +5,10 @@ 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.util.ErrorMessages.{UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount, UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount, UserLacksPermissionCanGrantAccessToViewForTargetAccount, UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount, UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount, UserLacksPermissionCanRevokeAccessToViewForTargetAccount, 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.v4_0_0.RevokedJsonV400
|
||||
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
|
||||
import code.entitlement.Entitlement
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
@ -28,13 +28,16 @@ class AccountAccessTest extends V510ServerSetup {
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.grantUserAccessToViewById))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.revokeUserAccessToViewById))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.createUserWithAccountAccessById))
|
||||
|
||||
|
||||
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 postAccountAccessJson = PostAccountAccessJsonV510(resourceUser2.userId, "_test_view")
|
||||
lazy val postCreateUserAccountAccessJsonV510 = PostCreateUserAccountAccessJsonV510(resourceUser2.userId, "dauth."+resourceUser2.provider, "_test_view")
|
||||
lazy val postBodyViewJson = createViewJsonV300.toCreateViewJson
|
||||
|
||||
def createAnAccount(bankId: String, user: Option[(Consumer,Token)]): CreateAccountResponseJsonV310 = {
|
||||
@ -55,7 +58,7 @@ class AccountAccessTest extends V510ServerSetup {
|
||||
|
||||
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 request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / bankAccount.id /"views" / ownerView /"account-access" / "grant").POST
|
||||
val response510 = makePostRequest(request510, write(postAccountAccessJson))
|
||||
Then("We should get a 401")
|
||||
response510.code should equal(401)
|
||||
@ -71,13 +74,13 @@ class AccountAccessTest extends V510ServerSetup {
|
||||
}
|
||||
|
||||
val view = createViewForAnAccount(bankId, account.account_id)
|
||||
val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(view.id, view.is_system))
|
||||
val postJson = PostAccountAccessJsonV510(resourceUser2.userId, view.id)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / ownerView / "account-access" / "grant").POST <@ (user1)
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ 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)
|
||||
Then("We should get a 403 and check the response body")
|
||||
response.code should equal(403)
|
||||
response.body.toString.contains(UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount) should be (true)
|
||||
}
|
||||
|
||||
scenario("We will call the endpoint with user credentials and managerCustomView view, but try to grant system view access", VersionOfApi, ApiEndpoint1) {
|
||||
@ -88,13 +91,13 @@ class AccountAccessTest extends V510ServerSetup {
|
||||
Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement)
|
||||
}
|
||||
|
||||
val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(SYSTEM_AUDITOR_VIEW_ID, true))
|
||||
val postJson = PostAccountAccessJsonV510(resourceUser2.userId, SYSTEM_AUDITOR_VIEW_ID)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / managerCustomView / "account-access" / "grant").POST <@ (user1)
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ 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)
|
||||
Then("We should get a 403 and check the response body")
|
||||
response.code should equal(403)
|
||||
response.body.toString.contains(UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount) should be (true)
|
||||
}
|
||||
|
||||
scenario("We will call the endpoint with user credentials and system view permission", VersionOfApi, ApiEndpoint1) {
|
||||
@ -105,9 +108,9 @@ class AccountAccessTest extends V510ServerSetup {
|
||||
Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement)
|
||||
}
|
||||
|
||||
val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(SYSTEM_AUDITOR_VIEW_ID, true))
|
||||
val postJson = PostAccountAccessJsonV510(resourceUser2.userId, SYSTEM_AUDITOR_VIEW_ID)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / ownerView / "account-access" / "grant").POST <@ (user1)
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ 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)
|
||||
@ -123,9 +126,190 @@ class AccountAccessTest extends V510ServerSetup {
|
||||
}
|
||||
|
||||
val view = createViewForAnAccount(bankId, account.account_id)
|
||||
val postJson = PostAccountAccessJsonV400(resourceUser2.userId, PostViewJsonV400(view.id, view.is_system))
|
||||
val postJson = PostAccountAccessJsonV510(resourceUser2.userId, view.id)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id / managerCustomView / "account-access" / "grant").POST <@ (user1)
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ 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]
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint2 Authorized access") {
|
||||
|
||||
scenario("We will call the endpoint without user credentials", ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v4.0.0")
|
||||
val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / bankAccount.id /"views" / ownerView /"account-access" / "revoke").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 = PostAccountAccessJsonV510(resourceUser2.userId, view.id)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ ownerView / "account-access" / "revoke").POST <@ (user1)
|
||||
val response = makePostRequest(request, write(postJson))
|
||||
Then("We should get a 403 and check the response body")
|
||||
response.code should equal(403)
|
||||
response.body.toString.contains(UserLacksPermissionCanRevokeAccessToCustomViewForTargetAccount) should be (true)
|
||||
}
|
||||
|
||||
scenario("We will call the endpoint with user credentials and managerCustomView view, but try to revoke 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 = PostAccountAccessJsonV510(resourceUser2.userId, SYSTEM_AUDITOR_VIEW_ID)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ managerCustomView / "account-access" / "revoke").POST <@ (user1)
|
||||
val response = makePostRequest(request, write(postJson))
|
||||
Then("We should get a 403 and check the response body")
|
||||
response.code should equal(403)
|
||||
response.body.toString.contains(UserLacksPermissionCanRevokeAccessToSystemViewForTargetAccount) should be (true)
|
||||
}
|
||||
|
||||
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 = PostAccountAccessJsonV510(resourceUser2.userId, SYSTEM_AUDITOR_VIEW_ID)
|
||||
|
||||
When("We 1st grant the account access the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ ownerView / "account-access" / "grant").POST <@ (user1)
|
||||
val responseGrant = makePostRequest(request, write(postJson))
|
||||
Then("We should get a 201 and check the response body")
|
||||
responseGrant.code should equal(201)
|
||||
responseGrant.body.extract[ViewJsonV300]
|
||||
|
||||
When("We send the Revoke request")
|
||||
val requestRevoke = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ ownerView / "account-access" / "revoke").POST <@ (user1)
|
||||
val response = makePostRequest(requestRevoke, write(postJson))
|
||||
Then("We should get a 201 and check the response body")
|
||||
response.code should equal(201)
|
||||
response.body.extract[RevokedJsonV400].revoked should be (true)
|
||||
}
|
||||
|
||||
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 = PostAccountAccessJsonV510(resourceUser2.userId, view.id)
|
||||
val requestGrant = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ managerCustomView / "account-access" / "grant").POST <@ (user1)
|
||||
|
||||
When("We 1st grant the account access the request")
|
||||
val responseGrant = makePostRequest(requestGrant, write(postJson))
|
||||
Then("We should get a 201 and check the response body")
|
||||
responseGrant.code should equal(201)
|
||||
responseGrant.body.extract[ViewJsonV300]
|
||||
|
||||
When("We send the Revoke request")
|
||||
val requestRevoke = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ managerCustomView / "account-access" / "revoke").POST <@ (user1)
|
||||
val response = makePostRequest(requestRevoke, write(postJson))
|
||||
Then("We should get a 201 and check the response body")
|
||||
response.code should equal(201)
|
||||
response.body.extract[RevokedJsonV400].revoked should be (true)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint3 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 /"views" / ownerView /"user-account-access").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 = PostCreateUserAccountAccessJsonV510(resourceUser2.userId, "dauth."+resourceUser2.provider, view.id)
|
||||
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ ownerView / "user-account-access").POST <@ (user1)
|
||||
val response = makePostRequest(request, write(postJson))
|
||||
Then("We should get a 403 and check the response body")
|
||||
response.code should equal(403)
|
||||
response.body.toString.contains(UserLacksPermissionCanGrantAccessToCustomViewForTargetAccount) should be (true)
|
||||
}
|
||||
|
||||
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 = PostCreateUserAccountAccessJsonV510(resourceUser2.userId, "dauth."+resourceUser2.provider, ownerView)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ managerCustomView / "user-account-access").POST <@ (user1)
|
||||
val response = makePostRequest(request, write(postJson))
|
||||
Then("We should get a 403 and check the response body")
|
||||
response.code should equal(403)
|
||||
response.body.toString.contains(UserLacksPermissionCanGrantAccessToSystemViewForTargetAccount) should be (true)
|
||||
}
|
||||
|
||||
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 = PostCreateUserAccountAccessJsonV510(resourceUser2.userId,"dauth."+resourceUser2.provider, SYSTEM_AUDITOR_VIEW_ID)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ ownerView / "user-account-access").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 = PostCreateUserAccountAccessJsonV510(resourceUser2.userId,"dauth."+resourceUser2.provider, view.id)
|
||||
When("We send the request")
|
||||
val request = (v5_1_0_Request / "banks" / bankId / "accounts" / account.account_id /"views"/ managerCustomView / "user-account-access").POST <@ (user1)
|
||||
val response = makePostRequest(request, write(postJson))
|
||||
Then("We should get a 201 and check the response body")
|
||||
response.code should equal(201)
|
||||
|
||||
@ -3,7 +3,7 @@ package code.setup
|
||||
import bootstrap.liftweb.ToSchemify
|
||||
import code.accountholders.AccountHolders
|
||||
import code.api.Constant.{CUSTOM_PUBLIC_VIEW_ID, SYSTEM_OWNER_VIEW_ID}
|
||||
import code.api.util.APIUtil.checkCustomViewIdOrName
|
||||
import code.api.util.APIUtil.isValidCustomViewName
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.model._
|
||||
import code.model.dataAccess._
|
||||
@ -40,7 +40,7 @@ trait TestConnectorSetupWithStandardPermissions extends TestConnectorSetup {
|
||||
val viewId = MapperViews.createViewIdByName(viewName)
|
||||
val description = randomString(40)
|
||||
|
||||
if (!checkCustomViewIdOrName(viewName)) {
|
||||
if (!isValidCustomViewName(viewName)) {
|
||||
throw new RuntimeException(InvalidCustomViewFormat)
|
||||
}
|
||||
|
||||
|
||||
@ -250,10 +250,11 @@ trait View {
|
||||
def usePrivateAliasIfOneExists: Boolean
|
||||
|
||||
def hideOtherAccountMetadataIfAlias: Boolean
|
||||
//TODO, in progress, we only make the system view work, the custom views are VIP.
|
||||
|
||||
def canGrantAccessToViews : Option[List[String]] = None
|
||||
def canGrantAccessToCustomViews : Boolean // if this true, we can grant custom views, if it is false, no one can grant custom views.
|
||||
def canRevokeAccessToViews : Option[List[String]] = None
|
||||
|
||||
def canGrantAccessToCustomViews : Boolean // if this true, we can grant custom views, if it is false, no one can grant custom views.
|
||||
def canRevokeAccessToCustomViews : Boolean // if this true, we can revoke custom views,if it is false, no one can revoke custom views.
|
||||
|
||||
//reading access
|
||||
|
||||
Loading…
Reference in New Issue
Block a user