diff options
author | Antoine A <> | 2024-03-06 09:55:03 +0100 |
---|---|---|
committer | Antoine A <> | 2024-03-06 09:55:03 +0100 |
commit | 9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47 (patch) | |
tree | 871fac85827e18e240e38dc3bb15b57a0ba3fda0 /bank | |
parent | 73c011ab2f5679bd1fb966318c53790097241540 (diff) | |
download | libeufin-9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47.tar.gz libeufin-9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47.tar.bz2 libeufin-9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47.zip |
Improve password crypto and TAN documentation
Diffstat (limited to 'bank')
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt | 4 | ||||
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt (renamed from bank/src/main/kotlin/tech/libeufin/bank/Tan.kt) | 20 | ||||
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt | 5 | ||||
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt | 9 |
4 files changed, 27 insertions, 11 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt index 2bda3a43..4b6a6e53 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt @@ -318,7 +318,7 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) { requireAdmin = !ctx.allowAccountDeletion ) { delete("/accounts/{USERNAME}") { - val challenge = call.challenge(db, Operation.account_delete) + val challenge = call.checkChallenge(db, Operation.account_delete) // Not deleting reserved names. if (RESERVED_ACCOUNTS.contains(username)) @@ -511,7 +511,7 @@ private fun Routing.coreBankWithdrawalApi(db: Database, ctx: BankConfig) { } post("/accounts/{USERNAME}/withdrawals/{withdrawal_id}/confirm") { val id = call.uuidParameter("withdrawal_id") - val challenge = call.challenge(db, Operation.withdrawal) + val challenge = call.checkChallenge(db, Operation.withdrawal) when (db.withdrawal.confirm(username, id, Instant.now(), challenge != null)) { WithdrawalConfirmationResult.UnknownOperation -> throw notFound( "Withdrawal operation $id not found", diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Tan.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt index eadddc29..f0b346ca 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/Tan.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt @@ -1,6 +1,6 @@ /* * This file is part of LibEuFin. - * Copyright (C) 2023 Stanisci and Dold. + * Copyright (C) 2023-2024 Stanisci and Dold. * LibEuFin is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -30,7 +30,13 @@ import java.security.SecureRandom import java.text.DecimalFormat import java.time.Instant - +/** + * Generate a TAN challenge for an [op] request with [body] and + * respond to the HTTP request with a TAN challenge. + * + * If [channel] and [info] are present, they will be used + * to send the TAN code, otherwise defaults will be used. + */ suspend inline fun <reified B> ApplicationCall.respondChallenge( db: Database, op: Operation, @@ -57,6 +63,10 @@ suspend inline fun <reified B> ApplicationCall.respondChallenge( ) } +/** + * Retrieve a confirmed challenge and its body for [op] from the database + * if the challenge header is defined, otherwise extract the HTTP body. + */ suspend inline fun <reified B> ApplicationCall.receiveChallenge( db: Database, op: Operation @@ -70,7 +80,10 @@ suspend inline fun <reified B> ApplicationCall.receiveChallenge( } } -suspend fun ApplicationCall.challenge( +/** + * Retrieve a confirmed challenge body for [op] if the challenge header is defined + */ +suspend fun ApplicationCall.checkChallenge( db: Database, op: Operation ): Challenge? { @@ -86,6 +99,7 @@ object Tan { private val CODE_FORMAT = DecimalFormat("00000000") private val SECURE_RNG = SecureRandom() + /** Generate a secure random TAN code */ fun genCode(): String { val rand = SECURE_RNG.nextInt(100000000) val code = CODE_FORMAT.format(rand) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt index c70627e7..7e8f4aac 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt @@ -28,6 +28,7 @@ import io.ktor.util.pipeline.* import tech.libeufin.bank.* import tech.libeufin.bank.db.Database import tech.libeufin.common.* +import tech.libeufin.common.crypto.* import java.time.Instant /** Used to store if the currently authenticated user is admin */ @@ -134,13 +135,13 @@ private suspend fun ApplicationCall.authenticateBankRequest(db: Database, requir * Returns the authenticated customer login */ private suspend fun doBasicAuth(db: Database, encoded: String): String { - val decoded = String(base64ToBytes(encoded), Charsets.UTF_8) + val decoded = String(encoded.decodeBase64(), Charsets.UTF_8) val (login, plainPassword) = decoded.splitOnce(":") ?: throw badRequest( "Malformed Basic auth credentials found in the Authorization header", TalerErrorCode.GENERIC_HTTP_HEADERS_MALFORMED ) val hash = db.account.passwordHash(login) ?: throw unauthorized("Unknown account") - if (!CryptoUtil.checkpw(plainPassword, hash)) throw unauthorized("Bad password") + if (!PwCrypto.checkpw(plainPassword, hash)) throw unauthorized("Bad password") return login } diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt index a23d34d5..c4c5054c 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt @@ -21,6 +21,7 @@ package tech.libeufin.bank.db import tech.libeufin.bank.* import tech.libeufin.common.* +import tech.libeufin.common.crypto.* import java.time.Instant /** Data access logic for accounts */ @@ -78,7 +79,7 @@ class AccountDAO(private val db: Database) { setString(9, tanChannel?.name) setString(10, login) oneOrNull { - CryptoUtil.checkpw(password, it.getString(1)) && it.getBoolean(2) + PwCrypto.checkpw(password, it.getString(1)) && it.getBoolean(2) } } @@ -118,7 +119,7 @@ class AccountDAO(private val db: Database) { """ ).run { setString(1, login) - setString(2, CryptoUtil.hashpw(password)) + setString(2, PwCrypto.hashpw(password)) setString(3, name) setString(4, email) setString(5, phone) @@ -392,13 +393,13 @@ class AccountDAO(private val db: Database) { } if (tanRequired) { AccountPatchAuthResult.TanRequired - } else if (oldPw != null && !CryptoUtil.checkpw(oldPw, currentPwh)) { + } else if (oldPw != null && !PwCrypto.checkpw(oldPw, currentPwh)) { AccountPatchAuthResult.OldPasswordMismatch } else { val stmt = conn.prepareStatement(""" UPDATE customers SET password_hash=? where login=? """) - stmt.setString(1, CryptoUtil.hashpw(newPw)) + stmt.setString(1, PwCrypto.hashpw(newPw)) stmt.setString(2, login) stmt.executeUpdateCheck() AccountPatchAuthResult.Success |