gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: make tests pass


From: gnunet
Subject: [libeufin] branch master updated: make tests pass
Date: Tue, 19 May 2020 14:35:43 +0200

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

dold pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new a43aa2e  make tests pass
a43aa2e is described below

commit a43aa2e9e89281b27bbe823d0a9c3197a762c1d2
Author: Florian Dold <address@hidden>
AuthorDate: Tue May 19 18:05:33 2020 +0530

    make tests pass
---
 integration-tests/test-ebics.py                    | 14 +----
 nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt    |  2 +
 .../src/main/kotlin/tech/libeufin/nexus/Helpers.kt | 70 ++++++++++------------
 nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt  |  9 +++
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  | 60 ++++++++++++-------
 nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt | 10 ++--
 util/src/test/kotlin/EbicsMessagesTest.kt          |  1 -
 7 files changed, 88 insertions(+), 78 deletions(-)

diff --git a/integration-tests/test-ebics.py b/integration-tests/test-ebics.py
index 50a217b..f7a94bd 100755
--- a/integration-tests/test-ebics.py
+++ b/integration-tests/test-ebics.py
@@ -5,7 +5,6 @@ from subprocess import call, Popen, PIPE
 from time import sleep
 import os
 import socket
-import sqlite3
 import hashlib
 import base64
 
@@ -89,9 +88,11 @@ assert(0 == call(["rm", "-f", 
"sandbox/libeufin-sandbox.sqlite3"]))
 assert(0 == call(["rm", "-f", "nexus/libeufin-nexus.sqlite3"]))
 DEVNULL = open(os.devnull, "w")
 
+assert(0 == call(["./gradlew", "nexus:run", "--console=plain", 
"--args=superuser admin --password x"]))
+
 # Start nexus
 checkPorts([5001])
-nexus = Popen(["./gradlew", "nexus:run"], stdout=PIPE, stderr=PIPE)
+nexus = Popen(["./gradlew", "nexus:run", "--console=plain", "--args=serve"], 
stdout=PIPE, stderr=PIPE)
 for i in range(10):
     try:
       get("http://localhost:5001/";)
@@ -166,15 +167,6 @@ assertResponse(
 
 #1.a, make a new nexus user.
 
-# "Create" the admin user first.
-dbconn = sqlite3.connect("nexus/libeufin-nexus.sqlite3")
-dbconn.execute(
-    "INSERT INTO NexusUsers (id, password) VALUES (?, ?)",
-    ("admin", sqlite3.Binary(hashlib.sha256(b"x").digest()))
-)
-dbconn.commit()
-dbconn.close()
-
 assertResponse(
     post(
         "http://localhost:5001/users";,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
index 9c7e225..89d55e2 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -211,11 +211,13 @@ class EbicsSubscriberEntity(id: EntityID<String>) : 
Entity<String>(id) {
 object NexusUsersTable : IdTable<String>() {
     override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
     val passwordHash = text("password")
+    val superuser = bool("superuser")
 }
 
 class NexusUserEntity(id: EntityID<String>) : Entity<String>(id) {
     companion object : EntityClass<String, NexusUserEntity>(NexusUsersTable)
     var passwordHash by NexusUsersTable.passwordHash
+    var superuser by NexusUsersTable.superuser
 }
 
 object BankAccountMapsTable : IntIdTable() {
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
index ac77efb..6258679 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -7,18 +7,14 @@ import io.ktor.http.HttpStatusCode
 import org.jetbrains.exposed.sql.and
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.joda.time.DateTime
-import tech.libeufin.util.Amount
-import tech.libeufin.util.CryptoUtil
-import tech.libeufin.util.EbicsClientSubscriberDetails
-import tech.libeufin.util.base64ToBytes
-import java.util.Random
+import tech.libeufin.util.*
 import tech.libeufin.util.ebics_h004.EbicsTypes
 import java.security.interfaces.RSAPublicKey
-import tech.libeufin.util.*
-import java.time.format.DateTimeFormatter
-import java.time.ZonedDateTime
 import java.time.Instant
 import java.time.ZoneId
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.util.*
 
 fun isProduction(): Boolean {
     return System.getenv("NEXUS_PRODUCTION") != null
@@ -75,8 +71,8 @@ fun getBankAccount(userId: String, accountId: String): 
BankAccountEntity {
         val bankAccountMap = BankAccountMapEntity.find {
             BankAccountMapsTable.nexusUser eq userId
         }.firstOrNull() ?: throw NexusError(
-        HttpStatusCode.NotFound,
-        "Bank account '$accountId' not found"
+            HttpStatusCode.NotFound,
+            "Bank account '$accountId' not found"
         )
         bankAccountMap.bankAccount
     }
@@ -142,7 +138,7 @@ fun getEbicsTransport(userId: String, transportId: String? 
= null): EbicsSubscri
                 EbicsSubscribersTable.nexusUser eq userId
             }.firstOrNull()
         }
-        return@transaction EbicsSubscriberEntity.find{
+        return@transaction EbicsSubscriberEntity.find {
             EbicsSubscribersTable.id eq transportId and 
(EbicsSubscribersTable.nexusUser eq userId)
         }.firstOrNull()
     }
@@ -196,18 +192,23 @@ suspend fun downloadAndPersistC5xEbics(
                     RawBankTransactionEntity.new {
                         bankAccount = getBankAccountFromIban(
                             camt53doc.pickString(
-                                
"//*[local-name()='Stmt']/*[local-name()='Acct']/*[local-name()='Id']/*[local-name()='IBAN']")
+                                
"//*[local-name()='Stmt']/*[local-name()='Acct']/*[local-name()='Id']/*[local-name()='IBAN']"
+                            )
                         )
                         sourceFileName = fileName
-                        unstructuredRemittanceInformation = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Ustrd']")
+                        unstructuredRemittanceInformation =
+                            
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Ustrd']")
                         transactionType = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='CdtDbtInd']")
                         currency = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Amt']/@Ccy")
                         amount = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Amt']")
                         status = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Sts']")
-                        bookingDate = 
parseDashedDate(camt53doc.pickString("//*[local-name()='BookgDt']//*[local-name()='Dt']")).millis
+                        bookingDate =
+                            
parseDashedDate(camt53doc.pickString("//*[local-name()='BookgDt']//*[local-name()='Dt']")).millis
                         nexusUser = extractNexusUser(userId)
-                        counterpartIban = 
camt53doc.pickString("//*[local-name()='${if (this.transactionType == "DBIT") 
"CdtrAcct" else "DbtrAcct"}']//*[local-name()='IBAN']")
-                        counterpartName = 
camt53doc.pickString("//*[local-name()='RltdPties']//*[local-name()='${if 
(this.transactionType == "DBIT") "Cdtr" else "Dbtr"}']//*[local-name()='Nm']")
+                        counterpartIban =
+                            camt53doc.pickString("//*[local-name()='${if 
(this.transactionType == "DBIT") "CdtrAcct" else 
"DbtrAcct"}']//*[local-name()='IBAN']")
+                        counterpartName =
+                            
camt53doc.pickString("//*[local-name()='RltdPties']//*[local-name()='${if 
(this.transactionType == "DBIT") "Cdtr" else "Dbtr"}']//*[local-name()='Nm']")
                         counterpartBic = 
camt53doc.pickString("//*[local-name()='RltdAgts']//*[local-name()='BIC']")
                     }
                 }
@@ -217,7 +218,7 @@ suspend fun downloadAndPersistC5xEbics(
             throw NexusError(
                 HttpStatusCode.BadGateway,
                 response.returnCode.errorCode
-                )
+            )
         }
     }
 }
@@ -426,7 +427,7 @@ fun extractNexusUser(param: String?): NexusUserEntity {
     if (param == null) {
         throw NexusError(HttpStatusCode.BadRequest, "Null Id given")
     }
-    return transaction{
+    return transaction {
         NexusUserEntity.findById(param) ?: throw NexusError(
             HttpStatusCode.NotFound,
             "Subscriber: $param not found"
@@ -461,34 +462,23 @@ fun extractUserAndHashedPassword(authorizationHeader: 
String): Pair<String, Stri
  * @param authorization the Authorization:-header line.
  * @return user id
  */
-fun authenticateRequest(authorization: String?): String {
+fun authenticateRequest(authorization: String?): NexusUserEntity {
     val headerLine = if (authorization == null) throw NexusError(
         HttpStatusCode.BadRequest, "Authentication:-header line not found"
     ) else authorization
-    val nexusUserId = transaction {
-        val (username, password) = extractUserAndHashedPassword(headerLine)
-        val user = NexusUserEntity.find {
-            NexusUsersTable.id eq username
-        }.firstOrNull()
-        if (user == null) {
-            throw NexusError(HttpStatusCode.Unauthorized, "Unknown user")
-        }
-        if (!CryptoUtil.checkpw(password, user.passwordHash)) {
-            throw NexusError(HttpStatusCode.Forbidden, "Wrong password")
-        }
-        return@transaction user.id.value
+    val (username, password) = extractUserAndHashedPassword(headerLine)
+    val user = NexusUserEntity.find {
+        NexusUsersTable.id eq username
+    }.firstOrNull()
+    if (user == null) {
+        throw NexusError(HttpStatusCode.Unauthorized, "Unknown user")
     }
-    return nexusUserId
+    if (!CryptoUtil.checkpw(password, user.passwordHash)) {
+        throw NexusError(HttpStatusCode.Forbidden, "Wrong password")
+    }
+    return user
 }
 
-fun authenticateAdminRequest(authorization: String?): String {
-    val userId = authenticateRequest(authorization)
-    if (!userId.equals("admin")) throw NexusError(
-        HttpStatusCode.Forbidden,
-        "Not the 'admin' user"
-    )
-    return userId
-}
 
 /**
  * Check if the subscriber has the right to use the (claimed) bank account.
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
index 7b764f2..d48e283 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
@@ -190,6 +190,15 @@ data class User(
     val password: String
 )
 
+data class UserInfo(
+    val username: String,
+    val superuser: Boolean
+)
+
+data class UsersResponse(
+    val users: List<UserInfo>
+)
+
 /** Response (list's element) type of "GET /bank-accounts" */
 data class BankAccount(
     var holder: String,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index ec2080e..5bcf100 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -20,6 +20,7 @@
 package tech.libeufin.nexus
 
 import com.github.ajalt.clikt.core.CliktCommand
+import com.github.ajalt.clikt.core.ProgramResult
 import com.github.ajalt.clikt.core.subcommands
 import com.github.ajalt.clikt.parameters.arguments.argument
 import com.github.ajalt.clikt.parameters.options.option
@@ -174,8 +175,8 @@ class Serve: CliktCommand("Run nexus HTTP server") {
 }
 
 class Superuser: CliktCommand("Add superuser or change pw") {
-    val username by argument()
-    val password by option().prompt(requireConfirmation = true, hideInput = 
true)
+    private val username by argument()
+    private val password by option().prompt(requireConfirmation = true, 
hideInput = true)
     override fun run() {
         dbCreateTables()
         transaction {
@@ -184,8 +185,13 @@ class Superuser: CliktCommand("Add superuser or change 
pw") {
             if (user == null) {
                 NexusUserEntity.new(username) {
                     this.passwordHash = hashedPw
+                    this.superuser = true
                 }
             } else {
+                if (!user.superuser) {
+                    println("Can only change password for superuser with this 
command.")
+                    throw ProgramResult(1)
+                }
                 user.passwordHash = hashedPw
             }
         }
@@ -267,30 +273,42 @@ fun serverMain() {
              * Shows information about the requesting user.
              */
             get("/user") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
                 val ret = transaction {
-                    NexusUserEntity.findById(userId)
+                    val currentUser = 
authenticateRequest(call.request.headers["Authorization"])
                     UserResponse(
-                        username = userId,
-                        superuser = userId.equals("admin")
+                        username = currentUser.id.value,
+                        superuser = currentUser.superuser
                     )
                 }
                 call.respond(HttpStatusCode.OK, ret)
                 return@get
             }
+
+            get("/users") {
+                val users = transaction {
+                    transaction {
+                        NexusUserEntity.all().map {
+                            UserInfo(it.id.value, it.superuser)
+                        }
+                    }
+                }
+                val usersResp = UsersResponse(users)
+                call.respond(HttpStatusCode.OK, usersResp)
+                return@get
+            }
             /**
-             * Add a new ordinary user in the system (requires "admin" 
privileges)
+             * Add a new ordinary user in the system (requires superuser 
privileges)
              */
             post("/users") {
-                authenticateAdminRequest(call.request.headers["Authorization"])
                 val body = call.receive<User>()
-                if (body.username.equals("admin")) throw NexusError(
-                    HttpStatusCode.Forbidden,
-                    "'admin' is a reserved username"
-                )
                 transaction {
+                    val currentUser = 
authenticateRequest(call.request.headers["Authorization"])
+                    if (!currentUser.superuser) {
+                        throw NexusError(HttpStatusCode.Forbidden, "only 
superuser can do that")
+                    }
                     NexusUserEntity.new(body.username) {
                         passwordHash = hashpw(body.password)
+                        superuser = false
                     }
                 }
                 call.respondText(
@@ -304,7 +322,7 @@ fun serverMain() {
              * Shows the bank accounts belonging to the requesting user.
              */
             get("/bank-accounts") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val bankAccounts = BankAccounts()
                 getBankAccountsFromNexusUserId(userId).forEach {
                     bankAccounts.accounts.add(
@@ -322,7 +340,7 @@ fun serverMain() {
              * Submit one particular payment at the bank.
              */
             post("/bank-accounts/prepared-payments/submit") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val body = call.receive<SubmitPayment>()
                 val preparedPayment = getPreparedPayment(body.uuid)
                 transaction {
@@ -368,7 +386,7 @@ fun serverMain() {
              * Shows information about one particular prepared payment.
              */
             get("/bank-accounts/{accountid}/prepared-payments/{uuid}") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val preparedPayment = 
getPreparedPayment(ensureNonNull(call.parameters["uuid"]))
                 if (preparedPayment.nexusUser.id.value != userId) throw 
NexusError(
                     HttpStatusCode.Forbidden,
@@ -393,7 +411,7 @@ fun serverMain() {
              * Adds a new prepared payment.
              */
             post("/bank-accounts/{accountid}/prepared-payments") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val bankAccount = getBankAccount(userId, 
ensureNonNull(call.parameters["accountid"]))
                 val body = call.receive<PreparedPaymentRequest>()
                 val amount = parseAmount(body.amount)
@@ -423,7 +441,7 @@ fun serverMain() {
              * bank account details)
              */
             post("/bank-accounts/collected-transactions") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val body = call.receive<CollectedTransaction>()
                 if (body.transport != null) {
                     when (body.transport.type) {
@@ -459,7 +477,7 @@ fun serverMain() {
              * Asks list of transactions ALREADY downloaded from the bank.
              */
             get("/bank-accounts/{accountid}/collected-transactions") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val bankAccount = expectNonNull(call.parameters["accountid"])
                 val start = call.request.queryParameters["start"]
                 val end = call.request.queryParameters["end"]
@@ -493,7 +511,7 @@ fun serverMain() {
              * Adds a new bank transport.
              */
             post("/bank-transports") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 // user exists and is authenticated.
                 val body = call.receive<JsonObject>()
                 val transport: Transport = getTransportFromJsonObject(body)
@@ -594,7 +612,7 @@ fun serverMain() {
              * "transportName".  Does not modify any DB table.
              */
             post("/bank-transports/send{MSG}") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val body = call.receive<Transport>()
                 when (body.type) {
                     "ebics" -> {
@@ -619,7 +637,7 @@ fun serverMain() {
              * "transportName".  DOES alterate DB tables.
              */
             post("/bank-transports/sync{MSG}") {
-                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
                 val body = call.receive<Transport>()
                 when (body.type) {
                     "ebics" -> {
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
index f3dd614..2b6b3ff 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
@@ -220,7 +220,7 @@ class Taler(app: Route) {
             return@get
         }
         app.post("/taler/transfer") {
-            val exchangeId = 
authenticateRequest(call.request.headers["Authorization"])
+            val exchangeId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
             val transferRequest = call.receive<TalerTransferRequest>()
             val amountObj = parseAmount(transferRequest.amount)
             val creditorObj = parsePayto(transferRequest.credit_account)
@@ -304,7 +304,7 @@ class Taler(app: Route) {
         }
         /** Test-API that creates one new payment addressed to the exchange.  
*/
         app.post("/taler/admin/add-incoming") {
-            val exchangeId = 
authenticateRequest(call.request.headers["Authorization"])
+            val exchangeId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
             val addIncomingData = call.receive<TalerAdminAddIncoming>()
             val debtor = parsePayto(addIncomingData.debit_account)
             val amount = parseAmount(addIncomingData.amount)
@@ -351,7 +351,7 @@ class Taler(app: Route) {
          * places it into a further table.  Eventually, another routine will 
perform
          * all the prepared payments.  */
         
app.post("/ebics/taler/{id}/accounts/{acctid}/refund-invalid-payments") {
-            val userId = 
authenticateRequest(call.request.headers["Authorization"])
+            val userId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
             val nexusUser = getNexusUser(userId)
             val callerBankAccount = expectNonNull(call.parameters["acctid"])
             transaction {
@@ -477,7 +477,7 @@ class Taler(app: Route) {
          */
         app.get("/taler/history/outgoing") {
             /* sanitize URL arguments */
-            val subscriberId = 
authenticateRequest(call.request.headers["Authorization"])
+            val subscriberId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
             val delta: Int = expectInt(call.expectUrlParameter("delta"))
             val start: Long = 
handleStartArgument(call.request.queryParameters["start"], delta)
             val startCmpOp = getComparisonOperator(delta, start, 
TalerRequestedPayments)
@@ -514,7 +514,7 @@ class Taler(app: Route) {
         }
         /** Responds only with the valid incoming payments */
         app.get("/taler/history/incoming") {
-            val exchangeId = 
authenticateRequest(call.request.headers["Authorization"])
+            val exchangeId = transaction { 
authenticateRequest(call.request.headers["Authorization"]).id.value }
             val delta: Int = expectInt(call.expectUrlParameter("delta"))
             val start: Long = 
handleStartArgument(call.request.queryParameters["start"], delta)
             val history = TalerIncomingHistory()
diff --git a/util/src/test/kotlin/EbicsMessagesTest.kt 
b/util/src/test/kotlin/EbicsMessagesTest.kt
index e7f2cf1..4c0032c 100644
--- a/util/src/test/kotlin/EbicsMessagesTest.kt
+++ b/util/src/test/kotlin/EbicsMessagesTest.kt
@@ -10,7 +10,6 @@ import tech.libeufin.util.ebics_hev.SystemReturnCodeType
 import tech.libeufin.util.ebics_s001.SignatureTypes
 import tech.libeufin.util.CryptoUtil
 import tech.libeufin.util.XMLUtil
-import tech.libeufin.util.ebics_h004.*
 import javax.xml.datatype.DatatypeFactory
 import kotlin.test.assertNotNull
 import kotlin.test.assertTrue

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

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