commit 6ec6d539216c2deb1afc0aec0b845c0267c1e23b
parent 8536282bb6046b1cb6c4f18461d96543dc77f979
Author: Antoine A <>
Date: Wed, 1 Nov 2023 11:07:58 +0000
Improve account creation and patching
Diffstat:
4 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt b/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt
@@ -41,6 +41,14 @@ fun Route.authAdmin(db: Database, scope: TokenScope, enforce: Boolean = true, ca
if (login != "admin") {
throw unauthorized("Only administrator allowed")
}
+ context.attributes.put(AUTH_IS_ADMIN, true)
+ } else {
+ val login = try {
+ context.authenticateBankRequest(db, scope)
+ } catch (e: Exception) {
+ null
+ }
+ context.attributes.put(AUTH_IS_ADMIN, login == "admin")
}
}
@@ -65,7 +73,7 @@ fun Route.auth(db: Database, scope: TokenScope, allowAdmin: Boolean = false, req
val PipelineContext<Unit, ApplicationCall>.username: String get() = call.username
val PipelineContext<Unit, ApplicationCall>.isAdmin: Boolean get() = call.isAdmin
val ApplicationCall.username: String get() = expectUriComponent("USERNAME")
-val ApplicationCall.isAdmin: Boolean get() = attributes.getOrNull(AUTH_IS_ADMIN) ?: throw Exception("No auth")
+val ApplicationCall.isAdmin: Boolean get() = attributes.getOrNull(AUTH_IS_ADMIN) ?: false
private fun Route.intercept(callback: Route.() -> Unit, interceptor: suspend PipelineContext<Unit, ApplicationCall>.() -> Unit): Route {
val subRoute = createChild(object : RouteSelector() {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -149,6 +149,8 @@ private fun Routing.coreBankAccountsMgmtApi(db: Database, ctx: BankConfig) {
"Username '${req.username}' is reserved.",
TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT
)
+ if (req.is_taler_exchange && !isAdmin)
+ throw forbidden("Only admin can create exchange accounts")
val internalPayto = req.internal_payto_uri ?: IbanPayTo(genIbanPaytoUri())
val result = db.accountCreate(
@@ -212,13 +214,12 @@ private fun Routing.coreBankAccountsMgmtApi(db: Database, ctx: BankConfig) {
}
auth(db, TokenScope.readwrite, allowAdmin = true) {
patch("/accounts/{USERNAME}") {
- // admin is not allowed itself to change its own details.
- if (username == "admin") throw forbidden("admin account not patchable")
-
val req = call.receive<AccountReconfiguration>()
req.debit_threshold?.run { ctx.checkInternalCurrency(this) }
- if (req.is_exchange != null && !isAdmin)
+ if (req.is_taler_exchange != null && username == "admin")
+ throw forbidden("admin account cannot be an exchange")
+ if (req.is_taler_exchange != null && !isAdmin)
throw forbidden("non-admin user cannot change their exchange nature")
val res = db.accountReconfig(
@@ -226,7 +227,7 @@ private fun Routing.coreBankAccountsMgmtApi(db: Database, ctx: BankConfig) {
name = req.name,
cashoutPayto = req.cashout_address,
emailAddress = req.challenge_contact_data?.email,
- isTalerExchange = req.is_exchange,
+ isTalerExchange = req.is_taler_exchange,
phoneNumber = req.challenge_contact_data?.phone,
debtLimit = req.debit_threshold,
isAdmin = isAdmin
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
@@ -621,6 +621,6 @@ data class AccountReconfiguration(
val challenge_contact_data: ChallengeContactData?,
val cashout_address: IbanPayTo?,
val name: String?,
- val is_exchange: Boolean?,
+ val is_taler_exchange: Boolean?,
val debit_threshold: TalerAmount?
)
\ No newline at end of file
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -206,6 +206,20 @@ class CoreBankAccountsMgmtApiTest {
}.assertForbidden().assertErr(TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT)
}
+ // Only admin can create exchange account
+ val exchangeReq = json(req) {
+ "username" to "better-exchange"
+ "internal_payto_uri" to genIbanPaytoUri()
+ "is_taler_exchange" to true
+ }
+ client.post("/accounts") {
+ jsonBody(exchangeReq)
+ }.assertForbidden()
+ client.post("/accounts") {
+ basicAuth("admin", "admin-password")
+ jsonBody(exchangeReq)
+ }.assertCreated()
+
// Testing login conflict
client.post("/accounts") {
jsonBody(json(req) {
@@ -277,12 +291,10 @@ class CoreBankAccountsMgmtApiTest {
"name" to "Mallory"
}
- // Ordinary user
client.post("/accounts") {
basicAuth("merchant", "merchant-password")
jsonBody(req)
}.assertUnauthorized()
- // Administrator
client.post("/accounts") {
basicAuth("admin", "admin-password")
jsonBody(req)
@@ -378,8 +390,19 @@ class CoreBankAccountsMgmtApiTest {
}
checkAdminOnly(json(req) { "name" to "Another Foo" })
- checkAdminOnly(json(req) { "is_exchange" to true })
+ checkAdminOnly(json(req) { "is_taler_exchange" to true })
checkAdminOnly(json(req) { "debit_threshold" to "KUDOS:100" })
+
+ // Check admin account cannot be exchange
+ client.patch("/accounts/admin") {
+ basicAuth("admin", "admin-password")
+ jsonBody(json { "is_taler_exchange" to true })
+ }.assertForbidden()
+ // But we can change its debt limit
+ client.patch("/accounts/admin") {
+ basicAuth("admin", "admin-password")
+ jsonBody(json { "debit_threshold" to "KUDOS:100" })
+ }.assertNoContent()
// Check currency
client.patch("/accounts/merchant") {