libeufin

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

commit e0f1d57d1a46772437952a4224537b698ba324df
parent 9e9cfb04e56f23b9dac2a782fd8951151fd1e6ad
Author: Antoine A <>
Date:   Tue, 21 Nov 2023 04:40:57 +0000

Basic auth challenge

Diffstat:
Mbank/src/main/kotlin/tech/libeufin/bank/Authentication.kt | 19+++++++++++++------
Mbank/src/main/kotlin/tech/libeufin/bank/Error.kt | 6++++--
Mbank/src/main/kotlin/tech/libeufin/bank/Main.kt | 9---------
Mutil/src/main/kotlin/HTTP.kt | 3+--
4 files changed, 18 insertions(+), 19 deletions(-)

diff --git 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 @@ -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 @@ -180,17 +180,8 @@ 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 diff --git 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 }