diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala b/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala index 837175941..b0310910b 100644 --- a/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala +++ b/obp-api/src/main/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApi.scala @@ -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) { diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala b/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala index c8eb32a96..5c073c79d 100644 --- a/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala +++ b/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala @@ -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() ) diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1_3/SigningBasketsApi.scala b/obp-api/src/main/scala/code/api/berlin/group/v1_3/SigningBasketsApi.scala index 5d041bc3a..905d2d549 100644 --- a/obp-api/src/main/scala/code/api/berlin/group/v1_3/SigningBasketsApi.scala +++ b/obp-api/src/main/scala/code/api/berlin/group/v1_3/SigningBasketsApi.scala @@ -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 { diff --git a/obp-api/src/main/scala/code/api/constant/constant.scala b/obp-api/src/main/scala/code/api/constant/constant.scala index 97fa6ddab..3fba160ed 100644 --- a/obp-api/src/main/scala/code/api/constant/constant.scala +++ b/obp-api/src/main/scala/code/api/constant/constant.scala @@ -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. diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala index 5ba84c140..f4acc2ccc 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -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 diff --git a/obp-api/src/main/scala/code/api/util/BerlinGroupError.scala b/obp-api/src/main/scala/code/api/util/BerlinGroupError.scala index e39065907..738ebd758 100644 --- a/obp-api/src/main/scala/code/api/util/BerlinGroupError.scala +++ b/obp-api/src/main/scala/code/api/util/BerlinGroupError.scala @@ -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" diff --git a/obp-api/src/main/scala/code/api/util/BerlinGroupSigning.scala b/obp-api/src/main/scala/code/api/util/BerlinGroupSigning.scala index ce97f3451..616310745 100644 --- a/obp-api/src/main/scala/code/api/util/BerlinGroupSigning.scala +++ b/obp-api/src/main/scala/code/api/util/BerlinGroupSigning.scala @@ -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 diff --git a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala index db2c6ea75..83a3ca225 100644 --- a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala +++ b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala @@ -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!") diff --git a/obp-api/src/main/scala/code/api/util/HashUtil.scala b/obp-api/src/main/scala/code/api/util/HashUtil.scala index e7960564e..6fb85eaea 100644 --- a/obp-api/src/main/scala/code/api/util/HashUtil.scala +++ b/obp-api/src/main/scala/code/api/util/HashUtil.scala @@ -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")) } } diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 7112b89a8..a7885cfba 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -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 { diff --git a/obp-api/src/main/scala/code/consent/MappedConsent.scala b/obp-api/src/main/scala/code/consent/MappedConsent.scala index 2b10dba67..072b1d50b 100644 --- a/obp-api/src/main/scala/code/consent/MappedConsent.scala +++ b/obp-api/src/main/scala/code/consent/MappedConsent.scala @@ -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. diff --git a/obp-api/src/main/scala/code/snippet/BerlinGroupConsent.scala b/obp-api/src/main/scala/code/snippet/BerlinGroupConsent.scala index 6f73a0034..d27b96636 100644 --- a/obp-api/src/main/scala/code/snippet/BerlinGroupConsent.scala +++ b/obp-api/src/main/scala/code/snippet/BerlinGroupConsent.scala @@ -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}" diff --git a/obp-api/src/test/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApiTest.scala b/obp-api/src/test/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApiTest.scala index 9e993fc2a..a413c86f7 100644 --- a/obp-api/src/test/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApiTest.scala +++ b/obp-api/src/test/scala/code/api/berlin/group/v1_3/AccountInformationServiceAISApiTest.scala @@ -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) }