libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 85a141fba1038430ac7bf23367a56595731740a6
parent 70b95e9aee7d84d835cc25dd512a24d16604f63b
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Tue, 10 Mar 2020 18:15:04 +0100

debugging

Diffstat:
Mcli/python/libeufin-cli | 8++++----
Mnexus/src/main/kotlin/tech/libeufin/nexus/EbicsClient.kt | 4+++-
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 17+++++++++++------
Mutil/src/main/kotlin/Ebics.kt | 33++++++++++++++++-----------------
4 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/cli/python/libeufin-cli b/cli/python/libeufin-cli @@ -114,7 +114,7 @@ def hev(obj, account_id, nexus_base_url): try: resp = get(url) except Exception: - print("Unsuccessful request") + print("Could not reach the bank") return print(resp.content.decode("utf-8")) @@ -714,7 +714,7 @@ def fetch_accounts(ctx, account_id, prepare, nexus_base_url): try: resp = post(url, json=dict()) except Exception: - print("Could not reach the bank") + print("Could not reach the Nexus") return print(resp.content.decode("utf-8")) @@ -735,7 +735,7 @@ def hia(obj, account_id, nexus_base_url): try: resp = post(url) except Exception: - print("Could not reach the bank") + print("Could not reach the Nexus") return print(resp.content.decode("utf-8")) @@ -756,7 +756,7 @@ def sync(obj, account_id, nexus_base_url): try: resp = post(url) except Exception: - print("Could not reach the bank") + print("Could not reach the Nexus") return print(resp.content.decode("utf-8")) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsClient.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsClient.kt @@ -8,7 +8,7 @@ import java.util.* suspend inline fun HttpClient.postToBank(url: String, body: String): String { logger.debug("Posting: $body") - val response = try { + val response: String = try { this.post<String>( urlString = url, block = { @@ -18,6 +18,7 @@ suspend inline fun HttpClient.postToBank(url: String, body: String): String { } catch (e: Exception) { throw NexusError(HttpStatusCode.InternalServerError, "Cannot reach the bank") } + logger.debug("Receiving: $response") return response } @@ -66,6 +67,7 @@ suspend fun doEbicsDownloadTransaction( // Success, nothing to do! } else -> { + logger.warn("Bank return code was: ${initResponse.bankReturnCode}") return EbicsDownloadBankErrorResult(initResponse.bankReturnCode) } } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -49,7 +49,6 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.slf4j.event.Level import tech.libeufin.util.* -import tech.libeufin.util.InvalidSubscriberStateError import tech.libeufin.util.ebics_h004.EbicsTypes import tech.libeufin.util.ebics_h004.HTDResponseOrderData import java.lang.StringBuilder @@ -58,7 +57,6 @@ import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* import javax.crypto.EncryptedPrivateKeyInfo -import javax.print.attribute.standard.JobStateReason import javax.sql.rowset.serial.SerialBlob fun testData() { @@ -85,7 +83,6 @@ fun testData() { data class NexusError(val statusCode: HttpStatusCode, val reason: String) : Exception() - val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus") fun getSubscriberEntityFromId(id: String): EbicsSubscriberEntity { @@ -309,11 +306,18 @@ fun main() { cause.statusCode ) } - + exception<UtilError> { cause -> + logger.error("Exception while handling '${call.request.uri}'", cause) + call.respondText( + cause.reason, + ContentType.Text.Plain, + cause.statusCode + ) + } exception<javax.xml.bind.UnmarshalException> { cause -> logger.error("Exception while handling '${call.request.uri}'", cause) call.respondText( - "Could not convert string into JAXB (either from client or from bank)\n", + "Could not convert string into JAXB\n", ContentType.Text.Plain, HttpStatusCode.NotFound ) @@ -500,7 +504,8 @@ fun main() { call.respondText( response.orderData.toString(Charsets.UTF_8), ContentType.Text.Plain, - HttpStatusCode.OK) + HttpStatusCode.OK + ) else -> call.respond(NexusErrorJson("Could not download any PAIN.002")) } return@post diff --git a/util/src/main/kotlin/Ebics.kt b/util/src/main/kotlin/Ebics.kt @@ -24,6 +24,7 @@ package tech.libeufin.util +import io.ktor.http.HttpStatusCode import tech.libeufin.util.ebics_h004.* import tech.libeufin.util.ebics_hev.HEVRequest import tech.libeufin.util.ebics_hev.HEVResponse @@ -37,11 +38,7 @@ import java.util.* import java.util.zip.DeflaterInputStream import javax.xml.datatype.DatatypeFactory -class InvalidSubscriberStateError : Exception("Invalid EBICS subscriber state") -class InvalidXmlError : Exception("Invalid EBICS XML") -class BadSignatureError : Exception("Invalid EBICS XML Signature") -class EbicsUnknownReturnCodeError(msg: String) : Exception(msg) - +data class UtilError(val statusCode: HttpStatusCode, val reason: String) : Exception() data class EbicsDateRange(val start: LocalDate, val end: LocalDate) sealed class EbicsOrderParams @@ -240,8 +237,8 @@ fun createEbicsRequestForDownloadInitialization( subscriberDetails.hostId, getNonce(128), DatatypeFactory.newInstance().newXMLGregorianCalendar(GregorianCalendar()), - subscriberDetails.bankEncPub ?: throw InvalidSubscriberStateError(), - subscriberDetails.bankAuthPub ?: throw InvalidSubscriberStateError(), + subscriberDetails.bankEncPub ?: throw UtilError(HttpStatusCode.BadRequest, "Invalid subscriber state 'bankEncPub' missing, please send HPB first"), + subscriberDetails.bankAuthPub ?: throw UtilError(HttpStatusCode.BadRequest, "Invalid subscriber state 'bankAuthPub' missing, please send HPB first"), orderType, makeOrderParams(orderParams) ) @@ -308,7 +305,7 @@ enum class EbicsReturnCode(val errorCode: String) { return x; } } - throw EbicsUnknownReturnCodeError("Unknown return code: $errorCode") + throw UtilError(HttpStatusCode.InternalServerError, "Unknown EBICS status code: $errorCode") } } } @@ -334,14 +331,16 @@ fun parseAndDecryptEbicsKeyManagementResponse( val resp = try { XMLUtil.convertStringToJaxb<EbicsKeyManagementResponse>(responseStr) } catch (e: Exception) { - throw InvalidXmlError() + throw UtilError(HttpStatusCode.InternalServerError, "Invalid XML received from bank") } val retCode = EbicsReturnCode.lookup(resp.value.header.mutable.returnCode) val daeXml = resp.value.body.dataTransfer?.dataEncryptionInfo val orderData = if (daeXml != null) { val dae = DataEncryptionInfo(daeXml.transactionKey, daeXml.encryptionPubKeyDigest.value) - val encOrderData = resp.value.body.dataTransfer?.orderData?.value ?: throw InvalidXmlError() + val encOrderData = resp.value.body.dataTransfer?.orderData?.value ?: throw UtilError( + HttpStatusCode.InternalServerError, "Invalid XML/orderData received from bank" + ) decryptAndDecompressResponse(subscriberDetails, dae, listOf(encOrderData)) } else { null @@ -365,7 +364,7 @@ fun parseEbicsHpbOrder(orderDataRaw: ByteArray): HpbResponseData { val resp = try { XMLUtil.convertStringToJaxb<HPBResponseOrderData>(orderDataRaw.toString(Charsets.UTF_8)) } catch (e: Exception) { - throw InvalidXmlError() + throw UtilError(HttpStatusCode.InternalServerError, "Invalid XML (as HPB response) received from bank") } val encPubKey = CryptoUtil.loadRsaPublicKeyFromComponents( resp.value.encryptionPubKeyInfo.pubKeyValue.rsaKeyValue.modulus, @@ -391,20 +390,20 @@ fun parseAndValidateEbicsResponse( val responseDocument = try { XMLUtil.parseStringIntoDom(responseStr) } catch (e: Exception) { - throw InvalidXmlError() + throw UtilError(HttpStatusCode.InternalServerError, "Invalid XML (as EbicsResponse) received from bank") } if (!XMLUtil.verifyEbicsDocument( responseDocument, - subscriberDetails.bankAuthPub ?: throw InvalidSubscriberStateError() + subscriberDetails.bankAuthPub ?: throw UtilError(HttpStatusCode.BadRequest, "Invalid subscriber state: bankAuthPub missing, please send HPB first") ) ) { - throw BadSignatureError() + throw UtilError(HttpStatusCode.InternalServerError, "Bank's signature validation failed") } val resp = try { XMLUtil.convertStringToJaxb<EbicsResponse>(responseStr) } catch (e: Exception) { - throw InvalidXmlError() + throw UtilError(HttpStatusCode.InternalServerError, "Could not transform string-response from bank into JAXB") } val bankReturnCodeStr = resp.value.body.returnCode.value @@ -443,7 +442,7 @@ fun getDecryptionKey(subscriberDetails: EbicsClientSubscriberDetails, pubDigest: if (pubDigest.contentEquals(encPubDigest)) { return subscriberDetails.customerEncPriv } - throw Exception("no matching private key to decrypt response") + throw UtilError(HttpStatusCode.NotFound,"Could not find customer's public key") } /** @@ -494,7 +493,7 @@ fun parseEbicsHEVResponse(respStr: String): EbicsHevDetails { XMLUtil.convertStringToJaxb<HEVResponse>(respStr) } catch (e: Exception) { logger.error("Exception while parsing HEV response", e) - throw InvalidXmlError() + throw UtilError(HttpStatusCode.InternalServerError, "Invalid HEV received from bank") } val versions = resp.value.versionNumber.map { versionNumber -> EbicsVersionSpec(versionNumber.protocolVersion, versionNumber.value)