Merge pull request #2229 from hongwei1/develop

feature/support the IMPLICIT SCA method
This commit is contained in:
Simon Redfern 2023-06-13 15:31:35 +02:00 committed by GitHub
commit a22ef5de07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 601 additions and 221 deletions

View File

@ -4189,6 +4189,15 @@ object SwaggerDefinitionsJSON {
valid_from = Some(new Date()),
time_to_live = Some(3600)
)
val postConsentImplicitJsonV310 = PostConsentImplicitJsonV310(
everything = false,
views = List(PostConsentViewJsonV310(bankIdExample.value, accountIdExample.value, viewIdExample.value)),
entitlements = List(PostConsentEntitlementJsonV310(bankIdExample.value, "CanGetCustomer")),
consumer_id = Some(consumerIdExample.value),
valid_from = Some(new Date()),
time_to_live = Some(3600)
)
val postConsentRequestJsonV310 = postConsentPhoneJsonV310.copy(consumer_id = None)
val consentsJsonV310 = ConsentsJsonV310(List(consentJsonV310))

View File

@ -444,6 +444,7 @@ object ErrorMessages {
val GetCustomerAccountLinksError = "OBP-30226: Could not get the customer account links."
val UpdateCustomerAccountLinkError = "OBP-30227: Could not update the customer account link."
val DeleteCustomerAccountLinkError = "OBP-30228: Could not delete the customer account link."
val GetConsentImplicitSCAError = "OBP-30229: Could not get the consent implicit SCA."
val CreateSystemViewError = "OBP-30250: Could not create the system view"
val DeleteSystemViewError = "OBP-30251: Could not delete the system view"
@ -489,7 +490,7 @@ object ErrorMessages {
val ConsentCheckExpiredIssue = "OBP-35006: Cannot check is Consent-Id expired. "
val ConsentDisabled = "OBP-35007: Consents are not allowed at this instance. "
val ConsentHeaderNotFound = "OBP-35008: Cannot get Consent-Id. "
val ConsentAllowedScaMethods = "OBP-35009: Only SMS and EMAIL are supported as SCA methods. "
val ConsentAllowedScaMethods = "OBP-35009: Only SMS, EMAIL and IMPLICIT are supported as SCA methods. "
val SmsServerNotResponding = "OBP-35010: SMS server is not working or SMS server can not send the message to the phone number:"
val AuthorizationNotFound = "OBP-35011: Resource identification of the related Consent authorisation sub-resource not found by AUTHORIZATION_ID. "
val ConsentAlreadyRevoked = "OBP-35012: Consent is already revoked. "
@ -514,6 +515,7 @@ object ErrorMessages {
val ConsumerKeyIsToLong = "OBP-35031: The Consumer Key max length <= 512"
val ConsentHeaderValueInvalid = "OBP-35032: The Consent's Request Header value is not formatted as UUID or JWT."
val RolesForbiddenInConsent = s"OBP-35033: Consents cannot contain the following Roles: ${canCreateEntitlementAtOneBank} and ${canCreateEntitlementAtAnyBank}."
val UserAuthContextUpdateRequestAllowedScaMethods = "OBP-35034: Only SMS and EMAIL are supported as SCA methods. "
//Authorisations
val AuthorisationNotFound = "OBP-36001: Authorisation not found. Please specify valid values for PAYMENT_ID and AUTHORISATION_ID. "

View File

@ -3942,6 +3942,11 @@ object NewStyle extends MdcLoggable{
i => (unboxFullOrFail(i._1, callContext, UpdateCustomerAccountLinkError), i._2)
}
def getConsentImplicitSCA(user: User, callContext: Option[CallContext]): OBPReturnType[ConsentImplicitSCAT] =
Connector.connector.vend.getConsentImplicitSCA(user: User, callContext: Option[CallContext]) map {
i => (unboxFullOrFail(i._1, callContext, GetConsentImplicitSCAError), i._2)
}
def getAtmsByBankId(bankId: BankId, offset: Box[String], limit: Box[String], callContext: Option[CallContext]): OBPReturnType[List[AtmT]] =
Connector.connector.vend.getAtms(bankId, callContext) map {
case Empty =>

View File

@ -3235,8 +3235,9 @@ trait APIMethods310 {
|
|The Consent is created in an ${ConsentStatus.INITIATED} state.
|
|A One Time Password (OTP) (AKA security challenge) is sent Out of band (OOB) to the User via the transport defined in SCA_METHOD
|SCA_METHOD is typically "SMS" or "EMAIL". "EMAIL" is used for testing purposes.
|A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
|SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
|Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
|
|When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
|
@ -3250,7 +3251,7 @@ trait APIMethods310 {
| "views": [],
| "entitlements": [],
| "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
| "email": "eveline@example.com"
| "phone_number": "+49 170 1234567"
|}
|
|Please note that consumer_id is optional field
@ -3259,7 +3260,7 @@ trait APIMethods310 {
| "everything": true,
| "views": [],
| "entitlements": [],
| "email": "eveline@example.com"
| "phone_number": "+49 170 1234567"
|}
|
|Please note if everything=false you need to explicitly specify views and entitlements
@ -3280,7 +3281,7 @@ trait APIMethods310 {
| }
| ],
| "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
| "email": "eveline@example.com"
| "phone_number": "+49 170 1234567"
|}
|
|""",
@ -3314,7 +3315,8 @@ trait APIMethods310 {
|The Consent is created in an ${ConsentStatus.INITIATED} state.
|
|A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
|SCA_METHOD is typically "SMS" or "EMAIL". "EMAIL" is used for testing purposes.
|SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
|Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
|
|When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
|
@ -3380,8 +3382,87 @@ trait APIMethods310 {
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
resourceDocs += ResourceDoc(
createConsentImplicit,
implementedInApiVersion,
nameOf(createConsentImplicit),
"POST",
"/banks/BANK_ID/my/consents/IMPLICIT",
"Create Consent (IMPLICIT)",
s"""
|
|This endpoint starts the process of creating a Consent.
|
|The Consent is created in an ${ConsentStatus.INITIATED} state.
|
|A One Time Password (OTP) (AKA security challenge) is sent Out of Band (OOB) to the User via the transport defined in SCA_METHOD
|SCA_METHOD is typically "SMS","EMAIL" or "IMPLICIT". "EMAIL" is used for testing purposes. OBP mapped mode "IMPLICIT" is "EMAIL".
|Other mode, bank can decide it in the connector method 'getConsentImplicitSCA'.
|
|When the Consent is created, OBP (or a backend system) stores the challenge so it can be checked later against the value supplied by the User with the Answer Consent Challenge endpoint.
|
|$generalObpConsentText
|
|${authenticationRequiredMessage(true)}
|
|Example 1:
|{
| "everything": true,
| "views": [],
| "entitlements": [],
| "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
|}
|
|Please note that consumer_id is optional field
|Example 2:
|{
| "everything": true,
| "views": [],
| "entitlements": [],
|}
|
|Please note if everything=false you need to explicitly specify views and entitlements
|Example 3:
|{
| "everything": false,
| "views": [
| {
| "bank_id": "GENODEM1GLS",
| "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
| "view_id": "owner"
| }
| ],
| "entitlements": [
| {
| "bank_id": "GENODEM1GLS",
| "role_name": "CanGetCustomer"
| }
| ],
| "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
|}
|
|""",
postConsentImplicitJsonV310,
consentJsonV310,
List(
UserNotLoggedIn,
BankNotFound,
InvalidJsonFormat,
ConsentAllowedScaMethods,
RolesAllowedInConsent,
ViewsAllowedInConsent,
ConsumerNotFoundByConsumerId,
ConsumerIsDisabled,
MissingPropsValueAtThisInstance,
SmsServerNotResponding,
InvalidConnectorResponse,
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
lazy val createConsentEmail = createConsent
lazy val createConsentSms = createConsent
lazy val createConsentImplicit = createConsent
lazy val createConsent : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "my" :: "consents" :: scaMethod :: Nil JsonPost json -> _ => {
@ -3390,7 +3471,7 @@ trait APIMethods310 {
(Full(user), callContext) <- authenticatedAccess(cc)
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString(), StrongCustomerAuthentication.IMPLICIT.toString()).exists(_ == scaMethod)
}
failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
consentJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
@ -3485,6 +3566,32 @@ trait APIMethods310 {
callContext
)
} yield Future{status}
case v if v == StrongCustomerAuthentication.IMPLICIT.toString => // Not implemented
for {
(consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext)
status <- consentImplicitSCA.scaMethod match {
case v if v == StrongCustomerAuthentication.EMAIL => // Send the email
Connector.connector.vend.sendCustomerNotification (
StrongCustomerAuthentication.EMAIL,
consentImplicitSCA.recipient,
Some ("OBP Consent Challenge"),
challengeText,
callContext
)
case v if v == StrongCustomerAuthentication.SMS => // Not implemented
Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.SMS,
consentImplicitSCA.recipient,
None,
challengeText,
callContext
)
case _ => Future {
"Success"
}
}} yield {
status
}
case _ =>Future{"Success"}
}
} yield {
@ -3671,7 +3778,7 @@ trait APIMethods310 {
checkScope(bankId.value, getConsumerPrimaryKey(callContext), ApiRole.canCreateUserAuthContextUpdate)
}
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
_ <- Helper.booleanToFuture(UserAuthContextUpdateRequestAllowedScaMethods, cc=callContext){
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
}
failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson "

View File

@ -556,6 +556,15 @@ case class PostConsentPhoneJsonV310(
time_to_live: Option[Long]
) extends PostConsentCommonBody
case class PostConsentImplicitJsonV310(
everything: Boolean,
views: List[PostConsentViewJsonV310],
entitlements: List[PostConsentEntitlementJsonV310],
consumer_id: Option[String],
valid_from: Option[Date],
time_to_live: Option[Long]
) extends PostConsentCommonBody
case class ConsentJsonV310(consent_id: String, jwt: String, status: String)
case class ConsentsJsonV310(consents: List[ConsentJsonV310])

View File

@ -512,7 +512,7 @@ trait APIMethods500 {
_ <- Helper.booleanToFuture(failMsg = ConsumerHasMissingRoles + CanCreateUserAuthContextUpdate, cc=callContext) {
checkScope(bankId.value, getConsumerPrimaryKey(callContext), ApiRole.canCreateUserAuthContextUpdate)
}
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
_ <- Helper.booleanToFuture(UserAuthContextUpdateRequestAllowedScaMethods, cc=callContext){
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
}
failMsg = s"$InvalidJsonFormat The Json body should be the $PostUserAuthContextJson "
@ -798,12 +798,83 @@ trait APIMethods500 {
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
staticResourceDocs += ResourceDoc(
createConsentByConsentRequestIdImplicit,
implementedInApiVersion,
nameOf(createConsentByConsentRequestIdImplicit),
"POST",
"/consumer/consent-requests/CONSENT_REQUEST_ID/IMPLICIT/consents",
"Create Consent By CONSENT_REQUEST_ID (IMPLICIT)",
s"""
|
|This endpoint continues the process of creating a Consent. It starts the SCA flow which changes the status of the consent from INITIATED to ACCEPTED or REJECTED.
|Please note that the Consent cannot elevate the privileges logged in user already have.
|
|""",
EmptyBody,
consentJsonV500,
List(
UserNotLoggedIn,
$BankNotFound,
InvalidJsonFormat,
ConsentRequestIsInvalid,
ConsentAllowedScaMethods,
RolesAllowedInConsent,
ViewsAllowedInConsent,
ConsumerNotFoundByConsumerId,
ConsumerIsDisabled,
MissingPropsValueAtThisInstance,
SmsServerNotResponding,
InvalidConnectorResponse,
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: Nil)
lazy val createConsentByConsentRequestIdEmail = createConsentByConsentRequestId
lazy val createConsentByConsentRequestIdSms = createConsentByConsentRequestId
lazy val createConsentByConsentRequestIdImplicit = createConsentByConsentRequestId
lazy val createConsentByConsentRequestId : OBPEndpoint = {
case "consumer" :: "consent-requests":: consentRequestId :: scaMethod :: "consents" :: Nil JsonPost _ -> _ => {
def sendEmailNotification(callContext: Option[CallContext], consentRequestJson: PostConsentRequestJsonV500, challengeText: String) = {
for {
failMsg <- Future {
s"$InvalidJsonFormat The Json body must contain the field email"
}
consentScaEmail <- NewStyle.function.tryons(failMsg, 400, callContext) {
consentRequestJson.email.head
}
(Full(status), callContext) <- Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.EMAIL,
consentScaEmail,
Some("OBP Consent Challenge"),
challengeText,
callContext
)
} yield {
status
}
}
def sendSmsNotification(callContext: Option[CallContext], consentRequestJson: PostConsentRequestJsonV500, challengeText: String) = {
for {
failMsg <- Future {
s"$InvalidJsonFormat The Json body must contain the field phone_number"
}
consentScaPhoneNumber <- NewStyle.function.tryons(failMsg, 400, callContext) {
consentRequestJson.phone_number.head
}
(Full(status), callContext) <- Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.SMS,
consentScaPhoneNumber,
None,
challengeText,
callContext
)
} yield {
status
}
}
cc =>
for {
(Full(user), callContext) <- authenticatedAccess(cc)
@ -816,7 +887,7 @@ trait APIMethods500 {
Consents.consentProvider.vend.getConsentByConsentRequestId(consentRequestId).isEmpty
}
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString(), StrongCustomerAuthentication.IMPLICIT.toString()).exists(_ == scaMethod)
}
failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
consentRequestJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
@ -912,35 +983,23 @@ trait APIMethods500 {
challengeText = s"Your consent challenge : ${challengeAnswer}, Application: $applicationText"
_ <- scaMethod match {
case v if v == StrongCustomerAuthentication.EMAIL.toString => // Send the email
for{
failMsg <- Future {s"$InvalidJsonFormat The Json body must contain the field email"}
consentScaEmail <- NewStyle.function.tryons(failMsg, 400, callContext) {
consentRequestJson.email.head
}
(Full(status), callContext) <- Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.EMAIL,
consentScaEmail,
Some("OBP Consent Challenge"),
challengeText,
callContext
)
} yield Future{status}
sendEmailNotification(callContext, consentRequestJson, challengeText)
case v if v == StrongCustomerAuthentication.SMS.toString => // Not implemented
sendSmsNotification(callContext, consentRequestJson, challengeText)
case v if v == StrongCustomerAuthentication.IMPLICIT.toString =>
for {
failMsg <- Future {
s"$InvalidJsonFormat The Json body must contain the field phone_number"
}
consentScaPhoneNumber <- NewStyle.function.tryons(failMsg, 400, callContext) {
consentRequestJson.phone_number.head
}
(Full(status), callContext) <- Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.SMS,
consentScaPhoneNumber,
None,
challengeText,
callContext
)
} yield Future{status}
(consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext)
status <- consentImplicitSCA.scaMethod match {
case v if v == StrongCustomerAuthentication.EMAIL => // Send the email
sendEmailNotification(callContext, consentRequestJson.copy(email=Some(consentImplicitSCA.recipient)), challengeText)
case v if v == StrongCustomerAuthentication.SMS => // Not implemented
sendSmsNotification(callContext, consentRequestJson.copy(phone_number=Some(consentImplicitSCA.recipient)), challengeText)
case _ => Future {
"Success"
}
}} yield {
status
}
case _ =>Future{"Success"}
}
} yield {

View File

@ -2683,4 +2683,6 @@ trait Connector extends MdcLoggable {
def updateCustomerAccountLinkById(customerAccountLinkId: String, relationshipType: String, callContext: Option[CallContext]): OBPReturnType[Box[CustomerAccountLinkTrait]] = Future{(Failure(setUnimplementedError), callContext)}
def getConsentImplicitSCA(user: User, callContext: Option[CallContext]): OBPReturnType[Box[ConsentImplicitSCAT]] = Future{(Failure(setUnimplementedError), callContext)}
}

View File

@ -2,7 +2,6 @@ package code.bankconnectors
import java.util.Date
import java.util.UUID.randomUUID
import _root_.akka.http.scaladsl.model.HttpMethod
import code.DynamicData.DynamicDataProvider
import code.DynamicEndpoint.{DynamicEndpointProvider, DynamicEndpointT}
@ -83,7 +82,7 @@ import com.openbankproject.commons.model.enums.DynamicEntityOperation._
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA
import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus
import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _}
import com.openbankproject.commons.model.{AccountApplication, AccountAttribute, DirectDebitTrait, FXRate, Product, ProductAttribute, ProductCollectionItem, TaxResidence, TransactionRequestCommonBodyJSON, _}
import com.openbankproject.commons.model.{AccountApplication, AccountAttribute, ConsentImplicitSCAT, DirectDebitTrait, FXRate, Product, ProductAttribute, ProductCollectionItem, TaxResidence, TransactionRequestCommonBodyJSON, _}
import com.tesobe.CacheKeyFromArguments
import com.tesobe.model.UpdateBankAccount
import com.twilio.Twilio
@ -5857,4 +5856,13 @@ object LocalMappedConnector extends Connector with MdcLoggable {
CustomerAccountLinkTrait.customerAccountLink.vend.createCustomerAccountLink(customerId: String, bankId, accountId: String, relationshipType: String) map { ( _, callContext) }
}
override def getConsentImplicitSCA(user: User, callContext: Option[CallContext]): OBPReturnType[Box[ConsentImplicitSCAT]] = Future {
//find the email from the user, and the OBP Implicit SCA is email
(Full(ConsentImplicitSCA(
scaMethod = StrongCustomerAuthentication.EMAIL,
recipient = user.emailAddress
)), callContext)
}
}

View File

@ -144,10 +144,6 @@ object RemotedataViews extends ObpActorInit with Views {
(actor ? cc.getOrCreatePublicPublicView(bankId, accountId, description)).mapTo[Box[View]]
)
def createCustomRandomView(bankId: BankId, accountId: AccountId) : Box[View] = getValueFromFuture(
(actor ? cc.createRandomView(bankId, accountId)).mapTo[Box[View]]
)
// For tests
def bulkDeleteAllPermissionsAndViews(): Boolean = getValueFromFuture(
(actor ? cc.bulkDeleteAllPermissionsAndViews()).mapTo[Boolean]

View File

@ -134,10 +134,6 @@ class RemotedataViewsActor extends Actor with ObpActorHelper with MdcLoggable {
logger.debug("getOrCreatePublicPublicView(" + bankId +", "+ accountId +", "+ description +")")
sender ! (mapper.getOrCreateCustomPublicView(bankId, accountId, description))
case cc.createRandomView(bankId, accountId) =>
logger.debug("createRandomView(" + bankId +", "+ accountId +")")
sender ! (mapper.createCustomRandomView(bankId, accountId))
case cc.getOwners(view) =>
logger.debug("getOwners(" + view +")")
sender ! (mapper.getOwners(view))

View File

@ -662,113 +662,6 @@ object MapperViews extends Views with MdcLoggable {
}
}
/**
* This is only for scala tests.
*/
def createCustomRandomView(bankId: BankId, accountId: AccountId) : Box[View] = {
//we set the length is to 40, try to be difficult for scala tests create the same viewName.
val viewName = "_" + randomString(40)
val viewId = MapperViews.createViewIdByName(viewName)
val description = randomString(40)
if (!checkCustomViewIdOrName(viewName)) {
return Failure(InvalidCustomViewFormat)
}
getExistingCustomView(bankId, accountId, viewId) match {
case Empty => {
tryo{ViewDefinition.create.
isSystem_(false).
isFirehose_(false).
name_(viewName).
metadataView_(SYSTEM_OWNER_VIEW_ID).
description_(description).
view_id(viewId).
isPublic_(false).
bank_id(bankId.value).
account_id(accountId.value).
usePrivateAliasIfOneExists_(false).
usePublicAliasIfOneExists_(false).
hideOtherAccountMetadataIfAlias_(false).
canSeeTransactionThisBankAccount_(true).
canSeeTransactionOtherBankAccount_(true).
canSeeTransactionMetadata_(true).
canSeeTransactionDescription_(true).
canSeeTransactionAmount_(true).
canSeeTransactionType_(true).
canSeeTransactionCurrency_(true).
canSeeTransactionStartDate_(true).
canSeeTransactionFinishDate_(true).
canSeeTransactionBalance_(true).
canSeeComments_(true).
canSeeOwnerComment_(true).
canSeeTags_(true).
canSeeImages_(true).
canSeeBankAccountOwners_(true).
canSeeBankAccountType_(true).
canSeeBankAccountBalance_(true).
canSeeBankAccountCurrency_(true).
canSeeBankAccountLabel_(true).
canSeeBankAccountNationalIdentifier_(true).
canSeeBankAccountSwift_bic_(true).
canSeeBankAccountIban_(true).
canSeeBankAccountNumber_(true).
canSeeBankAccountBankName_(true).
canSeeBankAccountBankPermalink_(true).
canSeeOtherAccountNationalIdentifier_(true).
canSeeOtherAccountSWIFT_BIC_(true).
canSeeOtherAccountIBAN_(true).
canSeeOtherAccountBankName_(true).
canSeeOtherAccountNumber_(true).
canSeeOtherAccountMetadata_(true).
canSeeOtherAccountKind_(true).
canSeeMoreInfo_(true).
canSeeUrl_(true).
canSeeImageUrl_(true).
canSeeOpenCorporatesUrl_(true).
canSeeCorporateLocation_(true).
canSeePhysicalLocation_(true).
canSeePublicAlias_(true).
canSeePrivateAlias_(true).
canAddMoreInfo_(true).
canAddURL_(true).
canAddImageURL_(true).
canAddOpenCorporatesUrl_(true).
canAddCorporateLocation_(true).
canAddPhysicalLocation_(true).
canAddPublicAlias_(true).
canAddPrivateAlias_(true).
canDeleteCorporateLocation_(true).
canDeletePhysicalLocation_(true).
canEditOwnerComment_(true).
canAddComment_(true).
canDeleteComment_(true).
canAddTag_(true).
canDeleteTag_(true).
canAddImage_(true).
canDeleteImage_(true).
canAddWhereTag_(true).
canSeeWhereTag_(true).
canDeleteWhereTag_(true).
canSeeBankRoutingScheme_(true). //added following in V300
canSeeBankRoutingAddress_(true).
canSeeBankAccountRoutingScheme_(true).
canSeeBankAccountRoutingAddress_(true).
canSeeOtherBankRoutingScheme_(true).
canSeeOtherBankRoutingAddress_(true).
canSeeOtherAccountRoutingScheme_(true).
canSeeOtherAccountRoutingAddress_(true).
canAddTransactionRequestToOwnAccount_(false). //added following two for payments
canAddTransactionRequestToAnyAccount_(false).
canSeeBankAccountCreditLimit_(true).
saveMe}
}
case Full(v) => Full(v)
case Failure(msg, t, c) => Failure(msg, t, c)
case ParamFailure(x, y, z, q) => ParamFailure(x, y, z, q)
}
}
def createDefaultSystemView(name: String): Box[View] = {
createAndSaveSystemView(name)
}

View File

@ -113,11 +113,6 @@ trait Views {
def getOrCreateSystemView(viewId: String) : Box[View]
def getOrCreateCustomPublicView(bankId: BankId, accountId: AccountId, description: String) : Box[View]
/**
* this is only used for the scala test
*/
def createCustomRandomView(bankId: BankId, accountId: AccountId) : Box[View]
def getOwners(view: View): Set[User]
def removeAllPermissions(bankId: BankId, accountId: AccountId) : Boolean
@ -167,7 +162,6 @@ class RemotedataViewsCaseClasses {
case class getOrCreateSystemViewFromCbs(viewId: String)
case class getOrCreateSystemView(viewId: String)
case class getOrCreatePublicPublicView(bankId: BankId, accountId: AccountId, description: String)
case class createRandomView(bankId: BankId, accountId: AccountId)
case class getOwners(view: View)

View File

@ -90,7 +90,6 @@ class CreateCounterpartyTest extends V220ServerSetup with DefaultUsers {
val bankId = testBank.bankId
val accountId = AccountId("notExistingAccountId")
val viewId =ViewId(SYSTEM_OWNER_VIEW_ID)
val ownerView = createOwnerView(bankId, accountId)
Views.views.vend.grantAccessToCustomView(ViewIdBankIdAccountId(viewId, bankId, accountId), resourceUser1)
val counterpartyPostJSON = SwaggerDefinitionsJSON.postCounterpartyJSON.copy(other_bank_routing_address=bankId.value,other_account_routing_address=accountId.value)

View File

@ -64,6 +64,10 @@ class ConsentTest extends V310ServerSetup {
.copy(entitlements=entitlements)
.copy(consumer_id=Some(testConsumer.consumerId.get))
.copy(views=views)
lazy val postConsentImplicitJsonV310 = SwaggerDefinitionsJSON.postConsentImplicitJsonV310
.copy(entitlements=entitlements)
.copy(consumer_id=Some(testConsumer.consumerId.get))
.copy(views=views)
val maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600)
val timeToLive: Option[Long] = Some(maxTimeToLive + 10)
@ -78,6 +82,15 @@ class ConsentTest extends V310ServerSetup {
response400.code should equal(401)
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
}
scenario("We will call the endpoint without user credentials-IMPLICIT", ApiEndpoint1, VersionOfApi) {
When("We make a request")
val request400 = (v3_1_0_Request / "banks" / bankId / "my" / "consents" / "IMPLICIT" ).POST
val response400 = makePostRequest(request400, write(postConsentImplicitJsonV310))
Then("We should get a 401")
response400.code should equal(401)
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
}
scenario("We will call the endpoint with user credentials but wrong SCA method", ApiEndpoint1, VersionOfApi) {
When("We make a request")
@ -95,6 +108,14 @@ class ConsentTest extends V310ServerSetup {
scenario("We will call the endpoint with user credentials and deprecated header name", ApiEndpoint1, ApiEndpoint3, VersionOfApi, VersionOfApi2) {
wholeFunctionality(RequestHeader.`Consent-Id`)
}
scenario("We will call the endpoint with user credentials-Implicit", ApiEndpoint1, ApiEndpoint3, VersionOfApi, VersionOfApi2) {
wholeFunctionalityImplicit(RequestHeader.`Consent-JWT`)
}
scenario("We will call the endpoint with user credentials and deprecated header name-Implicit", ApiEndpoint1, ApiEndpoint3, VersionOfApi, VersionOfApi2) {
wholeFunctionalityImplicit(RequestHeader.`Consent-Id`)
}
}
private def wholeFunctionality(nameOfRequestHeader: String) = {
@ -175,4 +196,83 @@ class ConsentTest extends V310ServerSetup {
responseGetUserByUserId400.body.extract[ErrorMessage].message should include(ConsentDisabled)
}
}
private def wholeFunctionalityImplicit(nameOfRequestHeader: String) = {
When("We make a request")
// Create a consent as the user1.
// Must fail because we try to set time_to_live=4500
val requestWrongTimeToLive400 = (v3_1_0_Request / "banks" / bankId / "my" / "consents" / "IMPLICIT").POST <@ (user1)
val responseWrongTimeToLive400 = makePostRequest(requestWrongTimeToLive400, write(postConsentImplicitJsonV310.copy(time_to_live = timeToLive)))
Then("We should get a 400")
responseWrongTimeToLive400.code should equal(400)
responseWrongTimeToLive400.body.extract[ErrorMessage].message should include(ConsentMaxTTL)
// Create a consent as the user1.
// Must fail because we try to assign a role other that user already have access to the request
val request400 = (v3_1_0_Request / "banks" / bankId / "my" / "consents" / "IMPLICIT").POST <@ (user1)
val response400 = makePostRequest(request400, write(postConsentImplicitJsonV310))
Then("We should get a 400")
response400.code should equal(400)
response400.body.extract[ErrorMessage].message should equal(RolesAllowedInConsent)
Then("We grant the role and test it again")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString)
// Create a consent as the user1. The consent is in status INITIATED
val secondResponse400 = makePostRequest(request400, write(postConsentImplicitJsonV310))
Then("We should get a 201")
secondResponse400.code should equal(201)
val consentId = secondResponse400.body.extract[ConsentJsonV310].consent_id
val jwt = secondResponse400.body.extract[ConsentJsonV310].jwt
val header = List((nameOfRequestHeader, jwt))
// Make a request with the consent which is NOT in status ACCEPTED
val requestGetUserByUserId400 = (v3_1_0_Request / "users" / "current").GET
val responseGetUserByUserId400 = makeGetRequest(requestGetUserByUserId400, header)
APIUtil.getPropsAsBoolValue(nameOfProperty = "consents.allowed", defaultValue = false) match {
case true =>
// Due to the wrong status of the consent the request must fail
responseGetUserByUserId400.body.extract[ErrorMessage].message should include(ConsentStatusIssue)
// Answer security challenge i.e. SCA
val answerConsentChallengeRequest = (v3_1_0_Request / "banks" / bankId / "consents" / consentId / "challenge").POST <@ (user1)
val challenge = Consent.challengeAnswerAtTestEnvironment
val post = PostConsentChallengeJsonV310(answer = challenge)
val response400 = makePostRequest(answerConsentChallengeRequest, write(post))
Then("We should get a 201")
response400.code should equal(201)
// Make a request WITHOUT the request header "Consumer-Key: SOME_VALUE"
// Due to missing value the request must fail
makeGetRequest(requestGetUserByUserId400, header)
.body.extract[ErrorMessage].message should include(ConsumerKeyHeaderMissing)
// Make a request WITH the request header "Consumer-Key: NON_EXISTING_VALUE"
// Due to non existing value the request must fail
val headerConsumerKey = List((RequestHeader.`Consumer-Key`, "NON_EXISTING_VALUE"))
makeGetRequest(requestGetUserByUserId400, header ::: headerConsumerKey)
.body.extract[ErrorMessage].message should include(ConsentDoesNotMatchConsumer)
// Make a request WITH the request header "Consumer-Key: EXISTING_VALUE"
val validHeaderConsumerKey = List((RequestHeader.`Consumer-Key`, user1.map(_._1.key).getOrElse("SHOULD_NOT_HAPPEN")))
val response = makeGetRequest((v3_1_0_Request / "users" / "current").GET, header ::: validHeaderConsumerKey)
val user = response.body.extract[UserJsonV300]
val assignedEntitlements: Seq[PostConsentEntitlementJsonV310] = user.entitlements.list.flatMap(
e => entitlements.find(_ == PostConsentEntitlementJsonV310(e.bank_id, e.role_name))
)
// Check we have all entitlements from the consent
assignedEntitlements should equal(entitlements)
// Every consent implies a brand new user is created
user.user_id should not equal (resourceUser1.userId)
// Check we have all views from the consent
val assignedViews = user.views.map(_.list).toSeq.flatten
assignedViews.map(e => PostConsentViewJsonV310(e.bank_id, e.account_id, e.view_id)).distinct should equal(views)
case false =>
// Due to missing props at the instance the request must fail
responseGetUserByUserId400.body.extract[ErrorMessage].message should include(ConsentDisabled)
}
}
}

View File

@ -71,7 +71,7 @@ class SystemViewsTests extends V310ServerSetup {
// Custom view, name starts from `_`
// System view, owner
val randomSystemViewId = APIUtil.generateUUID()
val randomSystemViewId = "a"+APIUtil.generateUUID()
val postBodySystemViewJson = createSystemViewJsonV300.copy(name=randomSystemViewId).copy(metadata_view = randomSystemViewId).toCreateViewJson
def getSystemView(viewId : String, consumerAndToken: Option[(Consumer, Token)]): APIResponse = {
@ -273,13 +273,19 @@ class SystemViewsTests extends V310ServerSetup {
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access with proper Role in order to delete owner view") {
scenario("We will call the endpoint without user credentials", ApiEndpoint4, VersionOfApi) {
When(s"We make a request $ApiEndpoint2")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemView.toString)
val responseCreate400 = postSystemView(postBodySystemViewJson, user1)
Then("We should get a 201")
responseCreate400.code should equal(201)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteSystemView.toString)
When(s"We make a request $ApiEndpoint4")
AccountAccess.findAll(
By(AccountAccess.view_id, SYSTEM_OWNER_VIEW_ID),
By(AccountAccess.view_id, randomSystemViewId),
By(AccountAccess.user_fk, resourceUser1.id.get)
).forall(_.delete_!) // Remove all rows assigned to the system owner view in order to delete it
val response400 = deleteSystemView(SYSTEM_OWNER_VIEW_ID, user1)
).forall(_.delete_!) // Remove all rows assigned to the system view in order to delete it
val response400 = deleteSystemView(randomSystemViewId, user1)
Then("We should get a 200")
response400.code should equal(200)
}

View File

@ -77,18 +77,93 @@ class ConsentRequestTest extends V500ServerSetupAsync with PropsReset{
val createConsentRequestUrl = (v5_0_0_Request / "consumer"/ "consent-requests").POST<@(user1)
def getConsentRequestUrl(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId).GET<@(user1)
def createConsentByConsentRequestIdEmail(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId/"EMAIL"/"consents").POST<@(user1)
def createConsentByConsentRequestIdImplicit(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId/"IMPLICIT"/"consents").POST<@(user1)
def getConsentByRequestIdUrl(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId/"consents").GET<@(user1)
feature("Create/Get Consent Request v5.0.0") {
scenario("We will call the Create endpoint without a user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v5.0.0")
val response500 = makePostRequest(createConsentRequestWithoutLoginUrl, write(postConsentRequestJsonV310))
Then("We should get a 401")
response500.code should equal(401)
response500.body.extract[ErrorMessage].message should equal (ApplicationNotIdentified)
}
// scenario("We will call the Create endpoint without a user credentials", ApiEndpoint1, VersionOfApi) {
// When("We make a request v5.0.0")
// val response500 = makePostRequest(createConsentRequestWithoutLoginUrl, write(postConsentRequestJsonV310))
// Then("We should get a 401")
// response500.code should equal(401)
// response500.body.extract[ErrorMessage].message should equal (ApplicationNotIdentified)
// }
//
// scenario("We will call the Create, Get and Delete endpoints with user credentials ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
// When(s"We try $ApiEndpoint1 v5.0.0")
// val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postConsentRequestJsonV310))
// Then("We should get a 201")
// createConsentResponse.code should equal(201)
// val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson]
// val consentRequestId = createConsentRequestResponseJson.consent_request_id
//
// When("We try to make the GET request v5.0.0")
// val successGetRes = makeGetRequest(getConsentRequestUrl(consentRequestId))
// Then("We should get a 200")
// successGetRes.code should equal(200)
// val getConsentRequestResponseJson = successGetRes.body.extract[ConsentRequestResponseJson]
// getConsentRequestResponseJson.payload should not be("")
//
// When("We try to make the GET request v5.0.0")
// Then("We grant the role and test it again")
// Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString)
// val createConsentByRequestResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write(""))
// Then("We should get a 200")
// createConsentByRequestResponse.code should equal(201)
// val consentId = createConsentByRequestResponse.body.extract[ConsentJsonV500].consent_id
// val consentJwt = createConsentByRequestResponse.body.extract[ConsentJsonV500].jwt
//
// setPropsValues("consumer_validation_method_for_consent"->"NONE")
// val requestWhichFails = (v5_0_0_Request / "users").GET
// val responseWhichFails = makeGetRequest(requestWhichFails, List((s"Consent-JWT", consentJwt)))
// Then("We get successful response")
// responseWhichFails.code should equal(401)
//
//
// val answerConsentChallengeRequest = (v5_0_0_Request / "banks" / testBankId1.value / "consents" / consentId / "challenge").POST <@ (user1)
// val challenge = Consent.challengeAnswerAtTestEnvironment
// val post = PostConsentChallengeJsonV310(answer = challenge)
// val answerConsentChallengeResponse = makePostRequest(answerConsentChallengeRequest, write(post))
// Then("We should get a 201")
// answerConsentChallengeResponse.code should equal(201)
//
// When("We try to make the GET request v5.0.0")
// val getConsentByRequestResponse = makeGetRequest(getConsentByRequestIdUrl(consentRequestId))
// Then("We should get a 200")
// getConsentByRequestResponse.code should equal(200)
// val getConsentByRequestResponseJson = getConsentByRequestResponse.body.extract[ConsentJsonV500]
// getConsentByRequestResponseJson.consent_request_id.head should be(consentRequestId)
// getConsentByRequestResponseJson.status should be(ConsentStatus.ACCEPTED.toString)
//
//
// val requestGetUsers = (v5_0_0_Request / "users").GET
//
// // Test Request Header "Consent-JWT:SOME_VALUE"
// val consentRequestHeader = (s"Consent-JWT", getConsentByRequestResponseJson.jwt)
// val responseGetUsers = makeGetRequest(requestGetUsers, List(consentRequestHeader))
// Then("We get successful response")
// responseGetUsers.code should equal(200)
// val users = responseGetUsers.body.extract[UsersJsonV400].users
// users.size should be > 0
//
// // Test Request Header "Consent-Id:SOME_VALUE"
// val consentIdRequestHeader = (s"Consent-Id", getConsentByRequestResponseJson.consent_id)
// val responseGetUsersSecond = makeGetRequest(requestGetUsers, List(consentIdRequestHeader))
// Then("We get successful response")
// responseGetUsersSecond.code should equal(200)
// val usersSecond = responseGetUsersSecond.body.extract[UsersJsonV400].users
// usersSecond.size should be > 0
// users.size should equal(usersSecond.size)
//
// // Test Request Header "Consent-JWT:INVALID_JWT_VALUE"
// val wrongRequestHeader = (s"Consent-JWT", "INVALID_JWT_VALUE")
// val responseGetUsersWrong = makeGetRequest(requestGetUsers, List(wrongRequestHeader))
// Then("We get successful response")
// responseGetUsersWrong.code should equal(401)
// responseGetUsersWrong.body.extract[ErrorMessage].message contains (ConsentHeaderValueInvalid) should be (true)
// }
scenario("We will call the Create, Get and Delete endpoints with user credentials ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
scenario("We will call the Create (IMPLICIT), Get and Delete endpoints with user credentials ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
When(s"We try $ApiEndpoint1 v5.0.0")
val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postConsentRequestJsonV310))
Then("We should get a 201")
@ -106,7 +181,7 @@ class ConsentRequestTest extends V500ServerSetupAsync with PropsReset{
When("We try to make the GET request v5.0.0")
Then("We grant the role and test it again")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString)
val createConsentByRequestResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write(""))
val createConsentByRequestResponse = makePostRequest(createConsentByConsentRequestIdImplicit(consentRequestId), write(""))
Then("We should get a 200")
createConsentByRequestResponse.code should equal(201)
val consentId = createConsentByRequestResponse.body.extract[ConsentJsonV500].consent_id
@ -162,39 +237,39 @@ class ConsentRequestTest extends V500ServerSetupAsync with PropsReset{
responseGetUsersWrong.body.extract[ErrorMessage].message contains (ConsentHeaderValueInvalid) should be (true)
}
scenario(s"Check the forbidden roles ${CanCreateEntitlementAtAnyBank.toString()}", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
When(s"We try $ApiEndpoint1 v5.0.0")
val postJsonForbiddenEntitlementAtAnyBank = postConsentRequestJsonV310.copy(entitlements = Some(forbiddenEntitlementAnyBank))
val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postJsonForbiddenEntitlementAtAnyBank))
Then("We should get a 201")
createConsentResponse.code should equal(201)
val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson]
val consentRequestId = createConsentRequestResponseJson.consent_request_id
// Role CanCreateEntitlementAtAnyBank MUST be forbidden
val forbiddenRoleResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write(""))
Then("We should get a 400")
forbiddenRoleResponse.code should equal(400)
forbiddenRoleResponse.code should equal(400)
forbiddenRoleResponse.body.extract[ErrorMessage].message should equal (RolesForbiddenInConsent)
}
scenario(s"Check the forbidden roles ${CanCreateEntitlementAtOneBank.toString()}", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
When(s"We try $ApiEndpoint1 v5.0.0")
val postJsonForbiddenEntitlementAtOneBank = postConsentRequestJsonV310.copy(entitlements = Some(forbiddenEntitlementOneBank))
val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postJsonForbiddenEntitlementAtOneBank))
Then("We should get a 201")
createConsentResponse.code should equal(201)
val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson]
val consentRequestId = createConsentRequestResponseJson.consent_request_id
// Role CanCreateEntitlementAtOneBank MUST be forbidden
val forbiddenRoleResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write(""))
Then("We should get a 400")
forbiddenRoleResponse.code should equal(400)
forbiddenRoleResponse.code should equal(400)
forbiddenRoleResponse.body.extract[ErrorMessage].message should equal (RolesForbiddenInConsent)
}
// scenario(s"Check the forbidden roles ${CanCreateEntitlementAtAnyBank.toString()}", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
// When(s"We try $ApiEndpoint1 v5.0.0")
// val postJsonForbiddenEntitlementAtAnyBank = postConsentRequestJsonV310.copy(entitlements = Some(forbiddenEntitlementAnyBank))
// val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postJsonForbiddenEntitlementAtAnyBank))
// Then("We should get a 201")
// createConsentResponse.code should equal(201)
// val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson]
// val consentRequestId = createConsentRequestResponseJson.consent_request_id
//
// // Role CanCreateEntitlementAtAnyBank MUST be forbidden
// val forbiddenRoleResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write(""))
// Then("We should get a 400")
// forbiddenRoleResponse.code should equal(400)
// forbiddenRoleResponse.code should equal(400)
// forbiddenRoleResponse.body.extract[ErrorMessage].message should equal (RolesForbiddenInConsent)
// }
//
// scenario(s"Check the forbidden roles ${CanCreateEntitlementAtOneBank.toString()}", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) {
// When(s"We try $ApiEndpoint1 v5.0.0")
// val postJsonForbiddenEntitlementAtOneBank = postConsentRequestJsonV310.copy(entitlements = Some(forbiddenEntitlementOneBank))
// val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postJsonForbiddenEntitlementAtOneBank))
// Then("We should get a 201")
// createConsentResponse.code should equal(201)
// val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson]
// val consentRequestId = createConsentRequestResponseJson.consent_request_id
//
// // Role CanCreateEntitlementAtOneBank MUST be forbidden
// val forbiddenRoleResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write(""))
// Then("We should get a 400")
// forbiddenRoleResponse.code should equal(400)
// forbiddenRoleResponse.code should equal(400)
// forbiddenRoleResponse.body.extract[ErrorMessage].message should equal (RolesForbiddenInConsent)
// }
}

View File

@ -71,11 +71,10 @@ class SystemViewsTests extends V500ServerSetup {
// Custom view, name starts from `_`
// System view, owner
val randomSystemViewId = APIUtil.generateUUID()
val randomSystemViewId = "a"+APIUtil.generateUUID()
val postBodySystemViewJson = createSystemViewJsonV500
.copy(name=randomSystemViewId)
.copy(metadata_view = randomSystemViewId).toCreateViewJson
val systemViewId = MapperViews.createViewIdByName(postBodySystemViewJson.name)
def getSystemView(viewId : String, consumerAndToken: Option[(Consumer, Token)]): APIResponse = {
val request = v5_0_0_Request / "system-views" / viewId <@(consumerAndToken)
@ -266,15 +265,21 @@ class SystemViewsTests extends V500ServerSetup {
response400.code should equal(200)
}
}
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access with proper Role in order to delete owner view") {
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access with proper Role in order to delete system view") {
scenario("We will call the endpoint without user credentials", ApiEndpoint4, VersionOfApi) {
When(s"We make a request $ApiEndpoint2")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemView.toString)
val responseCreate400 = postSystemView(postBodySystemViewJson, user1)
Then("We should get a 201")
responseCreate400.code should equal(201)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteSystemView.toString)
When(s"We make a request $ApiEndpoint4")
AccountAccess.findAll(
By(AccountAccess.view_id, SYSTEM_OWNER_VIEW_ID),
By(AccountAccess.view_id, randomSystemViewId),
By(AccountAccess.user_fk, resourceUser1.id.get)
).forall(_.delete_!) // Remove all rows assigned to the system owner view in order to delete it
val response400 = deleteSystemView(SYSTEM_OWNER_VIEW_ID, user1)
).forall(_.delete_!) // Remove all rows assigned to the system view in order to delete it
val response400 = deleteSystemView(randomSystemViewId, user1)
Then("We should get a 200")
response400.code should equal(200)
}

View File

@ -3,11 +3,15 @@ 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.ErrorMessages._
import code.model._
import code.model.dataAccess._
import code.views.Views
import code.views.MapperViews.getExistingCustomView
import code.views.system.ViewDefinition
import code.views.{MapperViews, Views}
import com.openbankproject.commons.model._
import net.liftweb.common.{Failure, Full, ParamFailure}
import net.liftweb.mapper.MetaMapper
import net.liftweb.util.Helpers._
@ -24,16 +28,117 @@ trait TestConnectorSetupWithStandardPermissions extends TestConnectorSetup {
protected def getOrCreateSystemView(name: String) : View = {
Views.views.vend.getOrCreateSystemView(name).openOrThrowException(attemptedToOpenAnEmptyBox)
}
protected def createOwnerView(bankId: BankId, accountId: AccountId ) : View = {
Views.views.vend.getOrCreateSystemView(SYSTEM_OWNER_VIEW_ID).openOrThrowException(attemptedToOpenAnEmptyBox)
}
protected def createPublicView(bankId: BankId, accountId: AccountId) : View = {
Views.views.vend.getOrCreateCustomPublicView(bankId: BankId, accountId: AccountId, CUSTOM_PUBLIC_VIEW_ID).openOrThrowException(attemptedToOpenAnEmptyBox)
}
protected def createCustomRandomView(bankId: BankId, accountId: AccountId) : View = {
Views.views.vend.createCustomRandomView(bankId, accountId).openOrThrowException(attemptedToOpenAnEmptyBox)
def createCustomRandomView(bankId: BankId, accountId: AccountId) : View = {
{
//we set the length is to 40, try to be difficult for scala tests create the same viewName.
val viewName = "_" + randomString(40)
val viewId = MapperViews.createViewIdByName(viewName)
val description = randomString(40)
if (!checkCustomViewIdOrName(viewName)) {
throw new RuntimeException(InvalidCustomViewFormat)
}
getExistingCustomView(bankId, accountId, viewId) match {
case net.liftweb.common.Empty => {
tryo {
ViewDefinition.create.
isSystem_(false).
isFirehose_(false).
name_(viewName).
metadataView_(SYSTEM_OWNER_VIEW_ID).
description_(description).
view_id(viewId).
isPublic_(false).
bank_id(bankId.value).
account_id(accountId.value).
usePrivateAliasIfOneExists_(false).
usePublicAliasIfOneExists_(false).
hideOtherAccountMetadataIfAlias_(false).
canSeeTransactionThisBankAccount_(true).
canSeeTransactionOtherBankAccount_(true).
canSeeTransactionMetadata_(true).
canSeeTransactionDescription_(true).
canSeeTransactionAmount_(true).
canSeeTransactionType_(true).
canSeeTransactionCurrency_(true).
canSeeTransactionStartDate_(true).
canSeeTransactionFinishDate_(true).
canSeeTransactionBalance_(true).
canSeeComments_(true).
canSeeOwnerComment_(true).
canSeeTags_(true).
canSeeImages_(true).
canSeeBankAccountOwners_(true).
canSeeBankAccountType_(true).
canSeeBankAccountBalance_(true).
canSeeBankAccountCurrency_(true).
canSeeBankAccountLabel_(true).
canSeeBankAccountNationalIdentifier_(true).
canSeeBankAccountSwift_bic_(true).
canSeeBankAccountIban_(true).
canSeeBankAccountNumber_(true).
canSeeBankAccountBankName_(true).
canSeeBankAccountBankPermalink_(true).
canSeeOtherAccountNationalIdentifier_(true).
canSeeOtherAccountSWIFT_BIC_(true).
canSeeOtherAccountIBAN_(true).
canSeeOtherAccountBankName_(true).
canSeeOtherAccountNumber_(true).
canSeeOtherAccountMetadata_(true).
canSeeOtherAccountKind_(true).
canSeeMoreInfo_(true).
canSeeUrl_(true).
canSeeImageUrl_(true).
canSeeOpenCorporatesUrl_(true).
canSeeCorporateLocation_(true).
canSeePhysicalLocation_(true).
canSeePublicAlias_(true).
canSeePrivateAlias_(true).
canAddMoreInfo_(true).
canAddURL_(true).
canAddImageURL_(true).
canAddOpenCorporatesUrl_(true).
canAddCorporateLocation_(true).
canAddPhysicalLocation_(true).
canAddPublicAlias_(true).
canAddPrivateAlias_(true).
canDeleteCorporateLocation_(true).
canDeletePhysicalLocation_(true).
canEditOwnerComment_(true).
canAddComment_(true).
canDeleteComment_(true).
canAddTag_(true).
canDeleteTag_(true).
canAddImage_(true).
canDeleteImage_(true).
canAddWhereTag_(true).
canSeeWhereTag_(true).
canDeleteWhereTag_(true).
canSeeBankRoutingScheme_(true). //added following in V300
canSeeBankRoutingAddress_(true).
canSeeBankAccountRoutingScheme_(true).
canSeeBankAccountRoutingAddress_(true).
canSeeOtherBankRoutingScheme_(true).
canSeeOtherBankRoutingAddress_(true).
canSeeOtherAccountRoutingScheme_(true).
canSeeOtherAccountRoutingAddress_(true).
canAddTransactionRequestToOwnAccount_(false). //added following two for payments
canAddTransactionRequestToAnyAccount_(false).
canSeeBankAccountCreditLimit_(true).
saveMe
}
}
case Full(v) => Full(v)
case Failure(msg, t, c) => Failure(msg, t, c)
case ParamFailure(x, y, z, q) => ParamFailure(x, y, z, q)
}
}.openOrThrowException(attemptedToOpenAnEmptyBox)
}

View File

@ -582,7 +582,16 @@ trait ChallengeTrait {
}
trait ConsentImplicitSCAT {
def scaMethod: SCA
def recipient: String
}
//---------------------------------------- trait dependents of case class
case class ConsentImplicitSCA(
scaMethod: SCA,
recipient: String
) extends ConsentImplicitSCAT
@deprecated("Use Lobby instead which contains detailed fields, not this string","24 July 2017")
case class LobbyString (hours : String) extends LobbyStringT

View File

@ -84,6 +84,7 @@ object StrongCustomerAuthentication extends OBPEnumeration[StrongCustomerAuthent
type SCA = Value
object SMS extends Value
object EMAIL extends Value
object IMPLICIT extends Value
object DUMMY extends Value
object UNDEFINED extends Value