mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:26:51 +00:00
feature/AAdd Endpoint Create Consent Implicit without BANK_ID
This commit is contained in:
parent
62f1193bef
commit
858e67aa28
@ -21,7 +21,7 @@ import code.api.v2_0_0.AccountsHelper.{accountTypeFilterText, getFilteredCoreAcc
|
||||
import code.api.v2_1_0.{ConsumerRedirectUrlJSON, JSONFactory210}
|
||||
import code.api.v3_0_0.JSONFactory300
|
||||
import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
|
||||
import code.api.v3_1_0.{ConsentChallengeJsonV310, ConsentJsonV310}
|
||||
import code.api.v3_1_0.{ConsentChallengeJsonV310, ConsentJsonV310, PostConsentBodyCommonJson, PostConsentEmailJsonV310, PostConsentPhoneJsonV310}
|
||||
import code.api.v3_1_0.JSONFactory310.{createBadLoginStatusJson, createConsumerJSON, createRefreshUserJson}
|
||||
import code.api.v4_0_0.JSONFactory400.{createAccountBalancesJson, createBalancesJson, createNewCoreBankAccountJson}
|
||||
import code.api.v4_0_0.{JSONFactory400, PostAccountAccessJsonV400, PostApiCollectionJson400, PutConsentStatusJsonV400, PutConsentUserJsonV400, RevokedJsonV400}
|
||||
@ -31,6 +31,7 @@ import code.atmattribute.AtmAttribute
|
||||
import code.bankconnectors.Connector
|
||||
import code.consent.{ConsentRequests, ConsentStatus, Consents, MappedConsent}
|
||||
import code.consumer.Consumers
|
||||
import code.entitlement.Entitlement
|
||||
import code.loginattempts.LoginAttempt
|
||||
import code.metrics.APIMetrics
|
||||
import code.metrics.MappedMetric.userId
|
||||
@ -46,7 +47,7 @@ import code.views.system.{AccountAccess, ViewDefinition}
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import com.openbankproject.commons.model._
|
||||
import com.openbankproject.commons.model.enums.{AtmAttributeType, ConsentType, TransactionRequestStatus, UserAttributeType}
|
||||
import com.openbankproject.commons.model.enums.{AtmAttributeType, ConsentType, StrongCustomerAuthentication, TransactionRequestStatus, UserAttributeType}
|
||||
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
@ -54,7 +55,7 @@ import net.liftweb.json
|
||||
import net.liftweb.json.{Extraction, compactRender, parse, prettyRender}
|
||||
import net.liftweb.mapper.By
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
import net.liftweb.util.{Helpers, StringHelpers}
|
||||
import net.liftweb.util.{Helpers, Props, StringHelpers}
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.{LocalDate, ZoneId}
|
||||
@ -1843,7 +1844,287 @@ trait APIMethods510 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
val generalObpConsentText: String =
|
||||
s"""
|
||||
|
|
||||
|An OBP Consent allows the holder of the Consent to call one or more endpoints.
|
||||
|
|
||||
|Consents must be created and authorisied using SCA (Strong Customer Authentication).
|
||||
|
|
||||
|That is, Consents can be created by an authorised User via the OBP REST API but they must be confirmed via an out of band (OOB) mechanism such as a code sent to a mobile phone.
|
||||
|
|
||||
|Each Consent has one of the following states: ${ConsentStatus.values.toList.sorted.mkString(", ")}.
|
||||
|
|
||||
|Each Consent is bound to a consumer i.e. you need to identify yourself over request header value Consumer-Key.
|
||||
|For example:
|
||||
|GET /obp/v4.0.0/users/current HTTP/1.1
|
||||
|Host: 127.0.0.1:8080
|
||||
|Consent-JWT: eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOlt7InJvbGVfbmFtZSI6IkNhbkdldEFueVVzZXIiLCJiYW5rX2lkIjoiIn
|
||||
|1dLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIzNDc1MDEzZi03YmY5LTQyNj
|
||||
|EtOWUxYy0xZTdlNWZjZTJlN2UiLCJhdWQiOiI4MTVhMGVmMS00YjZhLTQyMDUtYjExMi1lNDVmZDZmNGQzYWQiLCJuYmYiOjE1ODA3NDE2NjcsIml
|
||||
|zcyI6Imh0dHA6XC9cLzEyNy4wLjAuMTo4MDgwIiwiZXhwIjoxNTgwNzQ1MjY3LCJpYXQiOjE1ODA3NDE2NjcsImp0aSI6ImJkYzVjZTk5LTE2ZTY
|
||||
|tNDM4Yi1hNjllLTU3MTAzN2RhMTg3OCIsInZpZXdzIjpbXX0.L3fEEEhdCVr3qnmyRKBBUaIQ7dk1VjiFaEBW8hUNjfg
|
||||
|
|
||||
|Consumer-Key: ejznk505d132ryomnhbx1qmtohurbsbb0kijajsk
|
||||
|cache-control: no-cache
|
||||
|
|
||||
|Maximum time to live of the token is specified over props value consents.max_time_to_live. In case isn't defined default value is 3600 seconds.
|
||||
|
|
||||
|Example of POST JSON:
|
||||
|{
|
||||
| "everything": false,
|
||||
| "views": [
|
||||
| {
|
||||
| "bank_id": "GENODEM1GLS",
|
||||
| "account_id": "8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
|
||||
| "view_id": "${Constant.SYSTEM_OWNER_VIEW_ID}"
|
||||
| }
|
||||
| ],
|
||||
| "entitlements": [
|
||||
| {
|
||||
| "bank_id": "GENODEM1GLS",
|
||||
| "role_name": "CanGetCustomer"
|
||||
| }
|
||||
| ],
|
||||
| "consumer_id": "7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh",
|
||||
| "email": "eveline@example.com",
|
||||
| "valid_from": "2020-02-07T08:43:34Z",
|
||||
| "time_to_live": 3600
|
||||
|}
|
||||
|Please note that only optional fields are: consumer_id, valid_from and time_to_live.
|
||||
|In case you omit they the default values are used:
|
||||
|consumer_id = consumer of current user
|
||||
|valid_from = current time
|
||||
|time_to_live = consents.max_time_to_live
|
||||
|
|
||||
""".stripMargin
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createConsentImplicit,
|
||||
implementedInApiVersion,
|
||||
nameOf(createConsentImplicit),
|
||||
"POST",
|
||||
"/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
|
||||
|
|
||||
|${userAuthenticationMessage(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": "${Constant.SYSTEM_OWNER_VIEW_ID}"
|
||||
| }
|
||||
| ],
|
||||
| "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 createConsentImplicit = createConsent
|
||||
|
||||
lazy val createConsent: OBPEndpoint = {
|
||||
case "my" :: "consents" :: scaMethod :: Nil JsonPost json -> _ => {
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
(Full(user), callContext) <- authenticatedAccess(cc)
|
||||
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc = callContext) {
|
||||
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) {
|
||||
json.extract[PostConsentBodyCommonJson]
|
||||
}
|
||||
maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty = "consents.max_time_to_live", defaultValue = 3600)
|
||||
_ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc = callContext) {
|
||||
consentJson.time_to_live match {
|
||||
case Some(ttl) => ttl <= maxTimeToLive
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
requestedEntitlements = consentJson.entitlements
|
||||
myEntitlements <- Entitlement.entitlement.vend.getEntitlementsByUserIdFuture(user.userId)
|
||||
_ <- Helper.booleanToFuture(RolesAllowedInConsent, cc = callContext) {
|
||||
requestedEntitlements.forall(
|
||||
re => myEntitlements.getOrElse(Nil).exists(
|
||||
e => e.roleName == re.role_name && e.bankId == re.bank_id
|
||||
)
|
||||
)
|
||||
}
|
||||
requestedViews = consentJson.views
|
||||
(_, assignedViews) <- Future(Views.views.vend.privateViewsUserCanAccess(user))
|
||||
_ <- Helper.booleanToFuture(ViewsAllowedInConsent, cc = callContext) {
|
||||
requestedViews.forall(
|
||||
rv => assignedViews.exists {
|
||||
e =>
|
||||
e.view_id == rv.view_id &&
|
||||
e.bank_id == rv.bank_id &&
|
||||
e.account_id == rv.account_id
|
||||
}
|
||||
)
|
||||
}
|
||||
(consumerId, applicationText) <- consentJson.consumer_id match {
|
||||
case Some(id) => NewStyle.function.checkConsumerByConsumerId(id, callContext) map {
|
||||
c => (Some(c.consumerId.get), c.description)
|
||||
}
|
||||
case None => Future(None, "Any application")
|
||||
}
|
||||
|
||||
|
||||
challengeAnswer = Props.mode match {
|
||||
case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
|
||||
case _ => SecureRandomUtil.numeric()
|
||||
}
|
||||
createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, None)) map {
|
||||
i => connectorEmptyResponse(i, callContext)
|
||||
}
|
||||
consentJWT =
|
||||
Consent.createConsentJWT(
|
||||
user,
|
||||
consentJson,
|
||||
createdConsent.secret,
|
||||
createdConsent.consentId,
|
||||
consumerId,
|
||||
consentJson.valid_from,
|
||||
consentJson.time_to_live.getOrElse(3600)
|
||||
)
|
||||
_ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map {
|
||||
i => connectorEmptyResponse(i, callContext)
|
||||
}
|
||||
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 should be the $PostConsentEmailJsonV310"
|
||||
}
|
||||
postConsentEmailJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
json.extract[PostConsentEmailJsonV310]
|
||||
}
|
||||
(status, callContext) <- NewStyle.function.sendCustomerNotification(
|
||||
StrongCustomerAuthentication.EMAIL,
|
||||
postConsentEmailJson.email,
|
||||
Some("OBP Consent Challenge"),
|
||||
challengeText,
|
||||
callContext
|
||||
)
|
||||
} yield Future {
|
||||
status
|
||||
}
|
||||
case v if v == StrongCustomerAuthentication.SMS.toString =>
|
||||
for {
|
||||
failMsg <- Future {
|
||||
s"$InvalidJsonFormat The Json body should be the $PostConsentPhoneJsonV310"
|
||||
}
|
||||
postConsentPhoneJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
json.extract[PostConsentPhoneJsonV310]
|
||||
}
|
||||
phoneNumber = postConsentPhoneJson.phone_number
|
||||
(status, callContext) <- NewStyle.function.sendCustomerNotification(
|
||||
StrongCustomerAuthentication.SMS,
|
||||
phoneNumber,
|
||||
None,
|
||||
challengeText,
|
||||
callContext
|
||||
)
|
||||
} yield Future {
|
||||
status
|
||||
}
|
||||
case v if v == StrongCustomerAuthentication.IMPLICIT.toString =>
|
||||
for {
|
||||
(consentImplicitSCA, callContext) <- NewStyle.function.getConsentImplicitSCA(user, callContext)
|
||||
status <- consentImplicitSCA.scaMethod match {
|
||||
case v if v == StrongCustomerAuthentication.EMAIL => // Send the email
|
||||
NewStyle.function.sendCustomerNotification(
|
||||
StrongCustomerAuthentication.EMAIL,
|
||||
consentImplicitSCA.recipient,
|
||||
Some("OBP Consent Challenge"),
|
||||
challengeText,
|
||||
callContext
|
||||
)
|
||||
case v if v == StrongCustomerAuthentication.SMS =>
|
||||
NewStyle.function.sendCustomerNotification(
|
||||
StrongCustomerAuthentication.SMS,
|
||||
consentImplicitSCA.recipient,
|
||||
None,
|
||||
challengeText,
|
||||
callContext
|
||||
)
|
||||
case _ => Future {
|
||||
"Success"
|
||||
}
|
||||
}} yield {
|
||||
status
|
||||
}
|
||||
case _ => Future {
|
||||
"Success"
|
||||
}
|
||||
}
|
||||
} yield {
|
||||
(ConsentJsonV310(createdConsent.consentId, consentJWT, createdConsent.status), HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
mtlsClientCertificateInfo,
|
||||
|
||||
179
obp-api/src/test/scala/code/api/v5_1_0/ConsentObpTest.scala
Normal file
179
obp-api/src/test/scala/code/api/v5_1_0/ConsentObpTest.scala
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
Open Bank Project - API
|
||||
Copyright (C) 2011-2019, TESOBE GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Email: contact@tesobe.com
|
||||
TESOBE GmbH
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
*/
|
||||
package code.api.v5_1_0
|
||||
|
||||
import code.api.{Constant, RequestHeader}
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.util.ApiRole._
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.{APIUtil, Consent}
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.v3_0_0.{APIMethods300, UserJsonV300}
|
||||
import code.api.v3_1_0.{ConsentJsonV310, PostConsentChallengeJsonV310, PostConsentEntitlementJsonV310, PostConsentViewJsonV310}
|
||||
import code.api.v3_1_0.OBPAPI3_1_0.Implementations3_1_0
|
||||
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
|
||||
import code.entitlement.Entitlement
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.ErrorMessage
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import net.liftweb.json.Serialization.write
|
||||
import org.scalatest.Tag
|
||||
|
||||
class ConsentObpTest extends V510ServerSetup {
|
||||
|
||||
/**
|
||||
* Test tags
|
||||
* Example: To run tests with tag "getPermissions":
|
||||
* mvn test -D tagsToInclude
|
||||
*
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString)
|
||||
object CreateConsent extends Tag(nameOf(Implementations5_1_0.createConsent))
|
||||
object AnswerConsentChallenge extends Tag(nameOf(Implementations3_1_0.answerConsentChallenge))
|
||||
|
||||
object VersionOfApi2 extends Tag(ApiVersion.v3_0_0.toString)
|
||||
object GetUserByUserId extends Tag(nameOf(APIMethods300.Implementations3_0_0.getUserByUserId))
|
||||
|
||||
lazy val bankId = randomBankId
|
||||
lazy val bankAccount = randomPrivateAccount(bankId)
|
||||
lazy val entitlements = List(PostConsentEntitlementJsonV310("", CanGetAnyUser.toString()))
|
||||
lazy val views = List(PostConsentViewJsonV310(bankId, bankAccount.id, Constant.SYSTEM_OWNER_VIEW_ID))
|
||||
lazy val postConsentEmailJsonV310 = SwaggerDefinitionsJSON.postConsentEmailJsonV310
|
||||
.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)
|
||||
|
||||
feature(s"test $CreateConsent version $VersionOfApi - Unauthorized access")
|
||||
{
|
||||
scenario("We will call the endpoint without user credentials-IMPLICIT", CreateConsent, VersionOfApi) {
|
||||
When("We make a request")
|
||||
val request = (v5_1_0_Request / "my" / "consents" / "IMPLICIT" ).POST
|
||||
val response = makePostRequest(request, write(postConsentImplicitJsonV310))
|
||||
Then("We should get a 401")
|
||||
response.code should equal(401)
|
||||
response.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
|
||||
scenario("We will call the endpoint with user credentials-Implicit", CreateConsent, GetUserByUserId, VersionOfApi, VersionOfApi2) {
|
||||
setPropsValues("consumer_validation_method_for_consent"-> "CONSUMER_KEY_VALUE")
|
||||
wholeFunctionalityImplicit(RequestHeader.`Consent-JWT`)
|
||||
setPropsValues("consumer_validation_method_for_consent"-> "CONSUMER_CERTIFICATE")
|
||||
}
|
||||
|
||||
scenario("We will call the endpoint with user credentials and deprecated header name-Implicit", CreateConsent, GetUserByUserId, VersionOfApi, VersionOfApi2) {
|
||||
setPropsValues("consumer_validation_method_for_consent"-> "CONSUMER_KEY_VALUE")
|
||||
wholeFunctionalityImplicit(RequestHeader.`Consent-Id`)
|
||||
setPropsValues("consumer_validation_method_for_consent"-> "CONSUMER_CERTIFICATE")
|
||||
}
|
||||
}
|
||||
|
||||
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 requestWrongTimeToLive = (v5_1_0_Request / "my" / "consents" / "IMPLICIT").POST <@ (user1)
|
||||
val responseWrongTimeToLive = makePostRequest(requestWrongTimeToLive, write(postConsentImplicitJsonV310.copy(time_to_live = timeToLive)))
|
||||
Then("We should get a 400")
|
||||
responseWrongTimeToLive.code should equal(400)
|
||||
responseWrongTimeToLive.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 request = (v5_1_0_Request / "my" / "consents" / "IMPLICIT").POST <@ (user1)
|
||||
val response = makePostRequest(request, write(postConsentImplicitJsonV310))
|
||||
Then("We should get a 400")
|
||||
response.code should equal(400)
|
||||
response.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 secondResponse = makePostRequest(request, write(postConsentImplicitJsonV310))
|
||||
Then("We should get a 201")
|
||||
secondResponse.code should equal(201)
|
||||
|
||||
val consentId = secondResponse.body.extract[ConsentJsonV310].consent_id
|
||||
val jwt = secondResponse.body.extract[ConsentJsonV310].jwt
|
||||
val header = List((nameOfRequestHeader, jwt))
|
||||
|
||||
// Make a request with the consent which is NOT in status ACCEPTED
|
||||
val requestGetUserByUserId = (v5_1_0_Request / "users" / "current").GET
|
||||
val responseGetUserByUserId = makeGetRequest(requestGetUserByUserId, header)
|
||||
APIUtil.getPropsAsBoolValue(nameOfProperty = "consents.allowed", defaultValue = false) match {
|
||||
case true =>
|
||||
// Due to the wrong status of the consent the request must fail
|
||||
responseGetUserByUserId.body.extract[ErrorMessage].message should include(ConsentStatusIssue)
|
||||
|
||||
// Answer security challenge i.e. SCA
|
||||
val answerConsentChallengeRequest = (v5_1_0_Request / "banks" / bankId / "consents" / consentId / "challenge").POST <@ (user1)
|
||||
val challenge = Consent.challengeAnswerAtTestEnvironment
|
||||
val post = PostConsentChallengeJsonV310(answer = challenge)
|
||||
val response = makePostRequest(answerConsentChallengeRequest, write(post))
|
||||
Then("We should get a 201")
|
||||
response.code should equal(201)
|
||||
|
||||
// Make a request WITHOUT the request header "Consumer-Key: SOME_VALUE"
|
||||
// Due to missing value the request must fail
|
||||
makeGetRequest(requestGetUserByUserId, 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(requestGetUserByUserId, 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 response2 = makeGetRequest((v5_1_0_Request / "users" / "current").GET, header ::: validHeaderConsumerKey)
|
||||
val user = response2.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
|
||||
responseGetUserByUserId.body.extract[ErrorMessage].message should include(ConsentDisabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -43,6 +43,12 @@ trait V510ServerSetup extends ServerSetupWithTestData with DefaultUsers {
|
||||
bank.id
|
||||
}
|
||||
|
||||
def randomPrivateAccount(bankId: String): AccountJSON = {
|
||||
val accountsJson = getPrivateAccounts(bankId, user1).body.extract[AccountsJSON].accounts
|
||||
val randomPosition = nextInt(accountsJson.size)
|
||||
accountsJson(randomPosition)
|
||||
}
|
||||
|
||||
def getPrivateAccountsViaEndpoint(bankId : String, consumerAndToken: Option[(Consumer, Token)]) : APIResponse = {
|
||||
val request = v5_1_0_Request / "banks" / bankId / "accounts" / "private" <@(consumerAndToken)
|
||||
makeGetRequest(request)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user