Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions obp-api/src/main/resources/props/sample.props.template
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,10 @@ default_auth_context_update_request_key=CUSTOMER_NUMBER
# Show the path inside of Berlin Group error message
#berlin_group_error_message_show_path = true

# Check presence of the mandatory headers
#berlin_group_mandatory_headers = X-Request-ID,PSU-IP-Address,PSU-Device-ID,PSU-Device-Name
#berlin_group_mandatory_header_consent = TPP-Redirect-URL

## Berlin Group Create Consent Frequency per Day Upper Limit
#berlin_group_frequency_per_day_upper_limit = 4

Expand Down
8 changes: 4 additions & 4 deletions obp-api/src/main/scala/code/api/util/APIUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3244,8 +3244,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val verb = result._2.map(_.verb).getOrElse("None")
val body = result._2.flatMap(_.httpBody)
val reqHeaders = result._2.map(_.requestHeaders).getOrElse(Nil)
// Verify signed request (Berlin Group)
BerlinGroupSigning.verifySignedRequest(body, verb, url, reqHeaders, result)
// Berlin Group checks
BerlinGroupCheck.validate(body, verb, url, reqHeaders, result)
} map {
result =>
val excludeFunctions = getPropsValue("rate_limiting.exclude_endpoints", "root").split(",").toList
Expand Down Expand Up @@ -3300,8 +3300,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val verb = result._2.map(_.verb).getOrElse("None")
val body = result._2.flatMap(_.httpBody)
val reqHeaders = result._2.map(_.requestHeaders).getOrElse(Nil)
// Verify signed request if need be
BerlinGroupSigning.verifySignedRequest(body, verb, url, reqHeaders, result)
// Berlin Group checks
BerlinGroupCheck.validate(body, verb, url, reqHeaders, result)
} map { result =>
result._1 match {
case Empty if result._2.flatMap(_.consumer).isDefined => // There is no error and Consumer is defined
Expand Down
44 changes: 44 additions & 0 deletions obp-api/src/main/scala/code/api/util/BerlinGroupCheck.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package code.api.util

import code.api.RequestHeader
import com.openbankproject.commons.model.User
import net.liftweb.common.{Box, Empty, Failure}
import net.liftweb.http.provider.HTTPParam

object BerlinGroupCheck {

// Parse mandatory headers from a comma-separated string
private val berlinGroupMandatoryHeaders: List[String] = APIUtil.getPropsValue("berlin_group_mandatory_headers", defaultValue = "X-Request-ID,PSU-IP-Address,PSU-Device-ID,PSU-Device-Name")
.split(",")
.map(_.trim.toLowerCase)
.toList.filterNot(_.isEmpty)
private val berlinGroupMandatoryHeaderConsent = APIUtil.getPropsValue("berlin_group_mandatory_header_consent", defaultValue = "TPP-Redirect-URL")
.split(",")
.map(_.trim.toLowerCase)
.toList.filterNot(_.isEmpty)

private def validateHeaders(verb: String, url: String, reqHeaders: List[HTTPParam], forwardResult: (Box[User], Option[CallContext])): (Box[User], Option[CallContext]) = {
val headerMap = reqHeaders.map(h => h.name.toLowerCase -> h).toMap
val missingHeaders = if(url.contains("berlin-group") && url.endsWith("/consent"))
berlinGroupMandatoryHeaders.filterNot(headerMap.contains)
else
(berlinGroupMandatoryHeaders ++ berlinGroupMandatoryHeaderConsent).filterNot(headerMap.contains)

if (missingHeaders.isEmpty) {
forwardResult // All mandatory headers are present
} else {
(Failure(s"Missing mandatory headers: ${missingHeaders.mkString(", ")}"), forwardResult._2)
}
}

def validate(body: Box[String], verb: String, url: String, reqHeaders: List[HTTPParam], forwardResult: (Box[User], Option[CallContext])): (Box[User], Option[CallContext]) = {
validateHeaders(verb, url, reqHeaders, forwardResult) match {
case (user, _) if user.isDefined || user == Empty => // All good. Chain another check
// Verify signed request (Berlin Group)
BerlinGroupSigning.verifySignedRequest(body, verb, url, reqHeaders, forwardResult)
case forwardError => // Forward error case
forwardError
}
}

}
Loading