mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
Merge pull request #2229 from hongwei1/develop
feature/support the IMPLICIT SCA method
This commit is contained in:
commit
a22ef5de07
@ -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))
|
||||
|
||||
@ -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. "
|
||||
|
||||
@ -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 =>
|
||||
|
||||
@ -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 "
|
||||
|
||||
@ -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])
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)}
|
||||
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
Binary file not shown.
@ -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)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user