[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] branch master updated (8868572 -> c98ef14)
From: |
gnunet |
Subject: |
[libeufin] branch master updated (8868572 -> c98ef14) |
Date: |
Wed, 06 Nov 2019 11:02:44 +0100 |
This is an automated email from the git hooks/post-receive script.
marcello pushed a change to branch master
in repository libeufin.
from 8868572 HTD order type JAXB and test
new 9bdeeec Implement /ebics/subscribers (nexus).
new d44eef4 craft INI message to send (nexus)
new a61adff use the ".apply {}" notation
new aed6728 nexus POSTs INI (hits invalid XML for now)
new f85b013 get INI to validate
new c98ef14 make systemID nullable + catch != 200 responses (nexus)
The 6 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:
nexus/build.gradle | 1 +
nexus/src/main/kotlin/DB.kt | 42 +++-
nexus/src/main/kotlin/JSON.kt | 27 +++
nexus/src/main/kotlin/Main.kt | 214 ++++++++++++++++++++-
.../src/main/kotlin/tech/libeufin/sandbox/JSON.kt | 1 -
5 files changed, 282 insertions(+), 3 deletions(-)
create mode 100644 nexus/src/main/kotlin/JSON.kt
diff --git a/nexus/build.gradle b/nexus/build.gradle
index 5f93162..04c7f1c 100644
--- a/nexus/build.gradle
+++ b/nexus/build.gradle
@@ -32,6 +32,7 @@ dependencies {
implementation group: 'xerces', name: 'xercesImpl', version:
'2.6.2-jaxb-1.0.6'
implementation "javax.activation:activation:1.1"
implementation "org.glassfish.jaxb:jaxb-runtime:2.3.1"
+ implementation 'org.apache.santuario:xmlsec:2.1.4'
testImplementation group: 'junit', name: 'junit', version: '4.12'
}
diff --git a/nexus/src/main/kotlin/DB.kt b/nexus/src/main/kotlin/DB.kt
index 63d1e6b..ac61792 100644
--- a/nexus/src/main/kotlin/DB.kt
+++ b/nexus/src/main/kotlin/DB.kt
@@ -2,4 +2,44 @@ package tech.libeufin.nexus
import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.sql.*
-import org.jetbrains.exposed.sql.transactions.transaction
\ No newline at end of file
+import org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManager
+import org.jetbrains.exposed.sql.transactions.TransactionManager
+import org.jetbrains.exposed.sql.transactions.transaction
+import tech.libeufin.sandbox.EbicsHosts
+import java.sql.Connection
+
+object EbicsSubscribersTable: IntIdTable() {
+ val ebicsURL = text("ebicsURL")
+ val hostID = text("hostID")
+ val partnerID = text("partnerID")
+ val userID = text("userID")
+ val systemID = text("systemID").nullable()
+ val signaturePrivateKey = blob("signaturePrivateKey")
+ val encryptionPrivateKey = blob("encryptionPrivateKey")
+ val authenticationPrivateKey = blob("authenticationPrivateKey")
+}
+
+class EbicsSubscriberEntity(id: EntityID<Int>) : IntEntity(id) {
+ companion object :
IntEntityClass<EbicsSubscriberEntity>(EbicsSubscribersTable)
+
+ var ebicsURL by EbicsSubscribersTable.ebicsURL
+ var hostID by EbicsSubscribersTable.hostID
+ var partnerID by EbicsSubscribersTable.partnerID
+ var userID by EbicsSubscribersTable.userID
+ var systemID by EbicsSubscribersTable.systemID
+ var signaturePrivateKey by EbicsSubscribersTable.signaturePrivateKey
+ var encryptionPrivateKey by EbicsSubscribersTable.encryptionPrivateKey
+ var authenticationPrivateKey by
EbicsSubscribersTable.authenticationPrivateKey
+}
+
+fun dbCreateTables() {
+ Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver =
"org.h2.Driver")
+
+ transaction {
+ // addLogger(StdOutSqlLogger)
+
+ SchemaUtils.create(
+ EbicsSubscribersTable
+ )
+ }
+}
\ No newline at end of file
diff --git a/nexus/src/main/kotlin/JSON.kt b/nexus/src/main/kotlin/JSON.kt
new file mode 100644
index 0000000..4b6c66b
--- /dev/null
+++ b/nexus/src/main/kotlin/JSON.kt
@@ -0,0 +1,27 @@
+package tech.libeufin.nexus
+
+/**
+ * This object is POSTed by clients _after_ having created
+ * a EBICS subscriber at the sandbox.
+ */
+data class EbicsSubscriberInfoRequest(
+ val ebicsURL: String,
+ val hostID: String,
+ val partnerID: String,
+ val userID: String,
+ val systemID: String
+)
+
+/**
+ * Contain the ID that identifies the new user in the Nexus system.
+ */
+data class EbicsSubscriberInfoResponse(
+ val accountID: Number
+)
+
+/**
+ * Error message.
+ */
+data class NexusError(
+ val message: String
+)
\ No newline at end of file
diff --git a/nexus/src/main/kotlin/Main.kt b/nexus/src/main/kotlin/Main.kt
index 07c2efd..c6bdd27 100644
--- a/nexus/src/main/kotlin/Main.kt
+++ b/nexus/src/main/kotlin/Main.kt
@@ -19,32 +19,244 @@
package tech.libeufin.nexus
+import io.ktor.application.ApplicationCallPipeline
import io.ktor.application.call
+import io.ktor.application.install
import io.ktor.client.*
import io.ktor.client.features.ServerResponseException
import io.ktor.client.request.get
+import io.ktor.client.request.post
+import io.ktor.features.ContentNegotiation
+import io.ktor.features.StatusPages
+import io.ktor.gson.gson
+import io.ktor.http.ContentType
+import io.ktor.http.HttpStatusCode
+import io.ktor.http.URLBuilder
+import io.ktor.http.takeFrom
+import io.ktor.request.receive
+import io.ktor.request.uri
+import io.ktor.response.respond
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
+import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory
+import tech.libeufin.sandbox.*
+import tech.libeufin.schema.ebics_h004.EbicsKeyManagementResponse
+import tech.libeufin.schema.ebics_h004.EbicsUnsecuredRequest
+import tech.libeufin.schema.ebics_h004.OrderDetails
+import tech.libeufin.schema.ebics_h004.StaticHeader
+import tech.libeufin.schema.ebics_s001.PubKeyValueType
+import tech.libeufin.schema.ebics_s001.SignaturePubKeyInfoType
+import tech.libeufin.schema.ebics_s001.SignaturePubKeyOrderData
+import java.text.DateFormat
+import javax.sql.rowset.serial.SerialBlob
+
+fun testData() {
+
+ val pairA = CryptoUtil.generateRsaKeyPair(2048)
+ val pairB = CryptoUtil.generateRsaKeyPair(2048)
+ val pairC = CryptoUtil.generateRsaKeyPair(2048)
+
+ transaction {
+ EbicsSubscriberEntity.new {
+ ebicsURL = "http://localhost:5000/ebicsweb"
+ userID = "USER1"
+ partnerID = "PARTNER1"
+ hostID = "host01"
+
+ signaturePrivateKey = SerialBlob(pairA.private.encoded)
+ encryptionPrivateKey = SerialBlob(pairB.private.encoded)
+ authenticationPrivateKey = SerialBlob(pairC.private.encoded)
+ }
+ }
+}
fun main() {
+ dbCreateTables()
+ testData() // gets always id == 1
+ val client = HttpClient()
+
val logger = LoggerFactory.getLogger("tech.libeufin.nexus")
val server = embeddedServer(Netty, port = 5001) {
+ install(ContentNegotiation) {
+ gson {
+ setDateFormat(DateFormat.LONG)
+ setPrettyPrinting()
+ }
+ }
+ install(StatusPages) {
+ exception<Throwable> { cause ->
+ tech.libeufin.sandbox.logger.error("Exception while handling
'${call.request.uri}'", cause)
+ call.respondText("Internal server error.",
ContentType.Text.Plain, HttpStatusCode.InternalServerError)
+ }
+ }
+
+ intercept(ApplicationCallPipeline.Fallback) {
+ if (this.call.response.status() == null) {
+ call.respondText("Not found (no route matched).\n",
ContentType.Text.Plain, HttpStatusCode.NotFound)
+ return@intercept finish()
+ }
+ }
+
routing {
get("/") {
call.respondText("Hello by Nexus!\n")
return@get
}
+ post("/ebics/subscribers") {
+ val body = try {
+ call.receive<EbicsSubscriberInfoRequest>()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ call.respond(
+ HttpStatusCode.BadRequest,
+ NexusError(e.message.toString())
+ )
+ return@post
+ }
+
+ val pairA = CryptoUtil.generateRsaKeyPair(2048)
+ val pairB = CryptoUtil.generateRsaKeyPair(2048)
+ val pairC = CryptoUtil.generateRsaKeyPair(2048)
+
+ val id = transaction {
+
+ EbicsSubscriberEntity.new {
+ ebicsURL = body.ebicsURL
+ hostID = body.hostID
+ partnerID = body.partnerID
+ userID = body.userID
+ systemID = body.systemID
+ signaturePrivateKey = SerialBlob(pairA.private.encoded)
+ encryptionPrivateKey =
SerialBlob(pairB.private.encoded)
+ authenticationPrivateKey =
SerialBlob(pairC.private.encoded)
+
+ }.id.value
+ }
+
+ call.respond(
+ HttpStatusCode.OK,
+ EbicsSubscriberInfoResponse(id)
+ )
+ return@post
+ }
+
+ post("/ebics/subscribers/{id}/sendIni") {
+ // empty body for now..?
+ val id = try {
+ call.parameters["id"]!!.toInt()
+
+ } catch (e: Exception) {
+ e.printStackTrace()
+ call.respond(
+ HttpStatusCode.BadRequest,
+ NexusError(e.message.toString())
+ )
+ return@post
+ }
+
+ val iniRequest = EbicsUnsecuredRequest()
+
+ val url = transaction {
+ val subscriber = EbicsSubscriberEntity.findById(id)
+ val tmpKey =
CryptoUtil.loadRsaPrivateKey(subscriber!!.signaturePrivateKey.toByteArray())
+
+ iniRequest.apply {
+ version = "H004"
+ revision = 1
+ header = EbicsUnsecuredRequest.Header().apply {
+ authenticate = true
+ static = StaticHeader().apply {
+ orderDetails = OrderDetails().apply {
+ orderAttribute = "DZNNN"
+ orderType = "INI"
+ securityMedium = "0000"
+ hostID = subscriber!!.hostID
+ userID = subscriber!!.userID
+ partnerID = subscriber!!.partnerID
+ systemID = subscriber!!.systemID
+ }
+
+ }
+ mutable =
EbicsUnsecuredRequest.Header.EmptyMutableHeader()
+ }
+ body = EbicsUnsecuredRequest.Body().apply {
+ dataTransfer =
EbicsUnsecuredRequest.Body.UnsecuredDataTransfer().apply {
+ orderData =
EbicsUnsecuredRequest.Body.UnsecuredDataTransfer.OrderData().apply {
+ value = EbicsOrderUtil.encodeOrderDataXml(
+ SignaturePubKeyOrderData().apply {
+ signaturePubKeyInfo =
SignaturePubKeyInfoType().apply {
+ signatureVersion = "A006"
+ pubKeyValue =
PubKeyValueType().apply {
+ rsaKeyValue =
org.apache.xml.security.binding.xmldsig.RSAKeyValueType().apply {
+ exponent =
tmpKey.publicExponent.toByteArray()
+ modulus =
tmpKey.modulus.toByteArray()
+ }
+ }
+ }
+ userID = subscriber.userID
+ partnerID = subscriber.partnerID
+
+ }
+ )
+ }
+ }
+ }
+ }
+ subscriber!!.ebicsURL
+ }
+
+ if (iniRequest == null) {
+ call.respond(
+ HttpStatusCode.NotFound,
+ NexusError("Could not find that subscriber")
+ )
+ return@post
+ }
+
+ logger.info("POSTing to ${url}")
+
+ val response = try {
+ client.post<String>(
+ urlString = url,
+ block = {
+ body = XMLUtil.convertJaxbToString(iniRequest)
+ }
+ )
+ } catch (e: Exception) {
+ e.printStackTrace()
+
+ call.respond(
+ HttpStatusCode.OK,
+ NexusError("Exception thrown by HTTP client (likely
server responded != 200).")
+ )
+ return@post
+ }
+
+ /**
+ * TODO: check response status code,
+ * and act accordingly when it differs from 200.
+ */
+
+ // works: val responseJaxb =
XMLUtil.convertStringToJaxb<EbicsKeyManagementResponse>(response)
+
+ call.respond(
+ HttpStatusCode.OK,
+ NexusError("Sandbox responded.")
+ )
+ return@post
+ }
+
post("/nexus") {
- val client = HttpClient()
+
val content = try {
client.get<ByteArray>(
"https://ebicstest1.libeufin.tech/"
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
index 157db79..428b9c4 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
@@ -26,7 +26,6 @@ data class SandboxError(
val message: String
)
-
/**
* Request for POST /admin/customers
*/
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [libeufin] branch master updated (8868572 -> c98ef14),
gnunet <=
- [libeufin] 04/06: nexus POSTs INI (hits invalid XML for now), gnunet, 2019/11/06
- [libeufin] 02/06: craft INI message to send (nexus), gnunet, 2019/11/06
- [libeufin] 01/06: Implement /ebics/subscribers (nexus)., gnunet, 2019/11/06
- [libeufin] 06/06: make systemID nullable + catch != 200 responses (nexus), gnunet, 2019/11/06
- [libeufin] 03/06: use the ".apply {}" notation, gnunet, 2019/11/06
- [libeufin] 05/06: get INI to validate, gnunet, 2019/11/06