commit 3dbdedda04dc3014c5bfe18b5689c42e2e04efb4
parent d3ef68d4dd63c8b9e3dd59d40c70ff88d547b086
Author: Antoine A <>
Date: Wed, 8 Oct 2025 15:22:46 +0200
bank: combine redundant mfa challenges
Diffstat:
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/auth/mfa.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/mfa.kt
@@ -56,10 +56,15 @@ private suspend fun ApplicationCall.respondChallenges(
tanChannel = channel,
tanInfo = info
)
+ val privateInfo = if (op == Operation.create_token) {
+ "REDACTED"
+ } else {
+ info
+ }
challenges.add(Challenge(
challenge_id = uuid.toString(),
tan_channel = channel,
- tan_info = info
+ tan_info = privateInfo
))
}
return challenges
@@ -78,9 +83,6 @@ suspend fun ApplicationCall.respondMfa(
) {
val info = this.bankInfo(db)
var challenges = respondChallenges(db, op, info.mfa)
- if (op == Operation.create_token) {
- challenges = challenges.map { it.copy(tan_info="REDACTED") }
- }
respond(
status = HttpStatusCode.Accepted,
message = ChallengeResponse(
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
@@ -311,7 +311,13 @@ class AccountDAO(private val db: Database) {
if (!isAdmin && !is2fa) {
// Check if mfa is required
if (curr.channels.isNotEmpty()) {
- return@serializableTransaction AccountPatchResult.Challenges(emptyList())
+ val tans = curr.mfa;
+ if (tans.size == 1) {
+ // Perform mfa and validation at the same time
+ return@serializableTransaction AccountPatchResult.Challenges(validations + tans)
+ } else {
+ return@serializableTransaction AccountPatchResult.Challenges(emptyList())
+ }
}
// Check if validation is required
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -2106,29 +2106,26 @@ class CoreBankTanApiTest {
json { // Info change
"contact_data" to obj { "phone" to "+98" }
}
- }.expectMfa(TanChannel.sms to "+99")
- .expectValidation(TanChannel.sms to "+98")
+ }.expectValidation(TanChannel.sms to "+99", TanChannel.sms to "+98")
.assertNoContent()
client.patchA("/accounts/merchant") {
json { // Channel change
"tan_channel" to "email"
}
- }.expectMfa(TanChannel.sms to "+98")
- .expectValidation(TanChannel.email to "email@example.com")
+ }.expectValidation(TanChannel.sms to "+98", TanChannel.email to "email@example.com")
.assertNoContent()
client.patchA("/accounts/merchant") {
json { // Both change
"contact_data" to obj { "phone" to "+97" }
"tan_channel" to "sms"
}
- }.expectMfa(TanChannel.email to "email@example.com")
- .expectValidation(TanChannel.sms to "+97")
+ }.expectValidation(TanChannel.email to "email@example.com", TanChannel.sms to "+97")
.assertNoContent()
// Disable 2fa
client.patchA("/accounts/merchant") {
json { "tan_channel" to null as String? }
- }.expectMfa(TanChannel.sms to "+97")
+ }.expectValidation(TanChannel.sms to "+97")
.assertNoContent()
// Update mfa settings - first mfa challenge then new tan channel check
@@ -2206,8 +2203,7 @@ class CoreBankTanApiTest {
json {
"tan_channel" to "email"
}
- }.expectMfa(TanChannel.sms to "+88")
- .expectValidation(TanChannel.email to "email2@example.com")
+ }.expectValidation(TanChannel.sms to "+88", TanChannel.email to "email2@example.com")
.assertNoContent()
// Check invalidated
@@ -2217,7 +2213,7 @@ class CoreBankTanApiTest {
client.patchA("/accounts/merchant") {
headers[TALER_CHALLENGE_IDS] = "${challenge.challenge_id}"
json { "is_public" to false }
- }.expectMfa(TanChannel.email to "email2@example.com")
+ }.expectValidation(TanChannel.email to "email2@example.com")
.assertNoContent()
}