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

This commit is contained in:
tawoe 2025-05-12 16:01:54 +02:00
commit 8c422752e2
13 changed files with 118 additions and 56 deletions

View File

@ -248,7 +248,7 @@ recurringIndicator:
(Full(user), callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Aisp(callContext)
_ <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
unboxFullOrFail(_, callContext, ConsentNotFound)
unboxFullOrFail(_, callContext, ConsentNotFound, 403)
}
_ <- Future(Consents.consentProvider.vend.revokeBerlinGroupConsent(consentId)) map {
i => connectorEmptyResponse(i, callContext)
@ -752,7 +752,7 @@ This method returns the SCA status of a consent initiation's authorisation sub-r
(_, callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Aisp(callContext)
_ <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
unboxFullOrFail(_, callContext, s"$ConsentNotFound ($consentId)")
unboxFullOrFail(_, callContext, s"$ConsentNotFound ($consentId)", 403)
}
(challenges, callContext) <- NewStyle.function.getChallengesByConsentId(consentId, callContext)
} yield {
@ -787,7 +787,7 @@ This method returns the SCA status of a consent initiation's authorisation sub-r
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Aisp(callContext)
consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
unboxFullOrFail(_, callContext, ConsentNotFound)
unboxFullOrFail(_, callContext, ConsentNotFound, 403)
}
} yield {
val status = consent.status
@ -1134,7 +1134,7 @@ using the extended forms as indicated above.
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Aisp(callContext)
consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
unboxFullOrFail(_, callContext, ConsentNotFound)
unboxFullOrFail(_, callContext, ConsentNotFound, 403)
}
(challenges, callContext) <- NewStyle.function.createChallengesC2(
List(u.userId),
@ -1297,7 +1297,7 @@ Maybe in a later version the access path will change.
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Aisp(callContext)
_ <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
unboxFullOrFail(_, callContext, ConsentNotFound)
unboxFullOrFail(_, callContext, ConsentNotFound, 403)
}
failMsg = s"$InvalidJsonFormat The Json body should be the $TransactionAuthorisation "
updateJson <- NewStyle.function.tryons(failMsg, 400, callContext) {

View File

@ -62,7 +62,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
case class CoreAccountJsonV13(
resourceId: String,
iban: String,
bban: String,
bban: Option[String],
currency: String,
name: String,
product: String,
@ -137,6 +137,10 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
iban: String,
currency : Option[String] = None,
)
case class FromAccountJson(
iban: String,
currency : Option[String] = None,
)
case class TransactionJsonV13(
transactionId: String,
creditorName: String,
@ -190,7 +194,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
)
case class TransactionsJsonV13(
account:FromAccount,
account: FromAccountJson,
transactions:TransactionsV13Transactions,
)
@ -259,7 +263,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
recurringIndicator: Boolean,
validUntil: String,
frequencyPerDay: Int,
combinedServiceIndicator: Boolean,
combinedServiceIndicator: Option[Boolean],
lastActionDate: String,
consentStatus: String
)
@ -332,12 +336,12 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
CoreAccountJsonV13(
resourceId = x.accountId.value,
iban = iBan,
bban = bBan,
bban = None,
currency = x.currency,
name = x.name,
cashAccountType = x.accountType,
product = x.accountType,
balances = accountBalances,
balances = if(canReadBalances) accountBalances else None,
_links = CoreAccountLinksJsonV13(
balances = if(canReadBalances) Some(balanceRef) else None,
transactions = if(canReadTransactions) Some(transactionRef) else None,
@ -363,7 +367,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
CoreAccountJsonV13(
resourceId = x.accountId.value,
iban = iBan,
bban = bBan,
bban = None,
currency = x.currency,
name = x.name,
cashAccountType = x.accountType,
@ -440,14 +444,17 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
))
}
def createTransactionJSON(bankAccount: BankAccount, transaction : ModeratedTransaction, creditorAccount: CreditorAccountJson) : TransactionJsonV13 = {
val bookingDate = transaction.startDate.getOrElse(null)
val valueDate = transaction.finishDate.getOrElse(null)
def createTransactionJSON(bankAccount: BankAccount, transaction : ModeratedTransaction) : TransactionJsonV13 = {
val bookingDate = transaction.startDate.orNull
val valueDate = transaction.finishDate.orNull
val creditorName = bankAccount.label
TransactionJsonV13(
transactionId = transaction.id.value,
creditorName = creditorName,
creditorAccount = creditorAccount,
creditorAccount = CreditorAccountJson(
transaction.otherBankAccount.map(_.iban.orNull).orNull,
transaction.currency
),
transactionAmount = AmountOfMoneyV13(APIUtil.stringOptionOrNull(transaction.currency), transaction.amount.get.toString().trim.stripPrefix("-")),
bookingDate = BgSpecValidation.formatToISODate(bookingDate) ,
valueDate = BgSpecValidation.formatToISODate(valueDate),
@ -476,16 +483,19 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
}
def createTransactionFromRequestJSON(bankAccount: BankAccount, transactionRequest : TransactionRequest, creditorAccount: CreditorAccountJson) : TransactionJsonV13 = {
def createTransactionFromRequestJSON(bankAccount: BankAccount, tr : TransactionRequest) : TransactionJsonV13 = {
val creditorName = bankAccount.accountHolder
val remittanceInformationUnstructured = stringOrNull(transactionRequest.body.description)
val remittanceInformationUnstructured = stringOrNull(tr.body.description)
TransactionJsonV13(
transactionId = transactionRequest.id.value,
transactionId = tr.id.value,
creditorName = creditorName,
creditorAccount = creditorAccount,
transactionAmount = AmountOfMoneyV13(transactionRequest.charge.value.currency, transactionRequest.charge.value.amount.trim.stripPrefix("-")),
bookingDate = BgSpecValidation.formatToISODate(transactionRequest.start_date),
valueDate = BgSpecValidation.formatToISODate(transactionRequest.end_date),
creditorAccount = CreditorAccountJson(
if (tr.other_account_routing_scheme == "IBAN") tr.other_account_routing_address else "",
Some(tr.body.value.currency)
),
transactionAmount = AmountOfMoneyV13(tr.charge.value.currency, tr.charge.value.amount.trim.stripPrefix("-")),
bookingDate = BgSpecValidation.formatToISODate(tr.start_date),
valueDate = BgSpecValidation.formatToISODate(tr.end_date),
remittanceInformationUnstructured = remittanceInformationUnstructured
)
}
@ -494,17 +504,15 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
val accountId = bankAccount.accountId.value
val (iban: String, bban: String) = getIbanAndBban(bankAccount)
val creditorAccount = CreditorAccountJson(
val account = FromAccountJson(
iban = iban,
currency = Some(bankAccount.currency)
)
TransactionsJsonV13(
FromAccount(
iban = iban,
),
account,
TransactionsV13Transactions(
booked= transactions.map(transaction => createTransactionJSON(bankAccount, transaction, creditorAccount)),
pending = transactionRequests.filter(_.status!="COMPLETED").map(transactionRequest => createTransactionFromRequestJSON(bankAccount, transactionRequest, creditorAccount)),
booked= transactions.map(transaction => createTransactionJSON(bankAccount, transaction)),
pending = transactionRequests.filter(_.status!="COMPLETED").map(transactionRequest => createTransactionFromRequestJSON(bankAccount, transactionRequest)),
_links = TransactionsV13TransactionsLinks(LinkHrefJson(s"/v1.3/accounts/$accountId"))
)
)
@ -626,7 +634,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
recurringIndicator = createdConsent.recurringIndicator,
validUntil = if(createdConsent.validUntil == null) null else new SimpleDateFormat(DateWithDay).format(createdConsent.validUntil),
frequencyPerDay = createdConsent.frequencyPerDay,
combinedServiceIndicator= createdConsent.combinedServiceIndicator,
combinedServiceIndicator = None,
lastActionDate = if(createdConsent.lastActionDate == null) null else new SimpleDateFormat(DateWithDay).format(createdConsent.lastActionDate),
consentStatus = createdConsent.status.toLowerCase()
)

View File

@ -260,7 +260,7 @@ This method returns the SCA status of a signing basket's authorisation sub-resou
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Pisp(callContext)
_ <- Future(SigningBasketX.signingBasketProvider.vend.getSigningBasketByBasketId(basketId)) map {
unboxFullOrFail(_, callContext, s"$ConsentNotFound ($basketId)")
unboxFullOrFail(_, callContext, s"$ConsentNotFound ($basketId)", 403)
}
(challenges, callContext) <- NewStyle.function.getChallengesByBasketId(basketId, callContext)
} yield {

View File

@ -149,6 +149,8 @@ object RequestHeader {
final lazy val `PSD2-CERT` = "PSD2-CERT"
final lazy val `If-None-Match` = "If-None-Match"
final lazy val `PSU-Device-ID` = "PSU-Device-ID" // Berlin Group
final lazy val `PSU-IP-Address` = "PSU-IP-Address" // Berlin Group
final lazy val `X-Request-ID` = "X-Request-ID" // Berlin Group
final lazy val `TPP-Redirect-URI` = "TPP-Redirect-URI" // Berlin Group
final lazy val `TPP-Nok-Redirect-URI` = "TPP-Nok-Redirect-URI" // Redirect URI in case of an error.

View File

@ -3001,12 +3001,12 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val res =
if (authHeadersWithEmptyValues.nonEmpty) { // Check Authorization Headers Empty Values
val message = ErrorMessages.EmptyRequestHeaders + s"Header names: ${authHeadersWithEmptyValues.mkString(", ")}"
Future { (fullBoxOrException(Empty ~> APIFailureNewStyle(message, 400, Some(cc.toLight))), None) }
Future { (fullBoxOrException(Empty ~> APIFailureNewStyle(message, 400, Some(cc.toLight))), Some(cc)) }
} else if (authHeadersWithEmptyNames.nonEmpty) { // Check Authorization Headers Empty Names
val message = ErrorMessages.EmptyRequestHeaders + s"Header values: ${authHeadersWithEmptyNames.mkString(", ")}"
Future { (fullBoxOrException(Empty ~> APIFailureNewStyle(message, 400, Some(cc.toLight))), None) }
Future { (fullBoxOrException(Empty ~> APIFailureNewStyle(message, 400, Some(cc.toLight))), Some(cc)) }
} else if (authHeaders.size > 1) { // Check Authorization Headers ambiguity
Future { (Failure(ErrorMessages.AuthorizationHeaderAmbiguity + s"${authHeaders}"), None) }
Future { (Failure(ErrorMessages.AuthorizationHeaderAmbiguity + s"${authHeaders}"), Some(cc)) }
} else if (APIUtil.`hasConsent-ID`(reqHeaders)) { // Berlin Group's Consent
Consent.applyBerlinGroupRules(APIUtil.`getConsent-ID`(reqHeaders), cc.copy(consumer = consumerByCertificate))
} else if (APIUtil.hasConsentJWT(reqHeaders)) { // Open Bank Project's Consent

View File

@ -69,8 +69,6 @@ object BerlinGroupError {
case "401" if message.contains("OBP-35018") => "CONSENT_INVALID"
case "401" if message.contains("OBP-35005") => "CONSENT_INVALID"
case "403" if message.contains("OBP-35001") => "CONSENT_UNKNOWN"
case "401" if message.contains("OBP-20300") => "CERTIFICATE_BLOCKED"
case "401" if message.contains("OBP-20312") => "CERTIFICATE_INVALID"
case "401" if message.contains("OBP-20300") => "CERTIFICATE_INVALID"
@ -80,6 +78,7 @@ object BerlinGroupError {
case "400" if message.contains("OBP-35018") => "CONSENT_UNKNOWN"
case "400" if message.contains("OBP-35001") => "CONSENT_UNKNOWN"
case "403" if message.contains("OBP-35001") => "CONSENT_UNKNOWN"
case "404" if message.contains("OBP-30076") => "RESOURCE_UNKNOWN"

View File

@ -160,14 +160,15 @@ object BerlinGroupSigning extends MdcLoggable {
val certificate = getCertificateFromTppSignatureCertificate(requestHeaders)
X509.validateCertificate(certificate) match {
case Full(true) => // PEM certificate is ok
val digest = generateDigest(body.getOrElse(""))
if(digest == getHeaderValue(RequestHeader.Digest, requestHeaders)) { // Verifying the Hash in the Digest Field
val generatedDigest = generateDigest(body.getOrElse(""))
val requestHeaderDigest = getHeaderValue(RequestHeader.Digest, requestHeaders)
if(generatedDigest == requestHeaderDigest) { // Verifying the Hash in the Digest Field
val signatureHeaderValue = getHeaderValue(RequestHeader.Signature, requestHeaders)
val signature = parseSignatureHeader(signatureHeaderValue).getOrElse("signature", "NONE")
val headersToSign = parseSignatureHeader(signatureHeaderValue).getOrElse("headers", "").split(" ").toList
val headers = headersToSign.map(h =>
if (h.toLowerCase() == RequestHeader.Digest.toLowerCase()) {
s"$h: $digest"
s"$h: $generatedDigest"
} else {
s"$h: ${getHeaderValue(h, requestHeaders)}"
}
@ -183,6 +184,8 @@ object BerlinGroupSigning extends MdcLoggable {
case (false, _) => (Failure(ErrorMessages.X509PublicKeyCannotVerify), forwardResult._2)
}
} else { // The two DIGEST hashes do NOT match, the integrity of the request body is NOT confirmed.
logger.debug(s"Generated digest: $generatedDigest")
logger.debug(s"Request header digest: $requestHeaderDigest")
(Failure(ErrorMessages.X509PublicKeyCannotVerify), forwardResult._2)
}
case Failure(msg, t, c) => (Failure(msg, t, c), forwardResult._2) // PEM certificate is not valid

View File

@ -3,19 +3,22 @@ package code.api.util
import java.text.SimpleDateFormat
import java.util.{Date, UUID}
import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.{ConsentAccessJson, PostConsentJson}
import code.api.util.APIUtil.fullBoxOrException
import code.api.util.ApiRole.{canCreateEntitlementAtAnyBank, canCreateEntitlementAtOneBank}
import code.api.util.BerlinGroupSigning.getHeaderValue
import code.api.util.ErrorMessages.{CouldNotAssignAccountAccess, InvalidConnectorResponse, NoViewReadAccountsBerlinGroup}
import code.api.v3_1_0.{PostConsentBodyCommonJson, PostConsentEntitlementJsonV310, PostConsentViewJsonV310}
import code.api.v5_0_0.HelperInfoJson
import code.api.{APIFailure, Constant, RequestHeader}
import code.api.{APIFailure, APIFailureNewStyle, Constant, RequestHeader}
import code.bankconnectors.Connector
import code.consent
import code.consent.ConsentStatus.ConsentStatus
import code.consent.{ConsentStatus, Consents, MappedConsent}
import code.consumer.Consumers
import code.context.{ConsentAuthContextProvider, UserAuthContextProvider}
import code.entitlement.Entitlement
import code.model.Consumer
import code.scheduler.ConsentScheduler.logger
import code.users.Users
import code.util.Helper.MdcLoggable
import code.util.HydraUtil
@ -600,7 +603,8 @@ object Consent extends MdcLoggable {
case failure@Failure(_, _, _) =>
Future(failure, Some(callContext))
case _ =>
Future(Failure(ErrorMessages.ConsentNotFound + s" ($consentId)"), Some(callContext))
val errorMessage = ErrorMessages.ConsentNotFound + s" ($consentId)"
Future(fullBoxOrException(Empty ~> APIFailureNewStyle(errorMessage, 400, Some(callContext.toLight))), Some(callContext))
}
}
def applyBerlinGroupRules(consentId: Option[String], callContext: CallContext): Future[(Box[User], Option[CallContext])] = {
@ -772,6 +776,9 @@ object Consent extends MdcLoggable {
}
val tppRedirectUri: Option[HTTPParam] = callContext.map(_.requestHeaders).getOrElse(Nil).find(_.name == RequestHeader.`TPP-Redirect-URI`)
val tppNokRedirectUri: Option[HTTPParam] = callContext.map(_.requestHeaders).getOrElse(Nil).find(_.name == RequestHeader.`TPP-Nok-Redirect-URI`)
val xRequestId: Option[HTTPParam] = callContext.map(_.requestHeaders).getOrElse(Nil).find(_.name == RequestHeader.`X-Request-ID`)
val psuDeviceId: Option[HTTPParam] = callContext.map(_.requestHeaders).getOrElse(Nil).find(_.name == RequestHeader.`PSU-Device-ID`)
val psuIpAddress: Option[HTTPParam] = callContext.map(_.requestHeaders).getOrElse(Nil).find(_.name == RequestHeader.`PSU-IP-Address`)
Future.sequence(accounts ::: balances ::: transactions) map { views =>
val json = ConsentJWT(
createdByUserId = user.map(_.userId).getOrElse(""),
@ -782,7 +789,11 @@ object Consent extends MdcLoggable {
iat = currentTimeInSeconds,
nbf = currentTimeInSeconds,
exp = validUntilTimeInSeconds,
request_headers = tppRedirectUri.toList ::: tppNokRedirectUri.toList,
request_headers = tppRedirectUri.toList :::
tppNokRedirectUri.toList :::
xRequestId.toList :::
psuDeviceId.toList :::
psuIpAddress.toList,
name = None,
email = None,
entitlements = Nil,
@ -855,19 +866,18 @@ object Consent extends MdcLoggable {
}
}
}
def updateUserIdOfBerlinGroupConsentJWT(createdByUserId: String,
consent: MappedConsent,
callContext: Option[CallContext]): Future[Box[String]] = {
callContext: Option[CallContext]): Box[String] = {
implicit val dateFormats = CustomJsonFormats.formats
val payloadToUpdate: Box[ConsentJWT] = JwtUtil.getSignedPayloadAsJson(consent.jsonWebToken) // Payload as JSON string
.map(net.liftweb.json.parse(_).extract[ConsentJWT]) // Extract case class
Future {
val updatedPayload = payloadToUpdate.map(i => i.copy(createdByUserId = createdByUserId)) // Update only the field "createdByUserId"
val jwtPayloadAsJson = compactRender(Extraction.decompose(updatedPayload))
val jwtClaims: JWTClaimsSet = JWTClaimsSet.parse(jwtPayloadAsJson)
Full(CertificateUtil.jwtWithHmacProtection(jwtClaims, consent.secret))
}
val updatedPayload = payloadToUpdate.map(i => i.copy(createdByUserId = createdByUserId)) // Update only the field "createdByUserId"
val jwtPayloadAsJson = compactRender(Extraction.decompose(updatedPayload))
val jwtClaims: JWTClaimsSet = JWTClaimsSet.parse(jwtPayloadAsJson)
Full(CertificateUtil.jwtWithHmacProtection(jwtClaims, consent.secret))
}
def createUKConsentJWT(
@ -1036,6 +1046,26 @@ object Consent extends MdcLoggable {
consentsOfBank
}
def expireAllPreviousValidBerlinGroupConsents(consent: MappedConsent, updateTostatus: ConsentStatus): Boolean = {
if(updateTostatus == ConsentStatus.valid &&
consent.apiStandard == ApiVersion.berlinGroupV13.apiStandard) {
MappedConsent.findAll( // Find all
By(MappedConsent.mApiStandard, ApiVersion.berlinGroupV13.apiStandard), // Berlin Group
By(MappedConsent.mRecurringIndicator, true), // recurring
By(MappedConsent.mStatus, ConsentStatus.valid.toString), // and valid consents
By(MappedConsent.mUserId, consent.userId), // for the same PSU
By(MappedConsent.mConsumerId, consent.consumerId), // from the same TPP
).filterNot(_.consentId == consent.consentId) // Exclude current consent
.map{ c => // Set to expired
val changedStatus = c.mStatus(ConsentStatus.expired.toString).mLastActionDate(new Date()).save
if(changedStatus) logger.warn(s"|---> Changed status to ${ConsentStatus.expired.toString} for consent ID: ${c.id}")
changedStatus
}.forall(_ == true)
} else {
true
}
}
/*
// Example Usage
val box1: Box[String] = Full("Hello, World!")

View File

@ -2,6 +2,7 @@ package code.api.util
import java.math.BigInteger
import net.liftweb.common.Box
import org.iban4j.IbanUtil
object HashUtil {
def Sha256Hash(in: String): String = {
@ -25,5 +26,8 @@ object HashUtil {
val hashedText = Sha256Hash(plainText)
println("Password: " + plainText)
println("Hashed password: " + hashedText)
println("BBAN: " + IbanUtil.getBban("AT483200000012345864"))
println("Bank code: " + IbanUtil.getBankCode("AT483200000012345864"))
println("Country code: " + IbanUtil.getCountryCode("AT483200000012345864"))
}
}

View File

@ -1493,11 +1493,11 @@ trait APIMethods510 {
consent <- Future(Consents.consentProvider.vend.updateConsentUser(consentId, user)) map {
i => connectorEmptyResponse(i, cc.callContext)
}
consentJWT <- Consent.updateUserIdOfBerlinGroupConsentJWT(
consentJWT <- Future(Consent.updateUserIdOfBerlinGroupConsentJWT(
consentJson.user_id,
consent,
cc.callContext
) map {
)) map {
i => connectorEmptyResponse(i, cc.callContext)
}
updatedConsent <- Future(Consents.consentProvider.vend.setJsonWebToken(consent.consentId, consentJWT)) map {

View File

@ -30,6 +30,7 @@ object MappedConsentProvider extends ConsentProvider {
override def updateConsentStatus(consentId: String, status: ConsentStatus): Box[MappedConsent] = {
MappedConsent.find(By(MappedConsent.mConsentId, consentId)) match {
case Full(consent) =>
Consent.expireAllPreviousValidBerlinGroupConsents(consent, status)
tryo(consent
.mStatus(status.toString)
.mLastActionDate(now) //maybe not right, but for the create we use the `now`, we need to update it later.

View File

@ -110,7 +110,7 @@ class BerlinGroupConsent extends MdcLoggable with RestHelper with APIMethods510
for {
// Fetch the consent by ID
consent: MappedConsent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
APIUtil.unboxFullOrFail(_, None, s"$ConsentNotFound ($consentId)", 404)
APIUtil.unboxFullOrFail(_, None, s"$ConsentNotFound ($consentId)", 400)
}
// Update the consent JWT with new access details
consentJWT <- Consent.updateAccountAccessOfBerlinGroupConsentJWT(
@ -385,10 +385,17 @@ class BerlinGroupConsent extends MdcLoggable with RestHelper with APIMethods510
*/
private def denyConsentRequestProcess() = {
val consentId = ObpS.param("CONSENT_ID") openOr ("")
Consents.consentProvider.vend.updateConsentStatus(consentId, ConsentStatus.rejected)
S.redirectTo(
s"$redirectUriValue?CONSENT_ID=${consentId}"
)
Consents.consentProvider.vend.getConsentByConsentId(consentId) match {
case Full(consent) if otpValue.is == consent.challenge =>
updateConsentUser(consent)
Consents.consentProvider.vend.updateConsentStatus(consentId, ConsentStatus.rejected)
S.redirectTo(
s"$redirectUriValue?CONSENT_ID=${consentId}"
)
case _ =>
S.error("Cannot bet consent")
}
}
/**
@ -398,6 +405,7 @@ class BerlinGroupConsent extends MdcLoggable with RestHelper with APIMethods510
val consentId = ObpS.param("CONSENT_ID") openOr ("")
Consents.consentProvider.vend.getConsentByConsentId(consentId) match {
case Full(consent) if otpValue.is == consent.challenge =>
updateConsentUser(consent)
Consents.consentProvider.vend.updateConsentStatus(consentId, ConsentStatus.valid)
S.redirectTo(
s"/confirm-bg-consent-request-redirect-uri?CONSENT_ID=${consentId}"
@ -407,6 +415,13 @@ class BerlinGroupConsent extends MdcLoggable with RestHelper with APIMethods510
}
}
private def updateConsentUser(consent: MappedConsent): Box[MappedConsent] = {
val loggedInUser = AuthUser.currentUser.flatMap(_.user.foreign).openOrThrowException(ErrorMessages.UserNotLoggedIn)
Consents.consentProvider.vend.updateConsentUser(consent.consentId, loggedInUser)
val jwt = Consent.updateUserIdOfBerlinGroupConsentJWT(loggedInUser.userId, consent, None).openOrThrowException(ErrorMessages.InvalidConnectorResponse)
Consents.consentProvider.vend.setJsonWebToken(consent.consentId, jwt)
}
private def getTppRedirectUri() = {
val consentId = ObpS.param("CONSENT_ID") openOr ("")
s"$redirectUriValue?CONSENT_ID=${consentId}"

View File

@ -484,7 +484,7 @@ class AccountInformationServiceAISApiTest extends BerlinGroupServerSetupV1_3 wit
scenario("Authentication User, only mocked data, just test succeed", BerlinGroupV1_3, updateConsentsPsuDataTransactionAuthorisation) {
val requestStartConsentAuthorisation = (V1_3_BG / "consents"/"consentId" /"authorisations"/ "AUTHORISATIONID" ).PUT <@ (user1)
val responseStartConsentAuthorisation = makePutRequest(requestStartConsentAuthorisation, """{"scaAuthenticationData":""}""")
responseStartConsentAuthorisation.code should be (400)
responseStartConsentAuthorisation.code should be (403)
}