gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] 01/02: Check subscriber has rights over debtor IBAN


From: gnunet
Subject: [libeufin] 01/02: Check subscriber has rights over debtor IBAN
Date: Tue, 29 Nov 2022 19:44:43 +0100

This is an automated email from the git hooks/post-receive script.

ms pushed a commit to branch master
in repository libeufin.

commit 8c26eab27768ae507a5460770ace216fd43f882c
Author: MS <ms@taler.net>
AuthorDate: Tue Nov 29 18:32:14 2022 +0100

    Check subscriber has rights over debtor IBAN
---
 .../tech/libeufin/nexus/ebics/EbicsClient.kt       |  3 +--
 .../kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt |  2 +-
 .../tech/libeufin/nexus/iso20022/Iso20022.kt       |  6 ++---
 nexus/src/test/kotlin/DownloadAndSubmit.kt         |  7 +++---
 nexus/src/test/kotlin/MakeEnv.kt                   | 27 +++++++++++++++++++---
 .../tech/libeufin/sandbox/EbicsProtocolBackend.kt  | 25 ++++++++++++++++----
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  |  2 +-
 util/src/main/kotlin/Ebics.kt                      |  1 +
 8 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
index 5516e88c..4a7a7c28 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
@@ -238,14 +238,13 @@ suspend fun doEbicsUploadTransaction(
         subscriberDetails.ebicsUrl,
         payload
     )
-
     val txResp = parseAndValidateEbicsResponse(subscriberDetails, txRespStr)
     when (txResp.technicalReturnCode) {
         EbicsReturnCode.EBICS_OK -> {
         }
         else -> {
             throw NexusError(HttpStatusCode.InternalServerError,
-                "Unexpected EBICS return code: ${txResp.technicalReturnCode}"
+                "Unexpected EBICS technical return code: 
${txResp.technicalReturnCode}"
             )
         }
     }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
index ab359a16..726d94f5 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
@@ -180,7 +180,7 @@ private fun getEbicsSubscriberDetailsInternal(subscriber: 
EbicsSubscriberEntity)
 /**
  * Retrieve Ebics subscriber details given a bank connection.
  */
-private fun getEbicsSubscriberDetails(bankConnectionId: String): 
EbicsClientSubscriberDetails {
+fun getEbicsSubscriberDetails(bankConnectionId: String): 
EbicsClientSubscriberDetails {
     val transport = NexusBankConnectionEntity.findByName(bankConnectionId)
     if (transport == null) {
         throw NexusError(HttpStatusCode.NotFound, "transport not found")
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
index 592b7aa1..12045f50 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
@@ -343,15 +343,15 @@ data class NexusPaymentInitiationData(
     val debtorName: String,
     val messageId: String,
     val paymentInformationId: String,
-    val endToEndId: String?,
+    val endToEndId: String? = null,
     val amount: String,
     val currency: String,
     val subject: String,
     val preparationTimestamp: Long,
     val creditorName: String,
     val creditorIban: String,
-    val creditorBic: String?,
-    val instructionId: String?
+    val creditorBic: String? = null,
+    val instructionId: String? = null
 )
 
 /**
diff --git a/nexus/src/test/kotlin/DownloadAndSubmit.kt 
b/nexus/src/test/kotlin/DownloadAndSubmit.kt
index f061b4f9..b7bdc04e 100644
--- a/nexus/src/test/kotlin/DownloadAndSubmit.kt
+++ b/nexus/src/test/kotlin/DownloadAndSubmit.kt
@@ -30,9 +30,8 @@ import tech.libeufin.util.ebics_h004.EbicsTypes
  * This source is NOT a test case -- as it uses no assertions --
  * but merely a tool to download and submit payments to the bank
  * via Nexus.
- * /
-
  */
+
 /**
  * Data to make the test server return for EBICS
  * phases.  Currently only init is supported.
@@ -92,8 +91,8 @@ fun getCustomEbicsServer(r: EbicsResponses, endpoint: String 
= "/ebicsweb"): App
  * and having had access to runTask and TaskSchedule, that
  * are now 'private'.
  */
-// @Ignore
-class SchedulingTest {
+@Ignore
+class DownloadAndSubmit {
     /**
      * Instruct the server to return invalid CAMT content.
      */
diff --git a/nexus/src/test/kotlin/MakeEnv.kt b/nexus/src/test/kotlin/MakeEnv.kt
index 5161650e..b7eb482a 100644
--- a/nexus/src/test/kotlin/MakeEnv.kt
+++ b/nexus/src/test/kotlin/MakeEnv.kt
@@ -18,7 +18,8 @@ data class EbicsKeys(
 const val TEST_DB_FILE = "/tmp/nexus-test.sqlite3"
 const val TEST_DB_CONN = "jdbc:sqlite:$TEST_DB_FILE"
 val BANK_IBAN = getIban()
-val USER_IBAN = getIban()
+val FOO_USER_IBAN = getIban()
+val BAR_USER_IBAN = getIban()
 
 val bankKeys = EbicsKeys(
     auth = CryptoUtil.generateRsaKeyPair(2048),
@@ -86,12 +87,20 @@ fun prepNexusDb() {
         }
         val a = NexusBankAccountEntity.new {
             bankAccountName = "mock-bank-account"
-            iban = USER_IBAN
+            iban = FOO_USER_IBAN
             bankCode = "SANDBOXX"
             defaultBankConnection = c
             highestSeenBankMessageSerialId = 0
             accountHolder = "foo"
         }
+        val b = NexusBankAccountEntity.new {
+            bankAccountName = "bar-bank-account"
+            iban = BAR_USER_IBAN
+            bankCode = "SANDBOXX"
+            defaultBankConnection = c
+            highestSeenBankMessageSerialId = 0
+            accountHolder = "bar"
+        }
     }
 }
 
@@ -122,7 +131,7 @@ fun prepSandboxDb() {
             this.signaturePrivateKey = 
ExposedBlob(bankKeys.sig.private.encoded)
         }
         val bankAccount = BankAccountEntity.new {
-            iban = USER_IBAN
+            iban = FOO_USER_IBAN
             /**
              * For now, keep same semantics of Pybank: a username
              * is AS WELL a bank account label.  In other words, it
@@ -133,6 +142,18 @@ fun prepSandboxDb() {
             this.demoBank = demoBank
             isPublic = false
         }
+        val otherBankAccount = BankAccountEntity.new {
+            iban = BAR_USER_IBAN
+            /**
+             * For now, keep same semantics of Pybank: a username
+             * is AS WELL a bank account label.  In other words, it
+             * identifies a customer AND a bank account.
+             */
+            label = "bar"
+            owner = "bar"
+            this.demoBank = demoBank
+            isPublic = false
+        }
         tech.libeufin.sandbox.EbicsSubscriberEntity.new {
             hostId = "eufinSandbox"
             partnerId = "foo"
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index 5c525d92..19aa31fb 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -81,8 +81,8 @@ class EbicsInvalidRequestError : EbicsRequestError(
     "[EBICS_INVALID_REQUEST] Invalid request",
     "060102"
 )
-class EbicsAccountAuthorisationFailed : EbicsRequestError(
-    "[EBICS_ACCOUNT_AUTHORISATION_FAILED] Subscriber's signature didn't 
verify",
+class EbicsAccountAuthorisationFailed(reason: String) : EbicsRequestError(
+    "[EBICS_ACCOUNT_AUTHORISATION_FAILED] $reason",
     "091302"
 )
 
@@ -702,11 +702,23 @@ private fun parsePain001(paymentRequest: String): 
PainParseResult {
 /**
  * Process a payment request in the pain.001 format.
  */
-private fun handleCct(paymentRequest: String) {
+private fun handleCct(paymentRequest: String,
+                      requestingSubscriber: EbicsSubscriberEntity
+) {
     val parseResult = parsePain001(paymentRequest)
     logger.debug("Handling Pain.001: ${parseResult.pmtInfId}, " +
             "for payment: ${parseResult.subject}")
     transaction(Connection.TRANSACTION_SERIALIZABLE, repetitionAttempts = 10) {
+        // Check that subscriber has a bank account
+        // and that they have rights over the debtor IBAN
+        if (requestingSubscriber.bankAccount == null) throw 
EbicsProcessingError(
+            "Subscriber '${requestingSubscriber.userId}' does not have a bank 
account."
+        )
+        if (requestingSubscriber.bankAccount!!.iban != parseResult.debtorIban) 
throw
+                EbicsAccountAuthorisationFailed(
+                    "Subscriber '${requestingSubscriber.userId}' does not have 
rights" +
+                            " over the debtor IBAN '${parseResult.debtorIban}'"
+                )
         val maybeExist = BankAccountTransactionEntity.find {
             BankAccountTransactionsTable.pmtInfId eq parseResult.pmtInfId
         }.firstOrNull()
@@ -722,6 +734,7 @@ private fun handleCct(paymentRequest: String) {
             "[EBICS_PROCESSING_ERROR] Currency (${parseResult.currency}) not 
supported.",
             "091116"
         )
+        // FIXME: check that debtor IBAN _is_ the requesting subscriber.
         BankAccountTransactionEntity.new {
             account = bankAccount
             demobank = bankAccount.demoBank
@@ -1278,7 +1291,9 @@ private fun 
handleEbicsUploadTransactionTransmission(requestContext: RequestCont
             }
         }
         if (getOrderTypeFromTransactionId(requestTransactionID) == "CCT") {
-            handleCct(unzippedData.toString(Charsets.UTF_8))
+            handleCct(unzippedData.toString(Charsets.UTF_8),
+                requestContext.subscriber
+            )
         }
         return EbicsResponse.createForUploadTransferPhase(
             requestTransactionID,
@@ -1403,7 +1418,7 @@ suspend fun ApplicationCall.ebicsweb() {
                 // Step 2 of 3:  Validate the signature
                 val verifyResult = 
XMLUtil.verifyEbicsDocument(requestDocument, requestContext.clientAuthPub)
                 if (!verifyResult) {
-                    throw EbicsAccountAuthorisationFailed()
+                    throw EbicsAccountAuthorisationFailed("Subscriber's 
signature did not verify")
                 }
                 // Step 3 of 3:  Generate response
                 val ebicsResponse: EbicsResponse = when 
(requestObject.header.mutable.transactionPhase) {
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index fcc4dfc6..a8ddcf68 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -539,7 +539,7 @@ val sandboxApp: Application.() -> Unit = {
             )
         }
         exception<EbicsRequestError> { e ->
-            logger.debug("Handling EbicsRequestError: $e")
+            logger.info("Handling EbicsRequestError: ${e.message}")
             respondEbicsTransfer(call, e.errorText, e.errorCode)
         }
         exception<Throwable> { cause ->
diff --git a/util/src/main/kotlin/Ebics.kt b/util/src/main/kotlin/Ebics.kt
index ae13c72e..8b9070f0 100644
--- a/util/src/main/kotlin/Ebics.kt
+++ b/util/src/main/kotlin/Ebics.kt
@@ -365,6 +365,7 @@ enum class EbicsReturnCode(val errorCode: String) {
     EBICS_TX_SEGMENT_NUMBER_UNDERRUN("011101"),
     EBICS_INVALID_USER_OR_USER_STATE("091002"),
     EBICS_PROCESSING_ERROR("091116"),
+    EBICS_ACCOUNT_AUTHORISATION_FAILED("091302"),
     EBICS_NO_DOWNLOAD_DATA_AVAILABLE("090005");
 
     companion object {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]