libeufin

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

commit 1d08ec597f41c5cba0126eb3c399ace719201703
parent 1541b50689decb3c74abfb58c7d47e9dc9d05bc8
Author: Antoine A <>
Date:   Mon, 20 Nov 2023 17:45:09 +0000

Common auth test routine

Diffstat:
Mbank/src/test/kotlin/CoreBankApiTest.kt | 94+++++++++++++++++++++++++------------------------------------------------------
Mbank/src/test/kotlin/RevenueApiTest.kt | 2+-
Mbank/src/test/kotlin/WireGatewayApiTest.kt | 49++++---------------------------------------------
Mbank/src/test/kotlin/routines.kt | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 90 insertions(+), 111 deletions(-)

diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt @@ -45,15 +45,11 @@ class CoreBankConfigTest { // GET /monitor @Test fun monitor() = bankSetup { _ -> + authRoutine(HttpMethod.Get, "/monitor", requireAdmin = true) // Check OK client.get("/monitor?timeframe=hour") { pwAuth("admin") }.assertOk() - - // Check only admin - client.get("/monitor") { - pwAuth("exchange") - }.assertUnauthorized() } } @@ -61,10 +57,7 @@ class CoreBankTokenApiTest { // POST /accounts/USERNAME/token @Test fun post() = bankSetup { db -> - // Wrong user - client.post("/accounts/merchant/token") { - pwAuth("exchange") - }.assertUnauthorized() + authRoutine(HttpMethod.Post, "/accounts/merchant/token") // New default token client.postA("/accounts/merchant/token") { @@ -259,19 +252,14 @@ class CoreBankAccountsApiTest { // Test admin-only account creation @Test fun createAccountRestrictedTest() = bankSetup(conf = "test_restrict.conf") { _ -> - val req = obj { - "username" to "baz" - "password" to "xyz" - "name" to "Mallory" - } - - client.post("/accounts") { - pwAuth("merchant") - json(req) - }.assertUnauthorized() + authRoutine(HttpMethod.Post, "/accounts", requireAdmin = true) client.post("/accounts") { pwAuth("admin") - json(req) + json { + "username" to "baz" + "password" to "xyz" + "name" to "Mallory" + } }.assertCreated() } @@ -321,6 +309,8 @@ class CoreBankAccountsApiTest { // PATCH /accounts/USERNAME @Test fun accountReconfig() = bankSetup { _ -> + authRoutine(HttpMethod.Patch, "/accounts/merchant", withAdmin = true) + // Successful attempt now. val cashout = IbanPayTo(genIbanPaytoUri()) val req = obj { @@ -390,6 +380,8 @@ class CoreBankAccountsApiTest { // PATCH /accounts/USERNAME/auth @Test fun passwordChangeTest() = bankSetup { _ -> + authRoutine(HttpMethod.Patch, "/accounts/merchant/auth", withAdmin = true) + // Changing the password. client.patch("/accounts/customer/auth") { basicAuth("customer", "customer-password") @@ -441,6 +433,7 @@ class CoreBankAccountsApiTest { // GET /public-accounts and GET /accounts @Test fun accountsListTest() = bankSetup { _ -> + authRoutine(HttpMethod.Get, "/accounts", requireAdmin = true) // Remove default accounts listOf("merchant", "exchange", "customer").forEach { client.delete("/accounts/$it") { @@ -502,53 +495,19 @@ class CoreBankAccountsApiTest { // GET /accounts/USERNAME @Test fun getAccountTest() = bankSetup { _ -> + authRoutine(HttpMethod.Get, "/accounts/merchant", withAdmin = true) // Check ok client.getA("/accounts/merchant").assertOkJson<AccountData> { assertEquals("Merchant", it.name) } - - // Check admin ok - client.get("/accounts/merchant") { - pwAuth("admin") - }.assertOk() - - // Check wrong user - client.get("/accounts/exchange") { - pwAuth("merchant") - }.assertUnauthorized() } } class CoreBankTransactionsApiTest { - // Test endpoint is correctly authenticated - suspend fun ApplicationTestBuilder.authRoutine(path: String, withAdmin: Boolean = true, method: HttpMethod = HttpMethod.Post) { - // No body when authentication must happen before parsing the body - - // Unknown account - client.request(path) { - this.method = method - basicAuth("unknown", "password") - }.assertUnauthorized() - - // Wrong password - client.request(path) { - this.method = method - basicAuth("merchant", "wrong-password") - }.assertUnauthorized() - - // Wrong account - client.request(path) { - this.method = method - basicAuth("exchange", "merchant-password") - }.assertUnauthorized() - - // TODO check admin rights - } - // GET /transactions @Test fun testHistory() = bankSetup { _ -> - authRoutine("/accounts/customer/transactions", method = HttpMethod.Get) + authRoutine(HttpMethod.Get, "/accounts/merchant/transactions") historyRoutine<BankAccountTransactionsResponse>( url = "/accounts/customer/transactions", ids = { it.transactions.map { it.row_id } }, @@ -586,7 +545,7 @@ class CoreBankTransactionsApiTest { // GET /transactions/T_ID @Test fun testById() = bankSetup { _ -> - authRoutine("/accounts/merchant/transactions/1", method = HttpMethod.Get) + authRoutine(HttpMethod.Get, "/accounts/merchant/transactions/42") // Create transaction tx("merchant", "KUDOS:0.3", "exchange", "tx") @@ -607,13 +566,13 @@ class CoreBankTransactionsApiTest { // POST /transactions @Test fun create() = bankSetup { _ -> + authRoutine(HttpMethod.Post, "/accounts/merchant/transactions") + val valid_req = obj { "payto_uri" to "$exchangePayto?message=payout" "amount" to "KUDOS:0.3" } - authRoutine("/accounts/merchant/transactions") - // Check OK client.postA("/accounts/merchant/transactions") { json(valid_req) @@ -732,6 +691,8 @@ class CoreBankWithdrawalApiTest { // POST /accounts/USERNAME/withdrawals @Test fun create() = bankSetup { _ -> + authRoutine(HttpMethod.Post, "/accounts/merchant/withdrawals") + // Check OK client.postA("/accounts/merchant/withdrawals") { json { "amount" to "KUDOS:9.0" } @@ -894,7 +855,8 @@ class CoreBankCashoutApiTest { // POST /accounts/{USERNAME}/cashouts @Test fun create() = bankSetup { _ -> - // TODO auth routine + authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts") + val req = obj { "request_uid" to randShortHashCode() "amount_debit" to "KUDOS:1" @@ -994,7 +956,8 @@ class CoreBankCashoutApiTest { // POST /accounts/{USERNAME}/cashouts/{CASHOUT_ID}/abort @Test fun abort() = bankSetup { _ -> - // TODO auth routine + authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts/42/abort") + fillCashoutInfo("customer") val req = obj { @@ -1057,7 +1020,8 @@ class CoreBankCashoutApiTest { // POST /accounts/{USERNAME}/cashouts/{CASHOUT_ID}/confirm @Test fun confirm() = bankSetup { db -> - // TODO auth routine + authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts/42/confirm") + client.patchA("/accounts/customer") { json { "challenge_contact_data" to obj { @@ -1177,7 +1141,7 @@ class CoreBankCashoutApiTest { // GET /accounts/{USERNAME}/cashouts/{CASHOUT_ID} @Test fun get() = bankSetup { _ -> - // TODO auth routine + authRoutine(HttpMethod.Get, "/accounts/merchant/cashouts/42") fillCashoutInfo("customer") val amountDebit = TalerAmount("KUDOS:1.5") @@ -1249,7 +1213,7 @@ class CoreBankCashoutApiTest { // GET /accounts/{USERNAME}/cashouts @Test fun history() = bankSetup { _ -> - // TODO auth routine + authRoutine(HttpMethod.Get, "/accounts/merchant/cashouts") historyRoutine<Cashouts>( url = "/accounts/customer/cashouts", ids = { it.cashouts.map { it.cashout_id } }, @@ -1261,7 +1225,7 @@ class CoreBankCashoutApiTest { // GET /cashouts @Test fun globalHistory() = bankSetup { _ -> - // TODO admin auth routine + authRoutine(HttpMethod.Get, "/cashouts", requireAdmin = true) historyRoutine<GlobalCashouts>( url = "/cashouts", ids = { it.cashouts.map { it.cashout_id } }, diff --git a/bank/src/test/kotlin/RevenueApiTest.kt b/bank/src/test/kotlin/RevenueApiTest.kt @@ -33,7 +33,7 @@ class RevenueApiTest { @Test fun history() = bankSetup { setMaxDebt("exchange", TalerAmount("KUDOS:1000000")) - // TODO auth routine + authRoutine(HttpMethod.Get, "/accounts/merchant/taler-revenue/history") historyRoutine<MerchantIncomingHistory>( url = "/accounts/merchant/taler-revenue/history", ids = { it.incoming_transactions.map { it.row_id } }, diff --git a/bank/src/test/kotlin/WireGatewayApiTest.kt b/bank/src/test/kotlin/WireGatewayApiTest.kt @@ -30,47 +30,6 @@ import org.junit.Test import tech.libeufin.bank.* class WireGatewayApiTest { - // Test endpoint is correctly authenticated - suspend fun ApplicationTestBuilder.authRoutine(path: String, body: JsonObject? = null, method: HttpMethod = HttpMethod.Post, requireAdmin: Boolean = false) { - // No body when authentication must happen before parsing the body - - // Unknown account - client.request(path) { - this.method = method - basicAuth("unknown", "password") - }.assertUnauthorized() - - // Wrong password - client.request(path) { - this.method = method - basicAuth("merchant", "wrong-password") - }.assertUnauthorized() - - // Wrong account - client.request(path) { - this.method = method - basicAuth("exchange", "merchant-password") - }.assertUnauthorized() - - if (requireAdmin) { - // Not exchange account - client.request(path) { - this.method = method - if (body != null) json(body) - pwAuth("merchant") - }.assertUnauthorized() - } - - // Not exchange account - client.request(path) { - this.method = method - if (body != null) json(body) - if (requireAdmin) - pwAuth("admin") - else pwAuth("merchant") - }.assertConflict(TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE) - } - // Testing the POST /transfer call from the TWG API. @Test fun transfer() = bankSetup { _ -> @@ -82,7 +41,7 @@ class WireGatewayApiTest { "credit_account" to merchantPayto }; - authRoutine("/accounts/merchant/taler-wire-gateway/transfer", valid_req) + authRoutine(HttpMethod.Post, "/accounts/merchant/taler-wire-gateway/transfer", valid_req) // Checking exchange debt constraint. client.postA("/accounts/exchange/taler-wire-gateway/transfer") { @@ -169,7 +128,7 @@ class WireGatewayApiTest { fun historyIncoming() = bankSetup { // Give Foo reasonable debt allowance: setMaxDebt("merchant", TalerAmount("KUDOS:1000")) - authRoutine("/accounts/merchant/taler-wire-gateway/history/incoming?delta=7", method = HttpMethod.Get) + authRoutine(HttpMethod.Get, "/accounts/merchant/taler-wire-gateway/history/incoming") historyRoutine<IncomingHistory>( url = "/accounts/exchange/taler-wire-gateway/history/incoming", ids = { it.incoming_transactions.map { it.row_id } }, @@ -207,7 +166,7 @@ class WireGatewayApiTest { @Test fun historyOutgoing() = bankSetup { setMaxDebt("exchange", TalerAmount("KUDOS:1000000")) - authRoutine("/accounts/merchant/taler-wire-gateway/history/outgoing?delta=7", method = HttpMethod.Get) + authRoutine(HttpMethod.Get, "/accounts/merchant/taler-wire-gateway/history/outgoing") historyRoutine<OutgoingHistory>( url = "/accounts/exchange/taler-wire-gateway/history/outgoing", ids = { it.outgoing_transactions.map { it.row_id } }, @@ -243,7 +202,7 @@ class WireGatewayApiTest { "debit_account" to merchantPayto }; - authRoutine("/accounts/merchant/taler-wire-gateway/admin/add-incoming", valid_req, requireAdmin = true) + authRoutine(HttpMethod.Post, "/accounts/merchant/taler-wire-gateway/admin/add-incoming", valid_req, requireAdmin = true) // Checking exchange debt constraint. client.postA("/accounts/exchange/taler-wire-gateway/admin/add-incoming") { diff --git a/bank/src/test/kotlin/routines.kt b/bank/src/test/kotlin/routines.kt @@ -21,7 +21,63 @@ import tech.libeufin.bank.* import io.ktor.client.statement.HttpResponse import io.ktor.server.testing.ApplicationTestBuilder import io.ktor.client.request.* +import io.ktor.http.* import kotlinx.coroutines.* +import kotlinx.serialization.json.* +import net.taler.common.errorcodes.TalerErrorCode + +// Test endpoint is correctly authenticated +suspend fun ApplicationTestBuilder.authRoutine( + method: HttpMethod, + path: String, + body: JsonObject? = null, + requireExchange: Boolean = false, + requireAdmin: Boolean = false, + withAdmin: Boolean = false +) { + // No body when authentication must happen before parsing the body + + // Unknown account + client.request(path) { + this.method = method + basicAuth("unknown", "password") + }.assertUnauthorized() + + // Wrong password + client.request(path) { + this.method = method + basicAuth("merchant", "wrong-password") + }.assertUnauthorized() + + // Wrong account + client.request(path) { + this.method = method + basicAuth("exchange", "merchant-password") + }.assertUnauthorized() + + if (requireAdmin) { + // Not exchange account + client.request(path) { + this.method = method + pwAuth("merchant") + }.assertUnauthorized() + } else if (!withAdmin) { + // Check no admin + client.request(path) { + this.method = method + pwAuth("admin") + }.assertUnauthorized() + } + + if (requireExchange) { + // Not exchange account + client.request(path) { + this.method = method + if (body != null) json(body) + pwAuth(if (requireAdmin) "admin" else "merchant") + }.assertConflict(TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE) + } +} inline suspend fun <reified B> ApplicationTestBuilder.historyRoutine( url: String,