gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated (0692f2f2 -> e0f1d57d)


From: gnunet
Subject: [libeufin] branch master updated (0692f2f2 -> e0f1d57d)
Date: Tue, 21 Nov 2023 05:42:10 +0100

This is an automated email from the git hooks/post-receive script.

antoine pushed a change to branch master
in repository libeufin.

    from 0692f2f2 Test iban payto uri normalization
     new 9e9cfb04 Catch and format SQLException
     new e0f1d57d Basic auth challenge

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../kotlin/tech/libeufin/bank/Authentication.kt    | 19 ++++++---
 bank/src/main/kotlin/tech/libeufin/bank/Error.kt   |  6 ++-
 bank/src/main/kotlin/tech/libeufin/bank/Main.kt    | 45 ++++++++++++++--------
 .../main/kotlin/tech/libeufin/bank/db/Database.kt  | 17 ++++----
 .../main/kotlin/tech/libeufin/nexus/Database.kt    |  3 +-
 util/src/main/kotlin/DB.kt                         |  5 ++-
 util/src/main/kotlin/HTTP.kt                       |  3 +-
 7 files changed, 61 insertions(+), 37 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt
index 6001be52..cbef0e1e 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt
@@ -21,6 +21,7 @@ package tech.libeufin.bank
 import io.ktor.http.*
 import io.ktor.server.application.*
 import io.ktor.server.routing.Route
+import io.ktor.server.response.header
 import io.ktor.util.AttributeKey
 import io.ktor.util.pipeline.PipelineContext
 import java.time.Instant
@@ -84,10 +85,16 @@ val ApplicationCall.isAdmin: Boolean get() = 
attributes.getOrNull(AUTH_IS_ADMIN)
  */
 private suspend fun ApplicationCall.authenticateBankRequest(db: Database, 
requiredScope: TokenScope): String? {
     // Extracting the Authorization header.
-    val header = getAuthorizationRawHeader(this.request) ?: throw badRequest(
-        "Authorization header not found.",
-        TalerErrorCode.GENERIC_HTTP_HEADERS_MALFORMED
-    )
+    val header = getAuthorizationRawHeader(this.request)
+    if (header == null) {
+        // Basic auth challenge
+        response.header(HttpHeaders.WWWAuthenticate, "Basic")
+        throw unauthorized(
+            "Authorization header not found.",
+            TalerErrorCode.GENERIC_PARAMETER_MISSING
+        )
+    }
+    
     val authDetails = getAuthorizationDetails(header) ?: throw badRequest(
         "Authorization is invalid.",
         TalerErrorCode.GENERIC_HTTP_HEADERS_MALFORMED
@@ -95,7 +102,7 @@ private suspend fun 
ApplicationCall.authenticateBankRequest(db: Database, requir
     return when (authDetails.scheme) {
         "Basic" -> doBasicAuth(db, authDetails.content)
         "Bearer" -> doTokenAuth(db, authDetails.content, requiredScope)
-        else -> throw unauthorized("Authorization method wrong or not 
supported.") // TODO basic auth challenge
+        else -> throw unauthorized("Authorization method wrong or not 
supported.")
     }
 }
 
@@ -134,7 +141,7 @@ private suspend fun doBasicAuth(db: Database, 
encodedCredentials: String): Strin
         TalerErrorCode.GENERIC_HTTP_HEADERS_MALFORMED
     )
     val (login, plainPassword) = userAndPassSplit
-    val passwordHash = db.account.passwordHash(login) ?: throw unauthorized()
+    val passwordHash = db.account.passwordHash(login) ?: throw 
unauthorized("Bad password")
     if (!CryptoUtil.checkpw(plainPassword, passwordHash)) return null
     return login
 }
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Error.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Error.kt
index 77a584ab..ae879ebc 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Error.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Error.kt
@@ -63,8 +63,10 @@ fun forbidden(
     error: TalerErrorCode = TalerErrorCode.END
 ): LibeufinBankException = libeufinError(HttpStatusCode.Forbidden, hint, error)
 
-fun unauthorized(hint: String? = "Login failed"): LibeufinBankException 
-    = libeufinError(HttpStatusCode.Unauthorized, hint, 
TalerErrorCode.GENERIC_UNAUTHORIZED)
+fun unauthorized(
+    hint: String,
+    error: TalerErrorCode = TalerErrorCode.GENERIC_UNAUTHORIZED
+): LibeufinBankException = libeufinError(HttpStatusCode.Unauthorized, hint, 
error)
 
 fun internalServerError(hint: String?): LibeufinBankException 
     = libeufinError(HttpStatusCode.InternalServerError, hint, 
TalerErrorCode.GENERIC_INTERNAL_INVARIANT_FAILURE)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index f3fffcbe..d381d984 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -44,6 +44,7 @@ import io.ktor.utils.io.jvm.javaio.*
 import java.time.Duration
 import java.util.zip.DataFormatException
 import java.util.zip.Inflater
+import java.sql.SQLException
 import kotlin.system.exitProcess
 import kotlinx.coroutines.*
 import kotlinx.serialization.ExperimentalSerializationApi
@@ -53,6 +54,7 @@ import net.taler.common.errorcodes.TalerErrorCode
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import org.slf4j.event.Level
+import org.postgresql.util.PSQLState
 import tech.libeufin.bank.AccountDAO.*
 import tech.libeufin.util.getVersion
 import tech.libeufin.util.initializeDatabaseTables
@@ -178,32 +180,43 @@ fun Application.corebankWebApp(db: Database, ctx: 
BankConfig) {
                 )
             )
         }
-        /**
-         * This branch triggers when a bank handler throws it, and namely
-         * after one logical failure of the request(-handling).  This branch
-         * should be preferred to catch errors, as it allows to include the
-         * Taler specific error detail.
-         */
         exception<LibeufinBankException> { call, cause ->
             logger.error(cause.talerError.hint)
-            // Stacktrace if bank's fault
-            if (cause.httpStatus.toString().startsWith('5'))
-                cause.printStackTrace()
             call.respond(
                 status = cause.httpStatus,
                 message = cause.talerError
             )
         }
+        exception<SQLException> { call, cause ->
+            val err = when (cause.sqlState) {
+                PSQLState.SERIALIZATION_FAILURE.state -> libeufinError(
+                    HttpStatusCode.InternalServerError,
+                    "Transaction serialization failure",
+                    TalerErrorCode.BANK_SOFT_EXCEPTION
+                )
+                else -> libeufinError(
+                    HttpStatusCode.InternalServerError,
+                    "Unexpected sql error with state ${cause.sqlState}",
+                    TalerErrorCode.BANK_UNMANAGED_EXCEPTION
+                )
+            }
+            logger.error(err.talerError.hint)
+            call.respond(
+                status = err.httpStatus,
+                message = err.talerError
+            )
+        }
         // Catch-all branch to mean that the bank wasn't able to manage one 
error.
         exception<Exception> { call, cause ->
-            cause.printStackTrace()
-            logger.error(cause.message)
+            val err = libeufinError(
+                HttpStatusCode.InternalServerError,
+                cause.message,
+                TalerErrorCode.BANK_UNMANAGED_EXCEPTION
+            )
+            logger.error(err.talerError.hint)
             call.respond(
-                status = HttpStatusCode.InternalServerError,
-                message = TalerError(
-                    code = 
TalerErrorCode.GENERIC_INTERNAL_INVARIANT_FAILURE.code,
-                    hint = cause.message
-                )
+                status = err.httpStatus,
+                message = err.talerError
             )
         }
     }
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
index 892e0602..417d0275 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
@@ -21,6 +21,7 @@ package tech.libeufin.bank
 
 import org.postgresql.jdbc.PgConnection
 import org.postgresql.ds.PGSimpleDataSource
+import org.postgresql.util.PSQLState
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import java.io.File
@@ -150,16 +151,16 @@ class Database(dbConfig: String, internal val 
bankCurrency: String, internal val
             try {
                 return@conn lambda(conn);
             } catch (e: SQLException) {
-                logger.error(e.message)
-                if (e.sqlState != "40001") // serialization_failure
-                    throw e // rethrowing, not to hide other types of errors.
+                if (e.sqlState != PSQLState.SERIALIZATION_FAILURE.state)
+                    throw e
             }
         }
-        throw libeufinError(
-            HttpStatusCode.InternalServerError,
-            "Transaction serialization failure",
-            TalerErrorCode.BANK_SOFT_EXCEPTION
-        )
+        try {
+            return@conn lambda(conn)
+        } catch(e: SQLException) {
+            logger.warn("Serialization failure after $SERIALIZATION_RETRY 
retry")
+            throw e
+        }
     }
 
     /** Apply paging logic to a sql query */
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
index 82df529c..d80fd665 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
@@ -3,6 +3,7 @@ package tech.libeufin.nexus
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
 import org.postgresql.jdbc.PgConnection
+import org.postgresql.util.PSQLState
 import com.zaxxer.hikari.*
 import tech.libeufin.util.*
 import java.sql.PreparedStatement
@@ -137,7 +138,7 @@ private fun PreparedStatement.maybeUpdate(): Boolean {
         this.executeUpdate()
     } catch (e: SQLException) {
         logger.error(e.message)
-        if (e.sqlState == "23505") return false // unique_violation
+        if (e.sqlState == PSQLState.UNIQUE_VIOLATION.state) return false
         throw e // rethrowing, not to hide other types of errors.
     }
     return updateCount > 0
diff --git a/util/src/main/kotlin/DB.kt b/util/src/main/kotlin/DB.kt
index ebc7d7e2..1a7571df 100644
--- a/util/src/main/kotlin/DB.kt
+++ b/util/src/main/kotlin/DB.kt
@@ -25,6 +25,7 @@ import kotlinx.coroutines.coroutineScope
 import net.taler.wallet.crypto.Base32Crockford
 import org.postgresql.ds.PGSimpleDataSource
 import org.postgresql.jdbc.PgConnection
+import org.postgresql.util.PSQLState
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import java.io.File
@@ -171,7 +172,7 @@ fun PreparedStatement.executeUpdateViolation(): Boolean {
         executeUpdateCheck()
     } catch (e: SQLException) {
         logger.error(e.message)
-        if (e.sqlState == "23505") return false // unique_violation
+        if (e.sqlState == PSQLState.UNIQUE_VIOLATION.state) return false
         throw e // rethrowing, not to hide other types of errors.
     }
 }
@@ -184,7 +185,7 @@ fun PreparedStatement.executeProcedureViolation(): Boolean {
         true
     } catch (e: SQLException) {
         connection.rollback(savepoint);
-        if (e.sqlState == "23505") return false // unique_violation
+        if (e.sqlState == PSQLState.UNIQUE_VIOLATION.state) return false
         throw e // rethrowing, not to hide other types of errors.
     }
 }
diff --git a/util/src/main/kotlin/HTTP.kt b/util/src/main/kotlin/HTTP.kt
index 8c639496..d310c9ba 100644
--- a/util/src/main/kotlin/HTTP.kt
+++ b/util/src/main/kotlin/HTTP.kt
@@ -54,8 +54,7 @@ fun ApplicationCall.maybeUriComponent(name: String): String? {
 
 // Extracts the Authorization:-header line, or returns null if not found.
 fun getAuthorizationRawHeader(request: ApplicationRequest): String? {
-    val authorization = request.headers["Authorization"]
-    return authorization ?: run {
+    return request.headers["Authorization"] ?: run {
         logger.error("Authorization header not found")
         return null
     }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]