From c76d587b86521181de896a39cba37cf2a4e16641 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 22 Jan 2025 16:49:31 +0800 Subject: [PATCH] feature/added confirm-vrp-consent pages - WIP --- .../main/scala/bootstrap/liftweb/Boot.scala | 4 +- .../code/snippet/VrpConsentCreation.scala | 157 ++++++++++++++++++ obp-api/src/main/scala/code/util/Helper.scala | 10 +- .../webapp/confirm-vrp-consent-request.html | 55 ++++++ .../src/main/webapp/confirm-vrp-consent.html | 52 ++++++ obp-api/src/main/webapp/media/css/website.css | 4 + 6 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 obp-api/src/main/scala/code/snippet/VrpConsentCreation.scala create mode 100644 obp-api/src/main/webapp/confirm-vrp-consent-request.html create mode 100644 obp-api/src/main/webapp/confirm-vrp-consent.html diff --git a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala index 075c5ef62..88aa9229b 100644 --- a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala +++ b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala @@ -593,7 +593,9 @@ class Boot extends MdcLoggable { OAuthWorkedThanks.menu, //OAuth thanks page that will do the redirect Menu.i("Introduction") / "introduction", Menu.i("add-user-auth-context-update-request") / "add-user-auth-context-update-request", - Menu.i("confirm-user-auth-context-update-request") / "confirm-user-auth-context-update-request" + Menu.i("confirm-user-auth-context-update-request") / "confirm-user-auth-context-update-request", + Menu.i("confirm-vrp-consent-request") / "confirm-vrp-consent-request" >> AuthUser.loginFirst,//OAuth consent page, + Menu.i("confirm-vrp-consent") / "confirm-vrp-consent" >> AuthUser.loginFirst //OAuth consent page ) ++ accountCreation ++ Admin.menus // Build SiteMap diff --git a/obp-api/src/main/scala/code/snippet/VrpConsentCreation.scala b/obp-api/src/main/scala/code/snippet/VrpConsentCreation.scala new file mode 100644 index 000000000..b93c22a7f --- /dev/null +++ b/obp-api/src/main/scala/code/snippet/VrpConsentCreation.scala @@ -0,0 +1,157 @@ +/** +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 . + +Email: contact@tesobe.com +TESOBE GmbH. +Osloer Strasse 16/17 +Berlin 13359, Germany + +This product includes software developed at +TESOBE (http://www.tesobe.com/) + + */ +package code.snippet + +import code.api.util.APIUtil._ +import code.api.util.ErrorMessages.InvalidJsonFormat +import code.api.util.CustomJsonFormats +import code.api.v5_0_0.{APIMethods500, ConsentRequestResponseJson} +import code.api.v3_1_0.{APIMethods310, ConsentChallengeJsonV310} +import code.consent.ConsentStatus +import code.util.Helper.{MdcLoggable, ObpS} +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import net.liftweb.http.{GetRequest, PostRequest, RequestVar, S, SHtml} +import net.liftweb.json +import net.liftweb.json.Formats +import net.liftweb.util.Helpers._ + +class VrpConsentCreation extends MdcLoggable with RestHelper with APIMethods500 with APIMethods310 { + protected implicit override def formats: Formats = CustomJsonFormats.formats + + private object otpValue extends RequestVar("123456") + + def confirmVrpConsentRequest = { + getConsentRequest match { + case Left(error) => { + "#confirm-vrp-consent-request-form-title *" #> s"Please enter your consent request info:" & + "#confirm-vrp-consent-request-response-json *" #> s"""$error""" & + "type=submit" #> "" + } + case Right(response) => { + tryo {json.parse(response).extract[ConsentRequestResponseJson]} match { + case Full(consentRequestResponseJson) => + "#confirm-vrp-consent-request-form-title *" #> s"Please enter your consent request info:" & + "#confirm-vrp-consent-request-response-json *" #> s"""${json.prettyRender(json.Extraction.decompose(consentRequestResponseJson.payload))}""" & + "#confirm-vrp-consent-request-confirm-submit-button" #> SHtml.onSubmitUnit(confirmConsentRequestProcess)& + "#confirm-vrp-consent-request-deny-submit-button" #> SHtml.onSubmitUnit(denyConsentRequestProcess) + case _ => + "#confirm-vrp-consent-request-form-title *" #> s"Please enter your consent request info:" & + "#confirm-vrp-consent-request-response-json *" #> + s"""$InvalidJsonFormat The Json body should be the $ConsentRequestResponseJson. + |Please check `Get Consent Request` endpoint separately! """.stripMargin & + "type=submit" #> "" + } + } + } + + } + + def confirmVrpConsent = { + "#otp-value" #> SHtml.textElem(otpValue) & + "type=submit" #> SHtml.onSubmitUnit(confirmVrpConsentProcess) + } + + private def confirmConsentRequestProcess() ={ + //1st: we need to call `Create Consent By CONSENT_REQUEST_ID (IMPLICIT)`, this will send OTP to account owner. + + //2nd: we need to redirect to confirm page to fill the OTP + + S.redirectTo( + s"/confirm-vrp-consent" + ) + } + private def denyConsentRequestProcess() ={ + S.redirectTo( + s"/" // if click deny, we just redirect to Home page. + ) + } + + private def callAnswerConsentChallenge: Either[(String, Int), String] = { + + val requestParam = List( + ObpS.param("BANK_ID"), + ObpS.param("CONSENT_ID") + ) + + if(requestParam.count(_.isDefined) < requestParam.size) { + return Left(("There are one or many mandatory request parameter not present, please check request parameter: BANK_ID, CONSENT_ID", 500)) + } + + val pathOfEndpoint = List( + "banks", + ObpS.param("BANK_ID")openOr(""), + "consents", + ObpS.param("CONSENT_ID")openOr(""), + "challenge" + ) + + val requestBody = s"""{"answer":"${otpValue.get}"}""" + val authorisationsResult = callEndpoint(Implementations3_1_0.answerConsentChallenge, pathOfEndpoint, PostRequest, requestBody) + + authorisationsResult + + } + + private def confirmVrpConsentProcess() ={ + callAnswerConsentChallenge match { + case Left(error) => S.error("otp-value-error",error._1) + case Right(response) => { + tryo {json.parse(response).extract[ConsentChallengeJsonV310]} match { + case Full(consentChallengeJsonV310) if (consentChallengeJsonV310.status.equals(ConsentStatus.ACCEPTED.toString)) => + S.redirectTo("/") + case Full(consentChallengeJsonV310) => + S.error("otp-value-error",s"Current SCA status is ${consentChallengeJsonV310.status}. Please double check OTP value.") + case _ => S.error("otp-value-error",s"$InvalidJsonFormat The Json body should be the $ConsentChallengeJsonV310. " + + s"Please check `Create User Auth Context Update Request` endpoint separately! ") + } + } + } + } + + private def getConsentRequest: Either[(String, Int), String] = { + + val requestParam = List( + ObpS.param("CONSENT_REQUEST_ID"), + ) + + if(requestParam.count(_.isDefined) < requestParam.size) { + return Left(("Parameter CONSENT_REQUEST_ID is missing, please set it in the URL", 500)) + } + + val pathOfEndpoint = List( + "consumer", + "consent-requests", + ObpS.param("CONSENT_REQUEST_ID")openOr("") + ) + + val authorisationsResult = callEndpoint(Implementations5_0_0.getConsentRequest, pathOfEndpoint, GetRequest) + + authorisationsResult + } + +} diff --git a/obp-api/src/main/scala/code/util/Helper.scala b/obp-api/src/main/scala/code/util/Helper.scala index 084d68729..74e44e83e 100644 --- a/obp-api/src/main/scala/code/util/Helper.scala +++ b/obp-api/src/main/scala/code/util/Helper.scala @@ -212,18 +212,22 @@ object Helper extends Loggable { */ def isValidInternalRedirectUrl(url: String) : Boolean = { //set the default value is "/" and "/oauth/authorize" - val validUrls = List( + val internalRedirectUrlsWhiteList = List( "/","/oauth/authorize","/consumer-registration", "/dummy-user-tokens","/create-sandbox-account", "/add-user-auth-context-update-request","/otp", - "/terms-and-conditions", "/privacy-policy" + "/terms-and-conditions", "/privacy-policy", + "/confirm-vrp-consent-request", + "/confirm-vrp-consent", + "/consent-screen", + "/consent", ) //case1: OBP-API login: url = "/" //case2: API-Explore oauth login: url = "/oauth/authorize?oauth_token=V0JTCDYXWUNTXDZ3VUDNM1HE3Q1PZR2WJ4PURXQA&logUserOut=false" val extractCleanURL = StringUtils.substringBefore(url, "?") - validUrls.contains(extractCleanURL) + internalRedirectUrlsWhiteList.contains(extractCleanURL) } /** diff --git a/obp-api/src/main/webapp/confirm-vrp-consent-request.html b/obp-api/src/main/webapp/confirm-vrp-consent-request.html new file mode 100644 index 000000000..b0758ca55 --- /dev/null +++ b/obp-api/src/main/webapp/confirm-vrp-consent-request.html @@ -0,0 +1,55 @@ + + +
+ + +
+ diff --git a/obp-api/src/main/webapp/confirm-vrp-consent.html b/obp-api/src/main/webapp/confirm-vrp-consent.html new file mode 100644 index 000000000..4d091950e --- /dev/null +++ b/obp-api/src/main/webapp/confirm-vrp-consent.html @@ -0,0 +1,52 @@ + + +
+
+ +
+
+ diff --git a/obp-api/src/main/webapp/media/css/website.css b/obp-api/src/main/webapp/media/css/website.css index a047207c4..b8742d527 100644 --- a/obp-api/src/main/webapp/media/css/website.css +++ b/obp-api/src/main/webapp/media/css/website.css @@ -437,4 +437,8 @@ input{ color: #333333; line-height: 24px; margin-bottom: 15px; +} + +#confirm-vrp-consent-request-deny-submit-button { + background: red; } \ No newline at end of file