From 68c5cc093d58807c52822ed3526172d608299dca Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 11 Sep 2023 15:04:48 +0200 Subject: [PATCH 1/7] refactor/added the basic guard for all url parameters --- .../main/scala/bootstrap/liftweb/Boot.scala | 4 +-- .../ResourceDocsAPIMethods.scala | 14 ++++---- .../main/scala/code/api/openidconnect.scala | 7 ++-- .../code/api/sandbox/SandboxApiCalls.scala | 2 +- .../main/scala/code/api/util/APIUtil.scala | 8 ++--- .../main/scala/code/api/util/I18NUtil.scala | 4 +-- .../scala/code/api/v3_0_0/APIMethods300.scala | 18 +++++----- .../scala/code/api/v3_1_0/APIMethods310.scala | 5 +-- .../scala/code/api/v4_0_0/APIMethods400.scala | 9 +++-- .../scala/code/api/v5_1_0/APIMethods510.scala | 5 +-- .../scala/code/management/ImporterAPI.scala | 4 +-- .../code/model/dataAccess/AuthUser.scala | 14 ++++---- .../scala/code/snippet/ConsentScreen.scala | 6 ++-- .../code/snippet/ConsumerRegistration.scala | 4 +-- .../code/snippet/OAuthAuthorisation.scala | 8 ++--- .../code/snippet/OAuthWorkedThanks.scala | 4 +-- .../code/snippet/OpenIDConnectSnippet.scala | 9 +++-- .../main/scala/code/snippet/PaymentOTP.scala | 34 +++++++++---------- .../scala/code/snippet/UserInvitation.scala | 4 +-- .../scala/code/snippet/UserOnBoarding.scala | 22 ++++++------ obp-api/src/main/scala/code/util/Helper.scala | 27 +++++++++++++-- 21 files changed, 117 insertions(+), 95 deletions(-) diff --git a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala index ff7f9c3af4..85572f429a 100644 --- a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala +++ b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala @@ -125,7 +125,7 @@ import code.transactionrequests.{MappedTransactionRequest, MappedTransactionRequ import code.usercustomerlinks.MappedUserCustomerLink import code.userlocks.UserLocks import code.users._ -import code.util.Helper.{MdcLoggable, SILENCE_IS_GOLDEN} +import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN} import code.util.{Helper, HydraUtil} import code.validation.JsonSchemaValidation import code.views.Views @@ -631,7 +631,7 @@ class Boot extends MdcLoggable { // Check to see if the user explicitly requests a new locale // In case it's true we use that value to set up a new cookie value - S.param(PARAM_LOCALE) match { + ObpS.param(PARAM_LOCALE) match { case Full(requestedLocale) if requestedLocale != null && APIUtil.checkShortString(requestedLocale)==SILENCE_IS_GOLDEN => { val computedLocale: Locale = I18NUtil.computeLocale(requestedLocale) AuthUser.getCurrentUser.map(_.user.userPrimaryKey.value) match { diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala index aded4d68d0..75087a8b06 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala @@ -21,7 +21,7 @@ import code.api.v3_0_0.OBPAPI3_0_0 import code.api.v3_1_0.OBPAPI3_1_0 import code.api.v4_0_0.{APIMethods400, OBPAPI4_0_0} import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.github.dwickern.macros.NameOf.nameOf import com.openbankproject.commons.model.{BankId, ListResult, User} import com.openbankproject.commons.model.enums.ContentParam.{ALL, DYNAMIC, STATIC} @@ -941,7 +941,7 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{ def getParams() : (Option[List[ResourceDocTag]], Option[List[String]], Option[String], Option[ContentParam], Option[String], Option[String]) = { - val rawTagsParam = S.param("tags") + val rawTagsParam = ObpS.param("tags") val tags: Option[List[ResourceDocTag]] = @@ -965,7 +965,7 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{ logger.debug(s"tagsOption is $tags") // So we can produce a reduced list of resource docs to prevent manual editing of swagger files. - val rawPartialFunctionNames = S.param("functions") + val rawPartialFunctionNames = ObpS.param("functions") val partialFunctionNames: Option[List[String]] = rawPartialFunctionNames match { @@ -987,23 +987,23 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{ } logger.debug(s"partialFunctionNames is $partialFunctionNames") - val locale = S.param(PARAM_LOCALE).or(S.param("language")) // we used language before, so keep it there. + val locale = ObpS.param(PARAM_LOCALE).or(ObpS.param("language")) // we used language before, so keep it there. logger.debug(s"locale is $locale") // So we can produce a reduced list of resource docs to prevent manual editing of swagger files. val contentParam = for { - x <- S.param("content") + x <- ObpS.param("content") y <- stringToContentParam(x) } yield y logger.debug(s"content is $contentParam") val apiCollectionIdParam = for { - x <- S.param("api-collection-id") + x <- ObpS.param("api-collection-id") } yield x logger.debug(s"apiCollectionIdParam is $apiCollectionIdParam") val cacheModifierParam = for { - x <- S.param("cache-modifier") + x <- ObpS.param("cache-modifier") } yield x logger.debug(s"cacheModifierParam is $cacheModifierParam") diff --git a/obp-api/src/main/scala/code/api/openidconnect.scala b/obp-api/src/main/scala/code/api/openidconnect.scala index 9b6475448f..3702576705 100644 --- a/obp-api/src/main/scala/code/api/openidconnect.scala +++ b/obp-api/src/main/scala/code/api/openidconnect.scala @@ -27,7 +27,6 @@ TESOBE (http://www.tesobe.com/) package code.api import java.net.HttpURLConnection - import code.api.util.APIUtil._ import code.api.util.{APIUtil, AfterApiAuth, ErrorMessages, JwtUtil} import code.consumer.Consumers @@ -37,7 +36,7 @@ import code.model.dataAccess.AuthUser import code.snippet.OpenIDConnectSessionState import code.token.{OpenIDConnectToken, TokensOpenIDConnect} import code.users.Users -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.openbankproject.commons.model.User import com.openbankproject.commons.util.{ApiVersion,ApiVersionStatus} import javax.net.ssl.HttpsURLConnection @@ -182,8 +181,8 @@ object OpenIdConnect extends OBPRestHelper with MdcLoggable { } private def extractParams(s: S): (String, String, String) = { - val code = s.param("code") - val state = s.param("state") + val code = ObpS.param("code") + val state = ObpS.param("state") val sessionState = OpenIDConnectSessionState.get (code.getOrElse(""), state.getOrElse("0"), sessionState.map(_.toString).getOrElse("1")) } diff --git a/obp-api/src/main/scala/code/api/sandbox/SandboxApiCalls.scala b/obp-api/src/main/scala/code/api/sandbox/SandboxApiCalls.scala index 0768dbda3c..9adab10c73 100644 --- a/obp-api/src/main/scala/code/api/sandbox/SandboxApiCalls.scala +++ b/obp-api/src/main/scala/code/api/sandbox/SandboxApiCalls.scala @@ -29,7 +29,7 @@ // logger.debug("Hello from v1.0 data-import") // for{ // correctToken <- APIUtil.getPropsValue("sandbox_data_import_secret") ~> APIFailure("Data import is disabled for this API instance.", 403) -// providedToken <- S.param("secret_token") ~> APIFailure("secret_token parameter required", 403) +// providedToken <- ObpS.param("secret_token") ~> APIFailure("secret_token parameter required", 403) // tokensMatch <- Helper.booleanToBox(providedToken == correctToken) ~> APIFailure("incorrect secret token", 403) // importData <- tryo{json.extract[SandboxDataImport]} ?~ ErrorMessages.InvalidJsonFormat // importWorked <- OBPDataImport.importer.vend.importData(importData) 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 73584eacf2..e6507848c3 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -71,7 +71,7 @@ import code.model.dataAccess.AuthUser import code.sanitycheck.SanityCheck import code.scope.Scope import code.usercustomerlinks.UserCustomerLink -import code.util.Helper.{MdcLoggable, SILENCE_IS_GOLDEN} +import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN} import code.util.{Helper, JsonSchemaUtil} import code.views.{MapperViews, Views} import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue @@ -711,10 +711,10 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ case Full(h) => Full(h) case _ => - S.param(nameOfSpellingParam()) + ObpS.param(nameOfSpellingParam()) } case _ => - S.param(nameOfSpellingParam()) + ObpS.param(nameOfSpellingParam()) } } @@ -3534,7 +3534,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ val brandParameter = "brand" // Use brand in parameter (query or form) - val brand: Option[String] = S.param(brandParameter) match { + val brand: Option[String] = ObpS.param(brandParameter) match { case Full(value) => { // If found, and has a valid format, set the session. if (isValidID(value)) { diff --git a/obp-api/src/main/scala/code/api/util/I18NUtil.scala b/obp-api/src/main/scala/code/api/util/I18NUtil.scala index 116e0277e9..1dbb7e532b 100644 --- a/obp-api/src/main/scala/code/api/util/I18NUtil.scala +++ b/obp-api/src/main/scala/code/api/util/I18NUtil.scala @@ -1,7 +1,7 @@ package code.api.util import code.api.Constant.PARAM_LOCALE -import code.util.Helper.SILENCE_IS_GOLDEN +import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN} import java.util.{Date, Locale} @@ -29,7 +29,7 @@ object I18NUtil extends MdcLoggable { def currentLocale() : Locale = { // Cookie name val localeCookieName = "SELECTED_LOCALE" - S.param(PARAM_LOCALE) match { + ObpS.param(PARAM_LOCALE) match { // 1st choice: Use query parameter as a source of truth if any case Full(requestedLocale) if requestedLocale != null && APIUtil.checkShortString(requestedLocale) == SILENCE_IS_GOLDEN => { val computedLocale = I18NUtil.computeLocale(requestedLocale) diff --git a/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala b/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala index 6576b7ea42..c4872785d4 100644 --- a/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala +++ b/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala @@ -27,7 +27,7 @@ import code.scope.Scope import code.search.elasticsearchWarehouse import code.users.Users import code.util.Helper -import code.util.Helper.{booleanToBox, booleanToFuture} +import code.util.Helper.{booleanToBox, booleanToFuture,ObpS} import code.views.Views import code.views.system.ViewDefinition import com.github.dwickern.macros.NameOf.nameOf @@ -1330,12 +1330,12 @@ trait APIMethods300 { case "banks" :: BankId(bankId) :: "branches" :: Nil JsonGet _ => { cc => { implicit val ec = EndpointContext(Some(cc)) - val limit = S.param("limit") - val offset = S.param("offset") - val city = S.param("city") - val withinMetersOf = S.param("withinMetersOf") - val nearLatitude = S.param("nearLatitude") - val nearLongitude = S.param("nearLongitude") + val limit = ObpS.param("limit") + val offset = ObpS.param("offset") + val city = ObpS.param("city") + val withinMetersOf = ObpS.param("withinMetersOf") + val nearLatitude = ObpS.param("nearLatitude") + val nearLongitude = ObpS.param("nearLongitude") for { (_, callContext) <- getBranchesIsPublic match { case false => authenticatedAccess(cc) @@ -1463,8 +1463,8 @@ trait APIMethods300 { case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet req => { cc => { implicit val ec = EndpointContext(Some(cc)) - val limit = S.param("limit") - val offset = S.param("offset") + val limit = ObpS.param("limit") + val offset = ObpS.param("offset") for { (_, callContext) <- getAtmsIsPublic match { case false => authenticatedAccess(cc) diff --git a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala index 0ba4cd2a3d..9e2bccf12b 100644 --- a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala +++ b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala @@ -13,7 +13,7 @@ import code.api.util.ApiRole._ import code.api.util.ApiTag._ import code.api.util.ErrorMessages.{BankAccountNotFound, _} import code.api.util.ExampleValue._ -import code.api.util.FutureUtil.{EndpointContext} +import code.api.util.FutureUtil.EndpointContext import code.api.util.NewStyle.HttpCode import code.api.util._ import code.api.v1_2_1.{JSONFactory, RateLimiting} @@ -39,6 +39,7 @@ import code.ratelimiting.RateLimitingDI import code.userlocks.{UserLocks, UserLocksProvider} import code.users.Users import code.util.Helper +import code.util.Helper.ObpS import code.views.Views import code.views.system.ViewDefinition import code.webhook.AccountWebhook @@ -5731,7 +5732,7 @@ trait APIMethods310 { lazy val getWebUiProps: OBPEndpoint = { case "management" :: "webui_props":: Nil JsonGet req => { cc => implicit val ec = EndpointContext(Some(cc)) - val active = S.param("active").getOrElse("false") + val active = ObpS.param("active").getOrElse("false") for { (Full(u), callContext) <- authenticatedAccess(cc) invalidMsg = s"""$InvalidFilterParameterFormat `active` must be a boolean, but current `active` value is: ${active} """ diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 41e672a555..1f597dcd43 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -4,7 +4,6 @@ import java.net.URLEncoder import java.text.SimpleDateFormat import java.util import java.util.{Calendar, Date} - import code.DynamicData.{DynamicData, DynamicDataProvider} import code.DynamicEndpoint.DynamicEndpointSwagger import code.accountattribute.AccountAttributeX @@ -44,7 +43,7 @@ import code.api.v4_0_0.JSONFactory400._ import code.api.dynamic.endpoint.helper._ import code.api.dynamic.endpoint.helper.practise.PractiseEndpoint import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo} -import code.api.util.FutureUtil.{EndpointContext} +import code.api.util.FutureUtil.EndpointContext import code.api.v5_0_0.OBPAPI5_0_0 import code.api.{ChargePolicy, Constant, JsonResponseException} import code.apicollection.MappedApiCollectionsProvider @@ -73,7 +72,7 @@ import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{app import code.usercustomerlinks.UserCustomerLink import code.userlocks.UserLocksProvider import code.users.Users -import code.util.Helper.booleanToFuture +import code.util.Helper.{ObpS, booleanToFuture} import code.util.{Helper, JsonSchemaUtil} import code.validation.JsonValidation import code.views.Views @@ -11756,8 +11755,8 @@ trait APIMethods400 { lazy val getAtms : OBPEndpoint = { case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet _ => { cc => implicit val ec = EndpointContext(Some(cc)) - val limit = S.param("limit") - val offset = S.param("offset") + val limit = ObpS.param("limit") + val offset = ObpS.param("offset") for { (_, callContext) <- getAtmsIsPublic match { case false => authenticatedAccess(cc) 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 2194967aca..fadfc14314 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 @@ -27,6 +27,7 @@ import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{app import code.userlocks.UserLocksProvider import code.users.Users import code.util.Helper +import code.util.Helper.ObpS import code.views.Views import code.views.system.{AccountAccess, ViewDefinition} import com.github.dwickern.macros.NameOf.nameOf @@ -1394,8 +1395,8 @@ trait APIMethods510 { lazy val getAtms: OBPEndpoint = { case "banks" :: BankId(bankId) :: "atms" :: Nil JsonGet _ => { cc => implicit val ec = EndpointContext(Some(cc)) - val limit = S.param("limit") - val offset = S.param("offset") + val limit = ObpS.param("limit") + val offset = ObpS.param("offset") for { (_, callContext) <- getAtmsIsPublic match { case false => authenticatedAccess(cc) diff --git a/obp-api/src/main/scala/code/management/ImporterAPI.scala b/obp-api/src/main/scala/code/management/ImporterAPI.scala index 84a4d134ef..d8c8150b71 100644 --- a/obp-api/src/main/scala/code/management/ImporterAPI.scala +++ b/obp-api/src/main/scala/code/management/ImporterAPI.scala @@ -6,7 +6,7 @@ import code.api.util.ErrorMessages._ import code.api.util.{APIUtil, CustomJsonFormats} import code.bankconnectors.Connector import code.tesobe.ErrorMessage -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.openbankproject.commons.model.Transaction import com.openbankproject.commons.model.enums.AccountRoutingScheme import net.liftweb.common.Full @@ -181,7 +181,7 @@ object ImporterAPI extends RestHelper with MdcLoggable { } } - S.param("secret") match { + ObpS.param("secret") match { case Full(s) => { APIUtil.getPropsValue("importer_secret") match { case Full(localS) => diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index f7394da88f..f7d5a387f5 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -42,7 +42,7 @@ import code.snippet.WebUI import code.token.TokensOpenIDConnect import code.users.{UserAgreementProvider, Users} import code.util.Helper -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import code.views.Views import com.openbankproject.commons.model._ import net.liftweb.common._ @@ -439,7 +439,7 @@ import net.liftweb.util.Helpers._ "#loginText * " #> {S.?("log.in")} & "#usernameText * " #> {S.?("username")} & "#passwordText * " #> {S.?("password")} & - "#login_challenge [value]" #> S.param("login_challenge").getOrElse("") & + "#login_challenge [value]" #> ObpS.param("login_challenge").getOrElse("") & "autocomplete=off [autocomplete] " #> APIUtil.getAutocompleteValue & "#recoverPasswordLink * " #> { "a [href]" #> {lostPasswordPath.mkString("/", "/", "")} & @@ -1004,7 +1004,7 @@ def restoreSomeSessions(): Unit = { */ override def login: NodeSeq = { // This query parameter is specific to ORY Hydra login request - val loginChallenge: Box[String] = S.param("login_challenge").or(S.getSessionAttribute("login_challenge")) + val loginChallenge: Box[String] = ObpS.param("login_challenge").or(S.getSessionAttribute("login_challenge")) def redirectUri(): String = { loginRedirect.get match { case Full(url) => @@ -1073,10 +1073,10 @@ def restoreSomeSessions(): Unit = { def loginAction = { if (S.post_?) { - val usernameFromGui = S.param("username").getOrElse("") - val passwordFromGui = S.param("password").getOrElse("") - val usernameEmptyField = S.param("username").map(_.isEmpty()).getOrElse(true) - val passwordEmptyField = S.param("password").map(_.isEmpty()).getOrElse(true) + val usernameFromGui = ObpS.param("username").getOrElse("") + val passwordFromGui = ObpS.param("password").getOrElse("") + val usernameEmptyField = ObpS.param("username").map(_.isEmpty()).getOrElse(true) + val passwordEmptyField = ObpS.param("password").map(_.isEmpty()).getOrElse(true) val emptyField = usernameEmptyField || passwordEmptyField emptyField match { case true => diff --git a/obp-api/src/main/scala/code/snippet/ConsentScreen.scala b/obp-api/src/main/scala/code/snippet/ConsentScreen.scala index 8f5d575799..91ab6ae0f3 100644 --- a/obp-api/src/main/scala/code/snippet/ConsentScreen.scala +++ b/obp-api/src/main/scala/code/snippet/ConsentScreen.scala @@ -28,7 +28,7 @@ package code.snippet import code.api.util.APIUtil import code.model.dataAccess.AuthUser -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import code.util.HydraUtil.integrateWithHydra import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue import net.liftweb.http.{RequestVar, S, SHtml} @@ -41,8 +41,8 @@ import scala.jdk.CollectionConverters.seqAsJavaListConverter class ConsentScreen extends MdcLoggable { private object skipConsentScreenVar extends RequestVar(false) - private object consentChallengeVar extends RequestVar(S.param("consent_challenge").getOrElse("")) - private object csrfVar extends RequestVar(S.param("_csrf").getOrElse("")) + private object consentChallengeVar extends RequestVar(ObpS.param("consent_challenge").getOrElse("")) + private object csrfVar extends RequestVar(ObpS.param("_csrf").getOrElse("")) def submitAllowAction: Unit = { integrateWithHydra match { diff --git a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala index 45513574fa..f5b091f9d9 100644 --- a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala +++ b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala @@ -33,7 +33,7 @@ import code.api.util.{APIUtil, ErrorMessages, X509} import code.consumer.Consumers import code.model.dataAccess.AuthUser import code.model.{Consumer, _} -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import code.util.HydraUtil import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue import net.liftweb.common.{Box, Failure, Full} @@ -478,7 +478,7 @@ class ConsumerRegistration extends MdcLoggable { } def showDummyCustomerTokens(): CssSel = { - val consumerKeyBox = S.param("consumer_key") + val consumerKeyBox = ObpS.param("consumer_key") // The following will check the login user and the user from the consumerkey. we do not want to share consumerkey to others. val loginUserId = AuthUser.getCurrentUser.map(_.userId).openOr("") val userCreatedByUserId = consumerKeyBox.map(Consumers.consumers.vend.getConsumerByConsumerKey(_)).flatten.map(_.createdByUserId.get).openOr("") diff --git a/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala b/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala index 331333108b..17e54c6f73 100644 --- a/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala +++ b/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala @@ -40,7 +40,7 @@ import code.nonce.Nonces import code.token.Tokens import code.users.Users import code.util.Helper -import code.util.Helper.NOOP_SELECTOR +import code.util.Helper.{NOOP_SELECTOR, ObpS} import net.liftweb.common.{Empty, Failure, Full} import net.liftweb.http.S import net.liftweb.util.Helpers._ @@ -58,7 +58,7 @@ object OAuthAuthorisation { val VerifierBlocSel = "#verifierBloc" def shouldNotLogUserOut(): Boolean = { - S.param(LogUserOutParam) match { + ObpS.param(LogUserOutParam) match { case Full("false") => true case Empty => true case _ => false @@ -66,7 +66,7 @@ object OAuthAuthorisation { } def hideFailedLoginMessageIfNeeded() = { - S.param(FailedLoginParam) match { + ObpS.param(FailedLoginParam) match { case Full("true") => NOOP_SELECTOR case _ => ".login-error" #> "" } @@ -161,7 +161,7 @@ object OAuthAuthorisation { //TODO: improve error messages val cssSel = for { - tokenParam <- S.param(TokenName) ?~! "There is no Token." + tokenParam <- ObpS.param(TokenName) ?~! "There is no Token." token <- Tokens.tokens.vend.getTokenByKeyAndType(Helpers.urlDecode(tokenParam.toString), TokenType.Request) ?~! "This token does not exist" tokenValid <- Helper.booleanToBox(token.isValid, "Token expired") } yield { diff --git a/obp-api/src/main/scala/code/snippet/OAuthWorkedThanks.scala b/obp-api/src/main/scala/code/snippet/OAuthWorkedThanks.scala index e0a5d4080c..982b4a4dc7 100644 --- a/obp-api/src/main/scala/code/snippet/OAuthWorkedThanks.scala +++ b/obp-api/src/main/scala/code/snippet/OAuthWorkedThanks.scala @@ -30,7 +30,7 @@ import code.api.OAuthHandshake import code.model.Consumer import code.token.Tokens import code.util.Helper -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import net.liftweb.util.Helpers._ import net.liftweb.http.S import net.liftweb.common.{Box, Full} @@ -45,7 +45,7 @@ import net.liftweb.sitemap.Menu class OAuthWorkedThanks extends MdcLoggable { def thanks = { - val redirectUrl = S.param("redirectUrl").map(urlDecode(_)) + val redirectUrl = ObpS.param("redirectUrl").map(urlDecode(_)) logger.debug(s"OAuthWorkedThanks.thanks.redirectUrl $redirectUrl") //extract the clean(omit the parameters) redirect url from request url val requestedRedirectURL = Helper.extractCleanRedirectURL(redirectUrl.openOr("invalidRequestedRedirectURL")) openOr("invalidRequestedRedirectURL") diff --git a/obp-api/src/main/scala/code/snippet/OpenIDConnectSnippet.scala b/obp-api/src/main/scala/code/snippet/OpenIDConnectSnippet.scala index 1f0e9cfce7..c02186d293 100644 --- a/obp-api/src/main/scala/code/snippet/OpenIDConnectSnippet.scala +++ b/obp-api/src/main/scala/code/snippet/OpenIDConnectSnippet.scala @@ -1,8 +1,7 @@ package code.snippet import code.api.util.APIUtil -import code.util.Helper.MdcLoggable -import net.liftweb.http.S +import code.util.Helper.{MdcLoggable, ObpS} import net.liftweb.util.{CssSel, PassThru} import net.liftweb.util.Helpers._ @@ -26,7 +25,7 @@ class OpenIDConnectSnippet extends MdcLoggable{ "*" #> NodeSeq.Empty // In case of a url ends with something like this: user_mgt/login?login_challenge=f587e7ac91044fe5aa138d6a1ab46250 // we know that we just Hydra OIDC button and ORY Hydra is using OBP-API for login request so hide the OIDC buttons - else if(S.param("login_challenge").isDefined) + else if(ObpS.param("login_challenge").isDefined) "*" #> NodeSeq.Empty else PassThru @@ -36,7 +35,7 @@ class OpenIDConnectSnippet extends MdcLoggable{ "*" #> NodeSeq.Empty // In case of a url ends with something like this: user_mgt/login?login_challenge=f587e7ac91044fe5aa138d6a1ab46250 // we know that we just Hydra OIDC button and ORY Hydra is using OBP-API for login request so hide the OIDC buttons - else if(S.param("login_challenge").isDefined) + else if(ObpS.param("login_challenge").isDefined) "*" #> NodeSeq.Empty else PassThru @@ -48,7 +47,7 @@ class OpenIDConnectSnippet extends MdcLoggable{ "*" #> NodeSeq.Empty // In case of a url ends with something like this: user_mgt/login?login_challenge=f587e7ac91044fe5aa138d6a1ab46250 // we know that we just Hydra OIDC button and ORY Hydra is using OBP-API for login request so hide the OIDC buttons - else if(S.param("login_challenge").isDefined) + else if(ObpS.param("login_challenge").isDefined) "*" #> NodeSeq.Empty else PassThru diff --git a/obp-api/src/main/scala/code/snippet/PaymentOTP.scala b/obp-api/src/main/scala/code/snippet/PaymentOTP.scala index ffd51bde01..993e20d429 100644 --- a/obp-api/src/main/scala/code/snippet/PaymentOTP.scala +++ b/obp-api/src/main/scala/code/snippet/PaymentOTP.scala @@ -34,7 +34,7 @@ import code.api.util.{CallContext, CustomJsonFormats} import code.api.v2_1_0.TransactionRequestWithChargeJSON210 import code.api.v4_0_0.APIMethods400 import code.model.dataAccess.AuthUser -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.openbankproject.commons.util.ReflectUtils import net.liftweb.actor.LAFuture import net.liftweb.common.{Empty, Failure, Full} @@ -68,7 +68,7 @@ class PaymentOTP extends MdcLoggable with RestHelper with APIMethods400 { } def PaymentOTP = { - val result = S.param("flow") match { + val result = ObpS.param("flow") match { case Full("payment") => processPaymentOTP case Full(unSupportedFlow) => Left((s"flow $unSupportedFlow is not correct.", 500)) case _ => Left(("request parameter [flow] is mandatory, please add this parameter in url.", 500)) @@ -93,7 +93,7 @@ class PaymentOTP extends MdcLoggable with RestHelper with APIMethods400 { } } def transactionRequestOTP = { - val result = S.param("flow") match { + val result = ObpS.param("flow") match { case Full("transaction_request") => processTransactionRequestOTP case Full(unSupportedFlow) => Left((s"flow $unSupportedFlow is not correct.", 500)) case _ => Left(("request parameter [flow] is mandatory, please add this parameter in url.", 500)) @@ -119,7 +119,7 @@ class PaymentOTP extends MdcLoggable with RestHelper with APIMethods400 { "#otp-validation-success" #> "" & "#otp-validation-errors .errorContent *" #> "please input OTP value" } else { - S.param("flow") match { + ObpS.param("flow") match { case Full("payment") => PaymentOTP case Full("transaction_request") => transactionRequestOTP case _ => transactionRequestOTP @@ -137,7 +137,7 @@ class PaymentOTP extends MdcLoggable with RestHelper with APIMethods400 { private def processPaymentOTP: Either[(String, Int), String] = { - val requestParam = List(S.param("paymentService"), S.param("paymentProduct"), S.param("paymentId")) + val requestParam = List(ObpS.param("paymentService"), ObpS.param("paymentProduct"), ObpS.param("paymentId")) if(requestParam.count(_.isDefined) < requestParam.size) { return Left(("There are one or many mandatory request parameter not present, please check request parameter: paymentService, paymentProduct, paymentId", 500)) @@ -166,12 +166,12 @@ class PaymentOTP extends MdcLoggable with RestHelper with APIMethods400 { private def processTransactionRequestOTP: Either[(String, Int), String] = { val requestParam = List( - S.param("id"), - S.param("bankId"), - S.param("accountId"), - S.param("viewId"), - S.param("transactionRequestType"), - S.param("transactionRequestId") + ObpS.param("id"), + ObpS.param("bankId"), + ObpS.param("accountId"), + ObpS.param("viewId"), + ObpS.param("transactionRequestType"), + ObpS.param("transactionRequestId") ) if(requestParam.count(_.isDefined) < requestParam.size) { @@ -180,18 +180,18 @@ class PaymentOTP extends MdcLoggable with RestHelper with APIMethods400 { val pathOfEndpoint = List( "banks", - S.param("bankId")openOr(""), + ObpS.param("bankId")openOr(""), "accounts", - S.param("accountId")openOr(""), - S.param("viewId")openOr(""), + ObpS.param("accountId")openOr(""), + ObpS.param("viewId")openOr(""), "transaction-request-types", - S.param("transactionRequestType")openOr(""), + ObpS.param("transactionRequestType")openOr(""), "transaction-requests", - S.param("transactionRequestId")openOr(""), + ObpS.param("transactionRequestId")openOr(""), "challenge" ) - val requestBody = s"""{"id":"${S.param("id").getOrElse("")}","answer":"${otpVar.get}"}""" + val requestBody = s"""{"id":"${ObpS.param("id").getOrElse("")}","answer":"${otpVar.get}"}""" val authorisationsResult = callEndpoint(Implementations4_0_0.answerTransactionRequestChallenge, pathOfEndpoint, PostRequest, requestBody) diff --git a/obp-api/src/main/scala/code/snippet/UserInvitation.scala b/obp-api/src/main/scala/code/snippet/UserInvitation.scala index ad99efb687..cc541ce3c5 100644 --- a/obp-api/src/main/scala/code/snippet/UserInvitation.scala +++ b/obp-api/src/main/scala/code/snippet/UserInvitation.scala @@ -35,7 +35,7 @@ import code.model.dataAccess.{AuthUser, ResourceUser} import code.users import code.users.{UserAgreementProvider, UserInvitationProvider, Users} import code.util.Helper -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue import com.openbankproject.commons.model.User import net.liftweb.common.{Box, Empty, Failure, Full} @@ -70,7 +70,7 @@ class UserInvitation extends MdcLoggable { def registerForm: CssSel = { val secretLink: Box[Long] = tryo { - S.param("id").getOrElse("0").toLong + ObpS.param("id").getOrElse("0").toLong } val userInvitation: Box[users.UserInvitation] = UserInvitationProvider.userInvitationProvider.vend.getUserInvitationBySecretLink(secretLink.getOrElse(0)) firstNameVar.set(userInvitation.map(_.firstName).getOrElse("None")) diff --git a/obp-api/src/main/scala/code/snippet/UserOnBoarding.scala b/obp-api/src/main/scala/code/snippet/UserOnBoarding.scala index 0c066f0a9b..3ba4a03e64 100644 --- a/obp-api/src/main/scala/code/snippet/UserOnBoarding.scala +++ b/obp-api/src/main/scala/code/snippet/UserOnBoarding.scala @@ -30,7 +30,7 @@ import code.api.util.APIUtil._ import code.api.util.ErrorMessages.InvalidJsonFormat import code.api.util.{APIUtil, CustomJsonFormats} import code.api.v3_1_0.{APIMethods310, UserAuthContextUpdateJson} -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.openbankproject.commons.model.UserAuthContextUpdateStatus import net.liftweb.common.Full import net.liftweb.http.rest.RestHelper @@ -52,7 +52,7 @@ class UserOnBoarding extends MdcLoggable with RestHelper with APIMethods310 { def addUserAuthContextUpdateRequest = { - identifierKey.set(S.param("key").openOr(identifierKey.get)) + identifierKey.set(ObpS.param("key").openOr(identifierKey.get)) // CUSTOMER_NUMBER --> Customer Number val inputValue = identifierKey.get.split("_").map(_.toLowerCase.capitalize).mkString(" ") "#add-user-auth-context-update-request-form-title *" #> s"Please enter your ${inputValue}:" & @@ -73,7 +73,7 @@ class UserOnBoarding extends MdcLoggable with RestHelper with APIMethods310 { case Right(response) => { tryo {json.parse(response).extract[UserAuthContextUpdateJson]} match { case Full(userAuthContextUpdateJson) => S.redirectTo( - s"/confirm-user-auth-context-update-request?BANK_ID=${S.param("BANK_ID")openOr("")}&AUTH_CONTEXT_UPDATE_ID=${userAuthContextUpdateJson.user_auth_context_update_id}" + s"/confirm-user-auth-context-update-request?BANK_ID=${ObpS.param("BANK_ID")openOr("")}&AUTH_CONTEXT_UPDATE_ID=${userAuthContextUpdateJson.user_auth_context_update_id}" ) case _ => S.error("identifier-error",s"$InvalidJsonFormat The Json body should be the $UserAuthContextUpdateJson. " + s"Please check `Create User Auth Context Update Request` endpoint separately! ") @@ -102,8 +102,8 @@ class UserOnBoarding extends MdcLoggable with RestHelper with APIMethods310 { private def callCreateUserAuthContextUpdateRequest: Either[(String, Int), String] = { val requestParam = List( - S.param("BANK_ID"), - S.param("SCA_METHOD") + ObpS.param("BANK_ID"), + ObpS.param("SCA_METHOD") ) if(requestParam.count(_.isDefined) < requestParam.size) { @@ -112,11 +112,11 @@ class UserOnBoarding extends MdcLoggable with RestHelper with APIMethods310 { val pathOfEndpoint = List( "banks", - S.param("BANK_ID")openOr(""), + ObpS.param("BANK_ID")openOr(""), "users", "current", "auth-context-updates", - S.param("SCA_METHOD")openOr("") + ObpS.param("SCA_METHOD")openOr("") ) val requestBody = s"""{"key":"${identifierKey.get}","value":"${identifierValue.get}"}""" @@ -129,8 +129,8 @@ class UserOnBoarding extends MdcLoggable with RestHelper with APIMethods310 { private def callConfirmUserAuthContextUpdateRequest: Either[(String, Int), String] = { val requestParam = List( - S.param("BANK_ID"), - S.param("AUTH_CONTEXT_UPDATE_ID") + ObpS.param("BANK_ID"), + ObpS.param("AUTH_CONTEXT_UPDATE_ID") ) if(requestParam.count(_.isDefined) < requestParam.size) { @@ -139,11 +139,11 @@ class UserOnBoarding extends MdcLoggable with RestHelper with APIMethods310 { val pathOfEndpoint = List( "banks", - S.param("BANK_ID")openOr(""), + ObpS.param("BANK_ID")openOr(""), "users", "current", "auth-context-updates", - S.param("AUTH_CONTEXT_UPDATE_ID")openOr(""), + ObpS.param("AUTH_CONTEXT_UPDATE_ID")openOr(""), "challenge" ) diff --git a/obp-api/src/main/scala/code/util/Helper.scala b/obp-api/src/main/scala/code/util/Helper.scala index 4024cee9f2..c990928bf9 100644 --- a/obp-api/src/main/scala/code/util/Helper.scala +++ b/obp-api/src/main/scala/code/util/Helper.scala @@ -20,7 +20,8 @@ import com.openbankproject.commons.util.{ReflectUtils, RequiredFieldValidation, import com.tesobe.CacheKeyFromArguments import net.liftweb.http.S import net.liftweb.util.Helpers - +import net.sf.cglib.proxy.{Enhancer, MethodInterceptor, MethodProxy} +import java.lang.reflect.Method import scala.concurrent.Future import scala.util.Random import scala.reflect.runtime.universe.Type @@ -29,7 +30,7 @@ import scala.concurrent.duration._ -object Helper{ +object Helper extends Loggable { /** * @@ -458,4 +459,26 @@ object Helper{ } } + lazy val ObpS: S = { + val intercept: MethodInterceptor = (_: Any, method: Method, args: Array[AnyRef], _: MethodProxy) => { + + lazy val result = method.invoke(net.liftweb.http.S, args: _*) + val methodName = method.getName + if (methodName.equals("param")&&result.isInstanceOf[Box[String]]&&result.asInstanceOf[Box[String]].isDefined) { + //we provide the basic check for all the parameters + val resultAfterChecked = result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN) + if(resultAfterChecked.isEmpty) + logger.debug(s"ObpS.param validation failed. The input value is:$result") + resultAfterChecked + } else { + result + } + } + + val enhancer: Enhancer = new Enhancer() + enhancer.setSuperclass(classOf[S]) + enhancer.setCallback(intercept) + enhancer.create().asInstanceOf[S] + } + } \ No newline at end of file From e8b15ed2e207f3476e47639b87f099f1769cac3e Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 11 Sep 2023 15:39:02 +0200 Subject: [PATCH 2/7] refactor/added the basic guard for all url parameters-tweaked the log --- obp-api/src/main/scala/code/util/Helper.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/util/Helper.scala b/obp-api/src/main/scala/code/util/Helper.scala index c990928bf9..799cebd42b 100644 --- a/obp-api/src/main/scala/code/util/Helper.scala +++ b/obp-api/src/main/scala/code/util/Helper.scala @@ -467,8 +467,9 @@ object Helper extends Loggable { if (methodName.equals("param")&&result.isInstanceOf[Box[String]]&&result.asInstanceOf[Box[String]].isDefined) { //we provide the basic check for all the parameters val resultAfterChecked = result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN) - if(resultAfterChecked.isEmpty) - logger.debug(s"ObpS.param validation failed. The input value is:$result") + if(resultAfterChecked.isEmpty) { + logger.debug(s"ObpS.param validation failed. The input key is: ${if (args.length>0)args.apply(0) else ""}, value is:$result") + } resultAfterChecked } else { result From cb3f00b648b79e215277324798217e7ea11b87d2 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 12 Sep 2023 16:29:20 +0200 Subject: [PATCH 3/7] test/fixed the failed tests --- obp-api/src/main/scala/code/api/util/APIUtil.scala | 13 +++++++++++++ obp-api/src/main/scala/code/util/Helper.scala | 13 ++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) 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 e6507848c3..d871793e20 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -886,6 +886,19 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ case _ => false } } + + def basicUrlValidation(urlString: String): Boolean = { + //in scala test - org.scalatest.FeatureSpecLike.scenario: + // redirectUrl = http%3A%2F%2Flocalhost%3A8016%3Foauth_token%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461 + // URLDecoder.decode(urlString,"UTF-8")-->http://localhost:8016?oauth_token=EBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK&oauth_verifier=63461 + val regex = + """((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)""".r + val decodeUrlValue = URLDecoder.decode(urlString, "UTF-8").trim() + decodeUrlValue match { + case regex(_*) if (decodeUrlValue.length <= 2048) => true + case _ => false + } + } diff --git a/obp-api/src/main/scala/code/util/Helper.scala b/obp-api/src/main/scala/code/util/Helper.scala index 799cebd42b..1ccd0230fd 100644 --- a/obp-api/src/main/scala/code/util/Helper.scala +++ b/obp-api/src/main/scala/code/util/Helper.scala @@ -466,7 +466,18 @@ object Helper extends Loggable { val methodName = method.getName if (methodName.equals("param")&&result.isInstanceOf[Box[String]]&&result.asInstanceOf[Box[String]].isDefined) { //we provide the basic check for all the parameters - val resultAfterChecked = result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN) + val resultAfterChecked = + if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("username")) { + result.asInstanceOf[Box[String]].filter(APIUtil.checkUsernameString(_)==SILENCE_IS_GOLDEN) + }else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("password")){ + result.asInstanceOf[Box[String]].filter(APIUtil.basicPasswordValidation(_)==SILENCE_IS_GOLDEN) + }else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("consumer_key")){ + result.asInstanceOf[Box[String]].filter(APIUtil.basicConsumerKeyValidation(_)==SILENCE_IS_GOLDEN) + }else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("redirectUrl")){ + result.asInstanceOf[Box[String]].filter(APIUtil.basicUrlValidation(_)) + } else{ + result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN) + } if(resultAfterChecked.isEmpty) { logger.debug(s"ObpS.param validation failed. The input key is: ${if (args.length>0)args.apply(0) else ""}, value is:$result") } From 49d065af20325be2760693ba59bf4c0942c76e68 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 13 Sep 2023 16:21:02 +0200 Subject: [PATCH 4/7] refactor/moved uriAndQueryString to ObpS --- .../src/main/scala/code/api/OBPRestHelper.scala | 4 ++-- .../ResourceDocsAPIMethods.scala | 6 +++--- .../src/main/scala/code/api/util/APIUtil.scala | 16 ++++++++++++++-- .../scala/code/model/dataAccess/AuthUser.scala | 10 +++++----- .../scala/code/snippet/OAuthAuthorisation.scala | 2 +- obp-api/src/main/scala/code/util/Helper.scala | 11 ++++++++++- 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/obp-api/src/main/scala/code/api/OBPRestHelper.scala b/obp-api/src/main/scala/code/api/OBPRestHelper.scala index 42a18cd215..1a5853f75f 100644 --- a/obp-api/src/main/scala/code/api/OBPRestHelper.scala +++ b/obp-api/src/main/scala/code/api/OBPRestHelper.scala @@ -41,7 +41,7 @@ import code.api.v5_0_0.OBPAPI5_0_0 import code.api.v5_1_0.OBPAPI5_1_0 import code.loginattempts.LoginAttempt import code.model.dataAccess.AuthUser -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.alibaba.ttl.TransmittableThreadLocal import com.openbankproject.commons.model.ErrorMessage import com.openbankproject.commons.util.{ApiVersion, ReflectUtils, ScannedApiVersion} @@ -376,7 +376,7 @@ trait OBPRestHelper extends RestHelper with MdcLoggable { val body: Box[String] = getRequestBody(S.request) val implementedInVersion = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).view val verb = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).requestType.method - val url = URLDecoder.decode(S.uriAndQueryString.getOrElse(""),"UTF-8") + val url = URLDecoder.decode(ObpS.uriAndQueryString.getOrElse(""),"UTF-8") val correlationId = getCorrelationId() val reqHeaders = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).request.headers val remoteIpAddress = getRemoteIpAddress() diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala index 75087a8b06..5764e44321 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala @@ -250,7 +250,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider (Some(cacheKey.toString())) (getStaticResourceDocsTTL second) { - logger.debug(s"Generating OBP Resource Docs requestedApiVersion is $requestedApiVersionString") + logger.debug(s"Generating OBP-getStaticResourceDocsObpCached requestedApiVersion is $requestedApiVersionString") val requestedApiVersion = ApiVersionUtils.valueOf(requestedApiVersionString) val resourceDocJson = resourceDocsToResourceDocJson(getResourceDocsList(requestedApiVersion), resourceDocTags, partialFunctionNames, isVersion4OrHigher, locale) @@ -284,7 +284,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider (Some(cacheKey.toString())) (getStaticResourceDocsTTL second) { - logger.debug(s"Generating OBP Resource Docs requestedApiVersion is $requestedApiVersionString") + logger.debug(s"Generating getAllResourceDocsObpCached-Docs requestedApiVersion is $requestedApiVersionString") val requestedApiVersion = ApiVersionUtils.valueOf(requestedApiVersionString) val dynamicDocs = allDynamicResourceDocs @@ -723,7 +723,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider (Some(cacheKey.toString())) (getStaticResourceDocsTTL second) { - logger.debug(s"Generating Swagger requestedApiVersion is $requestedApiVersionString") + logger.debug(s"Generating Swagger-getResourceDocsSwaggerCached requestedApiVersion is $requestedApiVersionString") Box.tryo(ApiVersionUtils.valueOf(requestedApiVersionString)) match { case Full(requestedApiVersion) => 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 d871793e20..2268edfe7d 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -419,7 +419,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ val implementedInVersion = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).view //(GET, POST etc.) --S.request.get.requestType.method val verb = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).requestType.method - val url = S.uriAndQueryString.getOrElse("") + val url = ObpS.uriAndQueryString.getOrElse("") val correlationId = getCorrelationId() //execute saveMetric in future, as we do not need to know result of operation @@ -899,6 +899,18 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ case _ => false } } + + + /** only A-Z, a-z, 0-9,-,_,. =, & and max length <= 2048 */ + def basicUriAndQueryStringValidation(urlString: String): Boolean = { + val regex = + """^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?""".r + val decodeUrlValue = URLDecoder.decode(urlString, "UTF-8").trim() + decodeUrlValue match { + case regex(_*) if (decodeUrlValue.length <= 2048) => true + case _ => false + } + } @@ -3001,7 +3013,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ val body: Box[String] = getRequestBody(S.request) val implementedInVersion = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).view val verb = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).requestType.method - val url = URLDecoder.decode(S.uriAndQueryString.getOrElse(""),"UTF-8") + val url = URLDecoder.decode(ObpS.uriAndQueryString.getOrElse(""),"UTF-8") val correlationId = getCorrelationId() val reqHeaders = S.request.openOrThrowException(attemptedToOpenAnEmptyBox).request.headers val remoteIpAddress = getRemoteIpAddress() diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index f7d5a387f5..de919c28cc 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -744,7 +744,7 @@ import net.liftweb.util.Helpers._ override def signupXhtml (user:AuthUser) = {
-
+

{signupFormTitle}

{legalNoticeDiv}
@@ -786,13 +786,13 @@ import net.liftweb.util.Helpers._ def userLoginFailed = { logger.info("failed: " + failedLoginRedirect.get) // variable redir is from failedLoginRedirect, it is set-up in OAuthAuthorisation.scala as following code: - // val currentUrl = S.uriAndQueryString.getOrElse("/") + // val currentUrl = ObpS.uriAndQueryString.getOrElse("/") // AuthUser.failedLoginRedirect.set(Full(Helpers.appendParams(currentUrl, List((FailedLoginParam, "true"))))) val redir = failedLoginRedirect.get //Check the internal redirect, in case for open redirect issue. // variable redir is from loginRedirect, it is set-up in OAuthAuthorisation.scala as following code: - // val currentUrl = S.uriAndQueryString.getOrElse("/") + // val currentUrl = ObpS.uriAndQueryString.getOrElse("/") // AuthUser.loginRedirect.set(Full(Helpers.appendParams(currentUrl, List((LogUserOutParam, "false"))))) if (Helper.isValidInternalRedirectUrl(redir.toString)) { S.redirectTo(redir.toString) @@ -1016,7 +1016,7 @@ def restoreSomeSessions(): Unit = { } //Check the internal redirect, in case for open redirect issue. // variable redirect is from loginRedirect, it is set-up in OAuthAuthorisation.scala as following code: - // val currentUrl = S.uriAndQueryString.getOrElse("/") + // val currentUrl = ObpS.uriAndQueryString.getOrElse("/") // AuthUser.loginRedirect.set(Full(Helpers.appendParams(currentUrl, List((LogUserOutParam, "false"))))) def checkInternalRedirectAndLogUserIn(preLoginState: () => Unit, redirect: String, user: AuthUser) = { if (Helper.isValidInternalRedirectUrl(redirect)) { @@ -1573,7 +1573,7 @@ def restoreSomeSessions(): Unit = { //Check the internal redirect, in case for open redirect issue. // variable redir is from loginRedirect, it is set-up in OAuthAuthorisation.scala as following code: - // val currentUrl = S.uriAndQueryString.getOrElse("/") + // val currentUrl = ObpS.uriAndQueryString.getOrElse("/") // AuthUser.loginRedirect.set(Full(Helpers.appendParams(currentUrl, List((LogUserOutParam, "false"))))) val loginRedirectSave = loginRedirect.is diff --git a/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala b/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala index 17e54c6f73..a5cfe1e081 100644 --- a/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala +++ b/obp-api/src/main/scala/code/snippet/OAuthAuthorisation.scala @@ -122,7 +122,7 @@ object OAuthAuthorisation { S.redirectTo(appendParams(redirectionUrl, redirectionParam)) } } else { - val currentUrl = S.uriAndQueryString.getOrElse("/") + val currentUrl = ObpS.uriAndQueryString.getOrElse("/") /*if (AuthUser.loggedIn_?) { AuthUser.logUserOut() //Bit of a hack here, but for reasons I haven't had time to discover, if this page doesn't get diff --git a/obp-api/src/main/scala/code/util/Helper.scala b/obp-api/src/main/scala/code/util/Helper.scala index 1ccd0230fd..fdbc0d57af 100644 --- a/obp-api/src/main/scala/code/util/Helper.scala +++ b/obp-api/src/main/scala/code/util/Helper.scala @@ -464,6 +464,7 @@ object Helper extends Loggable { lazy val result = method.invoke(net.liftweb.http.S, args: _*) val methodName = method.getName + if (methodName.equals("param")&&result.isInstanceOf[Box[String]]&&result.asInstanceOf[Box[String]].isDefined) { //we provide the basic check for all the parameters val resultAfterChecked = @@ -479,7 +480,15 @@ object Helper extends Loggable { result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN) } if(resultAfterChecked.isEmpty) { - logger.debug(s"ObpS.param validation failed. The input key is: ${if (args.length>0)args.apply(0) else ""}, value is:$result") + logger.debug(s"ObpS.${methodName} validation failed. The input key is: ${if (args.length>0)args.apply(0) else ""}, value is:$result") + } + resultAfterChecked + } else if (methodName.equals("uri") && result.isInstanceOf[String] || + methodName.equals("uriAndQueryString") && result.isInstanceOf[Box[String]] && result.asInstanceOf[Box[String]].isDefined || + methodName.equals("queryString") && result.isInstanceOf[Box[String]]&&result.asInstanceOf[Box[String]].isDefined){ + val resultAfterChecked = result.asInstanceOf[Box[String]].filter(APIUtil.basicUriAndQueryStringValidation(_)) + if(resultAfterChecked.isEmpty) { + logger.debug(s"ObpS.${methodName} validation failed. The value is:$result") } resultAfterChecked } else { From 6403921b1cf0412ee2102a666b5001bead9cf0e7 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 13 Sep 2023 16:25:11 +0200 Subject: [PATCH 5/7] refactor/moved queryString to ObpS --- .../main/scala/code/model/dataAccess/AuthUser.scala | 2 +- .../src/main/scala/code/snippet/UserInvitation.scala | 2 +- obp-api/src/main/scala/code/snippet/WebUI.scala | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index de919c28cc..917a7cd70f 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -1538,7 +1538,7 @@ def restoreSomeSessions(): Unit = { override def passwordResetXhtml = {
-

{if(S.queryString.isDefined) Helper.i18n("set.your.password") else S.?("reset.your.password")}

+

{if(ObpS.queryString.isDefined) Helper.i18n("set.your.password") else S.?("reset.your.password")}

diff --git a/obp-api/src/main/scala/code/snippet/UserInvitation.scala b/obp-api/src/main/scala/code/snippet/UserInvitation.scala index cc541ce3c5..eab34b28a2 100644 --- a/obp-api/src/main/scala/code/snippet/UserInvitation.scala +++ b/obp-api/src/main/scala/code/snippet/UserInvitation.scala @@ -133,7 +133,7 @@ class UserInvitation extends MdcLoggable { UserInvitationProvider.userInvitationProvider.vend.updateStatusOfUserInvitation(userInvitation.map(_.userInvitationId).getOrElse(""), "FINISHED") // Set a new password // Please note that the query parameter is used to alter the message at password reset page i.e. at next code: - //

{if(S.queryString.isDefined) Helper.i18n("set.your.password") else S.?("reset.your.password")}

+ //

{if(ObpS.queryString.isDefined) Helper.i18n("set.your.password") else S.?("reset.your.password")}

// placed into function AuthZUser.passwordResetXhtml val resetLink = AuthUser.passwordResetUrl(u.idGivenByProvider, u.emailAddress, u.userId) + "?action=set" S.redirectTo(resetLink) diff --git a/obp-api/src/main/scala/code/snippet/WebUI.scala b/obp-api/src/main/scala/code/snippet/WebUI.scala index 24077a284c..2ba7641b04 100644 --- a/obp-api/src/main/scala/code/snippet/WebUI.scala +++ b/obp-api/src/main/scala/code/snippet/WebUI.scala @@ -35,7 +35,7 @@ import code.api.util.APIUtil.{activeBrand, getRemoteIpAddress, getServerUrl} import code.api.util.ApiRole.CanReadGlossary import code.api.util.{APIUtil, ApiRole, CustomJsonFormats, ErrorMessages, I18NUtil, PegdownOptions} import code.model.dataAccess.AuthUser -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable,ObpS} import net.liftweb.http.{LiftRules, S, SessionVar} import net.liftweb.util.Helpers._ import net.liftweb.util.{CssSel, Props} @@ -67,17 +67,17 @@ class WebUI extends MdcLoggable{ def currentPage = { def replaceLocale(replacement: String) = { - S.queryString.isDefined match { + ObpS.queryString.isDefined match { case true => - S.queryString.exists(_.contains("locale=")) match { + ObpS.queryString.exists(_.contains("locale=")) match { case true => - val queryString = S.queryString + val queryString = ObpS.queryString queryString.map( _.replaceAll("locale=en_GB", replacement) .replaceAll("locale=es_ES", replacement) ) case false => - S.queryString.map(i => i + s"&$replacement") + ObpS.queryString.map(i => i + s"&$replacement") } case false => Full(s"$replacement") From 22c796cb4c2e1a94c39b71d7f111db78ba968865 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 13 Sep 2023 17:36:20 +0200 Subject: [PATCH 6/7] refactor/moved uri to ObpS --- obp-api/src/main/scala/code/api/oauth1.0.scala | 6 +++--- .../src/main/scala/code/model/dataAccess/Admin.scala | 3 ++- .../main/scala/code/model/dataAccess/AuthUser.scala | 8 ++++---- obp-api/src/main/scala/code/snippet/Nav.scala | 3 ++- obp-api/src/main/scala/code/snippet/WebUI.scala | 2 +- obp-api/src/main/scala/code/util/Helper.scala | 11 +++++++++-- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/obp-api/src/main/scala/code/api/oauth1.0.scala b/obp-api/src/main/scala/code/api/oauth1.0.scala index c84f226130..3484ff3b0a 100644 --- a/obp-api/src/main/scala/code/api/oauth1.0.scala +++ b/obp-api/src/main/scala/code/api/oauth1.0.scala @@ -39,7 +39,7 @@ import code.model.{Consumer, TokenType, UserX} import code.nonce.Nonces import code.token.Tokens import code.users.Users -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, ObpS} import com.openbankproject.commons.model.User import net.liftweb.common._ import net.liftweb.http.rest.RestHelper @@ -282,7 +282,7 @@ object OAuthHandshake extends RestHelper with MdcLoggable { val sRequest = S.request val urlParams: Map[String, List[String]] = sRequest.map(_.params).getOrElse(Map.empty) - val sUri = S.uri + val sUri = ObpS.uri //are all the necessary OAuth parameters present? val missingParams = missingOAuthParameters(parameters,requestType) @@ -547,7 +547,7 @@ object OAuthHandshake extends RestHelper with MdcLoggable { val sRequest = S.request val urlParams: Map[String, List[String]] = sRequest.map(_.params).getOrElse(Map.empty) - val sUri = S.uri + val sUri = ObpS.uri // Please note that after this point S.request for instance cannot be used directly // If you need it later assign it to some variable and pass it diff --git a/obp-api/src/main/scala/code/model/dataAccess/Admin.scala b/obp-api/src/main/scala/code/model/dataAccess/Admin.scala index 5e9261266e..1aae0567c4 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/Admin.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/Admin.scala @@ -26,6 +26,7 @@ TESOBE (http://www.tesobe.com/) */ package code.model.dataAccess +import code.util.Helper.ObpS import net.liftweb.mapper._ import net.liftweb.common._ import net.liftweb.http.SessionVar @@ -68,7 +69,7 @@ object Admin extends Admin with MetaMegaProtoUser[Admin]{ } override def loginXhtml = { - (
diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index 917a7cd70f..472916ad98 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -435,7 +435,7 @@ import net.liftweb.util.Helpers._ override def loginXhtml = { val loginXml = Templates(List("templates-hidden","_login")).map({ - "form [action]" #> {S.uri} & + "form [action]" #> {ObpS.uri} & "#loginText * " #> {S.?("log.in")} & "#usernameText * " #> {S.?("username")} & "#passwordText * " #> {S.?("password")} & @@ -583,7 +583,7 @@ import net.liftweb.util.Helpers._

Recover Password

Enter your email address or username and we'll email you a link to reset your password
- +
@@ -744,7 +744,7 @@ import net.liftweb.util.Helpers._ override def signupXhtml (user:AuthUser) = {
- +

{signupFormTitle}

{legalNoticeDiv}
@@ -1539,7 +1539,7 @@ def restoreSomeSessions(): Unit = { override def passwordResetXhtml = {

{if(ObpS.queryString.isDefined) Helper.i18n("set.your.password") else S.?("reset.your.password")}

- +
diff --git a/obp-api/src/main/scala/code/snippet/Nav.scala b/obp-api/src/main/scala/code/snippet/Nav.scala index d8667c48a4..47ea20a876 100644 --- a/obp-api/src/main/scala/code/snippet/Nav.scala +++ b/obp-api/src/main/scala/code/snippet/Nav.scala @@ -26,6 +26,7 @@ TESOBE (http://www.tesobe.com/) */ package code.snippet +import code.util.Helper.ObpS import net.liftweb.http.S import net.liftweb.http.LiftRules import net.liftweb.util.Helpers._ @@ -72,7 +73,7 @@ class Nav { } def markIfSelected(href : String) : Box[String]= { - val currentHref = S.uri + val currentHref = ObpS.uri if(href.equals(currentHref)) Full("selected") else Empty } diff --git a/obp-api/src/main/scala/code/snippet/WebUI.scala b/obp-api/src/main/scala/code/snippet/WebUI.scala index 2ba7641b04..59cde07517 100644 --- a/obp-api/src/main/scala/code/snippet/WebUI.scala +++ b/obp-api/src/main/scala/code/snippet/WebUI.scala @@ -89,7 +89,7 @@ class WebUI extends MdcLoggable{ val hyphenLocale = locale.replace("_", "-") if (supportedLocales.contains(locale) || supportedLocales.contains(hyphenLocale) ) {""} else {"none"} } - val page = Constant.HostName + S.uri + val page = Constant.HostName + ObpS.uri val language = I18NUtil.currentLocale().getLanguage() "#es a [href]" #> scala.xml.Unparsed(s"${page}?${replaceLocale("locale=es_ES")}") & diff --git a/obp-api/src/main/scala/code/util/Helper.scala b/obp-api/src/main/scala/code/util/Helper.scala index fdbc0d57af..1a1b7a99c1 100644 --- a/obp-api/src/main/scala/code/util/Helper.scala +++ b/obp-api/src/main/scala/code/util/Helper.scala @@ -483,8 +483,15 @@ object Helper extends Loggable { logger.debug(s"ObpS.${methodName} validation failed. The input key is: ${if (args.length>0)args.apply(0) else ""}, value is:$result") } resultAfterChecked - } else if (methodName.equals("uri") && result.isInstanceOf[String] || - methodName.equals("uriAndQueryString") && result.isInstanceOf[Box[String]] && result.asInstanceOf[Box[String]].isDefined || + } else if (methodName.equals("uri") && result.isInstanceOf[String]){ + val resultAfterChecked = Full(result.asInstanceOf[String]).filter(APIUtil.basicUriAndQueryStringValidation(_)) + if(resultAfterChecked.isDefined) { + resultAfterChecked.head + }else{ + logger.debug(s"ObpS.${methodName} validation failed. The value is:$result") + resultAfterChecked.getOrElse("") + } + } else if (methodName.equals("uriAndQueryString") && result.isInstanceOf[Box[String]] && result.asInstanceOf[Box[String]].isDefined || methodName.equals("queryString") && result.isInstanceOf[Box[String]]&&result.asInstanceOf[Box[String]].isDefined){ val resultAfterChecked = result.asInstanceOf[Box[String]].filter(APIUtil.basicUriAndQueryStringValidation(_)) if(resultAfterChecked.isEmpty) { From 04af535fad59d341f960137db58641f922440991 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 13 Sep 2023 17:39:49 +0200 Subject: [PATCH 7/7] refactor/use param instead of params --- obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index 472916ad98..47796d7c45 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -1588,8 +1588,8 @@ def restoreSomeSessions(): Unit = { case _ => //if the register page url (user_mgt/sign_up?after-signup=link-to-customer) contains the parameter //after-signup=link-to-customer,then it will redirect to the on boarding customer page. - S.params("after-signup") match { - case url if (url.nonEmpty && url.head.equals("link-to-customer")) => + ObpS.param("after-signup") match { + case url if (url.equals("link-to-customer")) => "/add-user-auth-context-update-request" case _ => homePage
Admin Log In
{userNameFieldString}
{S.?("password")}