commit bb01cf635a1bc206a4ffb583f550cd336a9f2500
parent d13b09a8a905387eb2013eb42f3fa68a2664f13c
Author: ms <ms@taler.net>
Date: Tue, 19 Oct 2021 10:18:31 +0200
Access API.
Implement read operation on the 'account' resource.
Diffstat:
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -115,6 +115,7 @@ object DemobankCustomersTable : LongIdTable() {
val balance = text("balance")
val username = text("username")
val passwordHash = text("passwordHash")
+ val isDebit = bool("isDebit").default(false)
}
class DemobankCustomerEntity(id: EntityID<Long>) : LongEntity(id) {
@@ -124,9 +125,9 @@ class DemobankCustomerEntity(id: EntityID<Long>) : LongEntity(id) {
var balance by DemobankCustomersTable.balance
var username by DemobankCustomersTable.username
var passwordHash by DemobankCustomersTable.passwordHash
+ var isDebit by DemobankCustomersTable.isDebit
}
-
/**
* This table stores RSA public keys of subscribers.
*/
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -1073,8 +1073,29 @@ val sandboxApp: Application.() -> Unit = {
route("/access-api") {
get("/accounts/{account_name}") {
- // Authenticated. Accesses basic information (balance)
- // about an account. (see docs)
+ val username = call.request.basicAuth()
+ val accountAccessed = call.getUriComponent("account_name")
+ if (username != accountAccessed) {
+ throw forbidden("Account '$accountAccessed' not allowed for '$username'")
+ }
+ val customer = transaction {
+ val res = DemobankCustomerEntity.find {
+ DemobankCustomersTable.username eq username
+ }.firstOrNull()
+ res
+ } ?: throw internalServerError("Account '$accountAccessed' not found AFTER authentication!")
+ val creditDebitIndicator = if (customer.isDebit) {
+ "debit"
+ } else {
+ "credit"
+ }
+ call.respond(object {
+ val balance = {
+ val amount = customer.balance
+ val credit_debit_indicator = creditDebitIndicator
+ }
+ })
+ return@get
}
get("/accounts/{account_name}/history") {
diff --git a/util/src/main/kotlin/HTTP.kt b/util/src/main/kotlin/HTTP.kt
@@ -41,6 +41,14 @@ fun extractToken(authHeader: String): String {
return "${tokenSplit[0]}:${URLDecoder.decode(tokenSplit[1], Charsets.UTF_8)}"
}
+fun forbidden(msg: String): UtilError {
+ return UtilError(
+ HttpStatusCode.Forbidden,
+ msg,
+ ec = LibeufinErrorCode.LIBEUFIN_EC_NONE
+ )
+}
+
fun internalServerError(
reason: String,
libeufinErrorCode: LibeufinErrorCode? = LibeufinErrorCode.LIBEUFIN_EC_NONE
@@ -106,6 +114,10 @@ fun ApplicationCall.getUriComponent(name: String): String {
* - null if the authentication is disabled (during tests, for example)
* - the name of the authenticated user
* - throw exception when the authentication fails
+ *
+ * Note: at this point it is ONLY checked whether the user provided
+ * a valid password for the username mentioned in the Authorization header.
+ * The actual access to the resources must be later checked by each handler.
*/
fun ApplicationRequest.basicAuth(): String? {
val withAuth = this.call.ensureAttribute(WITH_AUTH_ATTRIBUTE_KEY)