commit e6cb07cf62015f2aef5683192cf3841686839462
parent 4ea85ec6af7ebbe80427783cc6bcc1dae5a5a79c
Author: MS <ms@taler.net>
Date: Wed, 29 Jul 2020 14:41:40 +0200
Sandbox error management.
Avoid passing private key inside exception objects,
but instead make the exception handler retrieve all
the needed information from the request context.
Diffstat:
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -26,6 +26,7 @@ import io.ktor.http.HttpStatusCode
import io.ktor.request.receiveText
import io.ktor.response.respond
import io.ktor.response.respondText
+import io.ktor.util.AttributeKey
import org.apache.xml.security.binding.xmldsig.RSAKeyValueType
import org.jetbrains.exposed.exceptions.ExposedSQLException
import org.jetbrains.exposed.sql.*
@@ -74,9 +75,7 @@ data class PainParseResult(
open class EbicsRequestError(
val errorText: String,
- val errorCode: String,
- // needed to sign the (error) response.
- val hostAuthPriv: RSAPrivateCrtKey? = null
+ val errorCode: String
) : Exception("EBICS request error: $errorText ($errorCode)")
class EbicsInvalidRequestError : EbicsRequestError(
@@ -586,8 +585,7 @@ private fun handleCct(paymentRequest: String, initiatorName: String, ctx: Reques
logger.warn("Could not insert new payment into the database: ${e}")
throw EbicsRequestError(
"[EBICS_PROCESSING_ERROR] ${e.sqlState}",
- "091116",
- ctx.hostAuthPriv
+ "091116"
)
}
}
@@ -659,7 +657,6 @@ private suspend fun ApplicationCall.handleEbicsHia(header: EbicsUnsecuredRequest
}
}
-
private suspend fun ApplicationCall.handleEbicsIni(header: EbicsUnsecuredRequest.Header, orderData: ByteArray) {
val plainOrderData = InflaterInputStream(orderData.inputStream()).use {
it.readAllBytes()
@@ -783,7 +780,6 @@ private fun ApplicationCall.ensureEbicsHost(requestHostID: String): EbicsHostPub
}
}
-
private suspend fun ApplicationCall.receiveEbicsXml(): Document {
val body: String = receiveText()
LOGGER.debug("Data received: $body")
@@ -792,6 +788,8 @@ private suspend fun ApplicationCall.receiveEbicsXml(): Document {
println("Problematic document was: $requestDocument")
throw EbicsInvalidXmlError()
}
+ val requestedHostID = requestDocument.getElementsByTagName("HostID")
+ this.attributes.put(AttributeKey("RequestedEbicsHostID"), requestedHostID.item(0).nodeValue)
return requestDocument
}
@@ -1090,7 +1088,7 @@ private fun handleEbicsUploadTransactionTransmission(requestContext: RequestCont
throw NotImplementedError()
}
}
-
+// req.header.static.hostID.
private fun makeReqestContext(requestObject: EbicsRequest): RequestContext {
val staticHeader = requestObject.header.static
val requestedHostId = staticHeader.hostID
@@ -1198,7 +1196,6 @@ suspend fun ApplicationCall.ebicsweb() {
"ebicsRequest" -> {
logger.debug("ebicsRequest ${XMLUtil.convertDomToString(requestDocument)}")
val requestObject = requestDocument.toObject<EbicsRequest>()
-
val responseXmlStr = transaction {
// Step 1 of 3: Get information about the host and subscriber
val requestContext = makeReqestContext(requestObject)
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -61,6 +61,7 @@ import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
+import io.ktor.util.AttributeKey
import tech.libeufin.sandbox.PaymentsTable
import tech.libeufin.sandbox.PaymentsTable.amount
import tech.libeufin.sandbox.PaymentsTable.creditorBic
@@ -181,7 +182,6 @@ fun serverMain(dbName: String) {
}
exception<EbicsRequestError> { cause ->
- LOGGER.info("Client EBICS request was invalid")
val resp = EbicsResponse.createForUploadWithError(
cause.errorText,
cause.errorCode,
@@ -190,13 +190,19 @@ fun serverMain(dbName: String) {
// already been caught by the chunking logic.
EbicsTypes.TransactionPhaseType.TRANSFER
)
- if (cause.hostAuthPriv == null)
- throw SandboxError(
- reason = "Cannot sign error response",
- statusCode = HttpStatusCode.InternalServerError
+
+ val hostAuthPriv = transaction {
+ val host = EbicsHostEntity.find {
+ EbicsHostsTable.hostID.upperCase() eq
+ call.attributes.get<String>(AttributeKey("EbicsHostID")).toUpperCase()
+ }.firstOrNull() ?: throw SandboxError(
+ HttpStatusCode.InternalServerError,
+ "Requested Ebics host ID not found."
)
+ CryptoUtil.loadRsaPrivateKey(host.authenticationPrivateKey.bytes)
+ }
call.respondText(
- XMLUtil.signEbicsResponse(resp, cause.hostAuthPriv),
+ XMLUtil.signEbicsResponse(resp, hostAuthPriv),
ContentType.Application.Xml,
HttpStatusCode.OK
)