[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.