Rename netpermission to doorman

This commit is contained in:
Patrick Kuo 2017-02-06 14:56:00 +00:00
parent 0c1a6aad6b
commit 6ff8d73402
9 changed files with 55 additions and 56 deletions

View File

@ -13,9 +13,9 @@ repositories {
} }
} }
task buildCertSignerJAR(type: FatCapsule, dependsOn: 'jar') { task buildDoormanJAR(type: FatCapsule, dependsOn: 'jar') {
applicationClass 'com.r3.corda.netpermission.MainKt' applicationClass 'com.r3.corda.doorman.MainKt'
archiveName 'certSigner.jar' archiveName 'doorman.jar'
capsuleManifest { capsuleManifest {
systemProperties['log4j.configuration'] = 'log4j2.xml' systemProperties['log4j.configuration'] = 'log4j2.xml'

View File

@ -1,8 +1,8 @@
package com.r3.corda.netpermission.internal package com.r3.corda.doorman
import com.r3.corda.netpermission.internal.persistence.CertificateResponse import com.r3.corda.doorman.persistence.CertificateResponse
import com.r3.corda.netpermission.internal.persistence.CertificationData import com.r3.corda.doorman.persistence.CertificationRequestData
import com.r3.corda.netpermission.internal.persistence.CertificationRequestStorage import com.r3.corda.doorman.persistence.CertificationRequestStorage
import net.corda.core.crypto.X509Utilities.CACertAndKey import net.corda.core.crypto.X509Utilities.CACertAndKey
import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_CA import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_CA
import net.corda.core.crypto.X509Utilities.CORDA_INTERMEDIATE_CA import net.corda.core.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
@ -25,7 +25,7 @@ import javax.ws.rs.core.Response.Status.UNAUTHORIZED
* Provides functionality for asynchronous submission of certificate signing requests and retrieval of the results. * Provides functionality for asynchronous submission of certificate signing requests and retrieval of the results.
*/ */
@Path("") @Path("")
class CertificateSigningService(val intermediateCACertAndKey: CACertAndKey, val rootCert: Certificate, val storage: CertificationRequestStorage) { class DoormanWebService(val intermediateCACertAndKey: CACertAndKey, val rootCert: Certificate, val storage: CertificationRequestStorage) {
@Context lateinit var request: HttpServletRequest @Context lateinit var request: HttpServletRequest
/** /**
* Accept stream of [PKCS10CertificationRequest] from user and persists in [CertificationRequestStorage] for approval. * Accept stream of [PKCS10CertificationRequest] from user and persists in [CertificationRequestStorage] for approval.
@ -42,7 +42,7 @@ class CertificateSigningService(val intermediateCACertAndKey: CACertAndKey, val
// TODO: Certificate signing request verifications. // TODO: Certificate signing request verifications.
// TODO: Use jira api / slack bot to semi automate the approval process? // TODO: Use jira api / slack bot to semi automate the approval process?
// TODO: Acknowledge to user we have received the request via email? // TODO: Acknowledge to user we have received the request via email?
val requestId = storage.saveRequest(CertificationData(request.remoteHost, request.remoteAddr, certificationRequest)) val requestId = storage.saveRequest(CertificationRequestData(request.remoteHost, request.remoteAddr, certificationRequest))
return ok(requestId).build() return ok(requestId).build()
} }

View File

@ -1,8 +1,7 @@
package com.r3.corda.netpermission package com.r3.corda.doorman
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3.corda.netpermission.internal.CertificateSigningService import com.r3.corda.doorman.persistence.DBCertificateRequestStorage
import com.r3.corda.netpermission.internal.persistence.DBCertificateRequestStorage
import joptsimple.ArgumentAcceptingOptionSpec import joptsimple.ArgumentAcceptingOptionSpec
import joptsimple.OptionParser import joptsimple.OptionParser
import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.X509Utilities
@ -30,20 +29,22 @@ import kotlin.system.exitProcess
* The server will require keystorePath, keystore password and key password via command line input. * The server will require keystorePath, keystore password and key password via command line input.
* The Intermediate CA certificate,Intermediate CA private key and Root CA Certificate should use alias name specified in [X509Utilities] * The Intermediate CA certificate,Intermediate CA private key and Root CA Certificate should use alias name specified in [X509Utilities]
*/ */
class CertificateSigningServer(val webServerAddr: HostAndPort, val certSigningService: CertificateSigningService) : Closeable { class DoormanServer(val webServerAddr: HostAndPort, val doormanWebService: DoormanWebService) : Closeable {
companion object { companion object {
val log = loggerFor<CertificateSigningServer>() val log = loggerFor<DoormanServer>()
fun Server.hostAndPort(): HostAndPort {
val connector = server.connectors.first() as ServerConnector
return HostAndPort.fromParts(connector.host, connector.localPort)
}
} }
val server: Server = initWebServer() private val server: Server = initWebServer()
val hostAndPort: HostAndPort get() = server.connectors
.map { it as? ServerConnector }
.filterNotNull()
.map { HostAndPort.fromParts(it.host, it.localPort) }
.first()
override fun close() { override fun close() {
log.info("Shutting down CertificateSigningService...") log.info("Shutting down CertificateSigningService...")
server.stop() server.stop()
server.join()
} }
private fun initWebServer(): Server { private fun initWebServer(): Server {
@ -53,7 +54,7 @@ class CertificateSigningServer(val webServerAddr: HostAndPort, val certSigningSe
addHandler(buildServletContextHandler()) addHandler(buildServletContextHandler())
} }
start() start()
log.info("CertificateSigningService started on ${server.hostAndPort()}") log.info("CertificateSigningService started on $hostAndPort")
} }
} }
@ -62,7 +63,7 @@ class CertificateSigningServer(val webServerAddr: HostAndPort, val certSigningSe
contextPath = "/" contextPath = "/"
val resourceConfig = ResourceConfig().apply { val resourceConfig = ResourceConfig().apply {
// Add your API provider classes (annotated for JAX-RS) here // Add your API provider classes (annotated for JAX-RS) here
register(certSigningService) register(doormanWebService)
} }
val jerseyServlet = ServletHolder(ServletContainer(resourceConfig)).apply { val jerseyServlet = ServletHolder(ServletContainer(resourceConfig)).apply {
initOrder = 0 // Initialise at server start initOrder = 0 // Initialise at server start
@ -79,7 +80,7 @@ object ParamsSpec {
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
val log = CertificateSigningServer.log val log = DoormanServer.log
log.info("Starting certificate signing server.") log.info("Starting certificate signing server.")
try { try {
ParamsSpec.parser.parse(*args) ParamsSpec.parser.parse(*args)
@ -97,9 +98,8 @@ fun main(args: Array<String>) {
// Create DB connection. // Create DB connection.
val (datasource, database) = configureDatabase(config.getProperties("dataSourceProperties")) val (datasource, database) = configureDatabase(config.getProperties("dataSourceProperties"))
val storage = DBCertificateRequestStorage(database) val storage = DBCertificateRequestStorage(database)
val service = CertificateSigningService(intermediateCACertAndKey, rootCA, storage) val service = DoormanWebService(intermediateCACertAndKey, rootCA, storage)
// Background thread approving all request periodically. // Background thread approving all request periodically.
var stopSigner = false var stopSigner = false
@ -123,14 +123,12 @@ fun main(args: Array<String>) {
null null
} }
CertificateSigningServer(HostAndPort.fromParts(config.getString("host"), config.getInt("port")), service).use { DoormanServer(HostAndPort.fromParts(config.getString("host"), config.getInt("port")), service).use {
Runtime.getRuntime().addShutdownHook(thread(false) { Runtime.getRuntime().addShutdownHook(thread(false) {
stopSigner = true stopSigner = true
certSinger?.join() certSinger?.join()
it.close()
datasource.close() datasource.close()
}) })
it.server.join()
} }
} }
} }

View File

@ -1,4 +1,4 @@
package com.r3.corda.netpermission.internal.persistence package com.r3.corda.doorman.persistence
import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.PKCS10CertificationRequest
import java.security.cert.Certificate import java.security.cert.Certificate
@ -11,12 +11,12 @@ interface CertificationRequestStorage {
* Persist [certificationData] in storage for further approval if it's a valid request. If not then it will be automically * Persist [certificationData] in storage for further approval if it's a valid request. If not then it will be automically
* rejected and not subject to any approval process. In both cases a randomly generated request ID is returned. * rejected and not subject to any approval process. In both cases a randomly generated request ID is returned.
*/ */
fun saveRequest(certificationData: CertificationData): String fun saveRequest(certificationData: CertificationRequestData): String
/** /**
* Retrieve certificate singing request and Host/IP information using [requestId]. * Retrieve certificate singing request and Host/IP information using [requestId].
*/ */
fun getRequest(requestId: String): CertificationData? fun getRequest(requestId: String): CertificationRequestData?
/** /**
* Return the response for a previously saved request with ID [requestId]. * Return the response for a previously saved request with ID [requestId].
@ -26,7 +26,7 @@ interface CertificationRequestStorage {
/** /**
* Approve the given request by generating and storing a new certificate using the provided generator. * Approve the given request by generating and storing a new certificate using the provided generator.
*/ */
fun approveRequest(requestId: String, certificateGenerator: (CertificationData) -> Certificate) fun approveRequest(requestId: String, certificateGenerator: (CertificationRequestData) -> Certificate)
/** /**
* Reject the given request using the given reason. * Reject the given request using the given reason.
@ -40,7 +40,7 @@ interface CertificationRequestStorage {
fun getPendingRequestIds(): List<String> fun getPendingRequestIds(): List<String>
} }
data class CertificationData(val hostName: String, val ipAddress: String, val request: PKCS10CertificationRequest) data class CertificationRequestData(val hostName: String, val ipAddress: String, val request: PKCS10CertificationRequest)
sealed class CertificateResponse { sealed class CertificateResponse {
object NotReady : CertificateResponse() object NotReady : CertificateResponse()

View File

@ -1,4 +1,4 @@
package com.r3.corda.netpermission.internal.persistence package com.r3.corda.doorman.persistence
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.commonName import net.corda.core.crypto.commonName
@ -29,7 +29,7 @@ class DBCertificateRequestStorage(private val database: Database) : Certificatio
} }
} }
override fun saveRequest(certificationData: CertificationData): String { override fun saveRequest(certificationData: CertificationRequestData): String {
val legalName = certificationData.request.subject.commonName val legalName = certificationData.request.subject.commonName
val requestId = SecureHash.randomSHA256().toString() val requestId = SecureHash.randomSHA256().toString()
databaseTransaction(database) { databaseTransaction(database) {
@ -83,7 +83,7 @@ class DBCertificateRequestStorage(private val database: Database) : Certificatio
} }
} }
override fun approveRequest(requestId: String, certificateGenerator: (CertificationData) -> Certificate) { override fun approveRequest(requestId: String, certificateGenerator: (CertificationRequestData) -> Certificate) {
databaseTransaction(database) { databaseTransaction(database) {
val request = singleRequestWhere { DataTable.requestId eq requestId and DataTable.processTimestamp.isNull() } val request = singleRequestWhere { DataTable.requestId eq requestId and DataTable.processTimestamp.isNull() }
if (request != null) { if (request != null) {
@ -109,7 +109,7 @@ class DBCertificateRequestStorage(private val database: Database) : Certificatio
} }
} }
override fun getRequest(requestId: String): CertificationData? { override fun getRequest(requestId: String): CertificationRequestData? {
return databaseTransaction(database) { return databaseTransaction(database) {
singleRequestWhere { DataTable.requestId eq requestId } singleRequestWhere { DataTable.requestId eq requestId }
} }
@ -121,10 +121,10 @@ class DBCertificateRequestStorage(private val database: Database) : Certificatio
} }
} }
private fun singleRequestWhere(where: SqlExpressionBuilder.() -> Op<Boolean>): CertificationData? { private fun singleRequestWhere(where: SqlExpressionBuilder.() -> Op<Boolean>): CertificationRequestData? {
return DataTable return DataTable
.select(where) .select(where)
.map { CertificationData(it[DataTable.hostName], it[DataTable.ipAddress], deserializeFromBlob(it[DataTable.request])) } .map { CertificationRequestData(it[DataTable.hostName], it[DataTable.ipAddress], deserializeFromBlob(it[DataTable.request])) }
.singleOrNull() .singleOrNull()
} }
} }

View File

@ -1,12 +1,10 @@
package com.r3.corda.netpermission package com.r3.corda.doorman
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.nhaarman.mockito_kotlin.* import com.nhaarman.mockito_kotlin.*
import com.r3.corda.netpermission.CertificateSigningServer.Companion.hostAndPort import com.r3.corda.doorman.persistence.CertificateResponse
import com.r3.corda.netpermission.internal.CertificateSigningService import com.r3.corda.doorman.persistence.CertificationRequestData
import com.r3.corda.netpermission.internal.persistence.CertificateResponse import com.r3.corda.doorman.persistence.CertificationRequestStorage
import com.r3.corda.netpermission.internal.persistence.CertificationData
import com.r3.corda.netpermission.internal.persistence.CertificationRequestStorage
import net.corda.core.crypto.CertificateStream import net.corda.core.crypto.CertificateStream
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.X509Utilities
@ -27,18 +25,18 @@ import java.util.zip.ZipInputStream
import javax.ws.rs.core.MediaType import javax.ws.rs.core.MediaType
import kotlin.test.assertEquals import kotlin.test.assertEquals
class CertificateSigningServiceTest { class DoormanServiceTest {
private val rootCA = X509Utilities.createSelfSignedCACert("Corda Node Root CA") private val rootCA = X509Utilities.createSelfSignedCACert("Corda Node Root CA")
private val intermediateCA = X509Utilities.createSelfSignedCACert("Corda Node Intermediate CA") private val intermediateCA = X509Utilities.createSelfSignedCACert("Corda Node Intermediate CA")
private lateinit var signingServer: CertificateSigningServer private lateinit var doormanServer: DoormanServer
private fun startSigningServer(storage: CertificationRequestStorage) { private fun startSigningServer(storage: CertificationRequestStorage) {
signingServer = CertificateSigningServer(HostAndPort.fromParts("localhost", 0), CertificateSigningService(intermediateCA, rootCA.certificate, storage)) doormanServer = DoormanServer(HostAndPort.fromParts("localhost", 0), DoormanWebService(intermediateCA, rootCA.certificate, storage))
} }
@After @After
fun close() { fun close() {
signingServer.close() doormanServer.close()
} }
@Test @Test
@ -74,8 +72,8 @@ class CertificateSigningServiceTest {
} }
on { approveRequest(eq(id), any()) }.then { on { approveRequest(eq(id), any()) }.then {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val certGen = it.arguments[1] as ((CertificationData) -> Certificate) val certGen = it.arguments[1] as ((CertificationRequestData) -> Certificate)
val request = CertificationData("", "", X509Utilities.createCertificateSigningRequest("LegalName", "London", "admin@test.com", keyPair)) val request = CertificationRequestData("", "", X509Utilities.createCertificateSigningRequest("LegalName", "London", "admin@test.com", keyPair))
certificateStore[id] = certGen(request) certificateStore[id] = certGen(request)
Unit Unit
} }
@ -123,7 +121,7 @@ class CertificateSigningServiceTest {
} }
private fun submitRequest(request: PKCS10CertificationRequest): String { private fun submitRequest(request: PKCS10CertificationRequest): String {
val conn = URL("http://${signingServer.server.hostAndPort()}/api/certificate").openConnection() as HttpURLConnection val conn = URL("http://${doormanServer.hostAndPort}/api/certificate").openConnection() as HttpURLConnection
conn.doOutput = true conn.doOutput = true
conn.requestMethod = "POST" conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM) conn.setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
@ -132,7 +130,7 @@ class CertificateSigningServiceTest {
} }
private fun pollForResponse(id: String): PollResponse { private fun pollForResponse(id: String): PollResponse {
val url = URL("http://${signingServer.server.hostAndPort()}/api/certificate/$id") val url = URL("http://${doormanServer.hostAndPort}/api/certificate/$id")
val conn = url.openConnection() as HttpURLConnection val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET" conn.requestMethod = "GET"

View File

@ -1,5 +1,8 @@
package com.r3.corda.netpermission.internal.persistence package com.r3.corda.doorman.internal.persistence
import com.r3.corda.doorman.persistence.CertificateResponse
import com.r3.corda.doorman.persistence.CertificationRequestData
import com.r3.corda.doorman.persistence.DBCertificateRequestStorage
import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.X509Utilities
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
@ -119,9 +122,9 @@ class DBCertificateRequestStorageTest {
assertThat(response.message).contains(",") assertThat(response.message).contains(",")
} }
private fun createRequest(legalName: String): Pair<CertificationData, KeyPair> { private fun createRequest(legalName: String): Pair<CertificationRequestData, KeyPair> {
val keyPair = X509Utilities.generateECDSAKeyPairForSSL() val keyPair = X509Utilities.generateECDSAKeyPairForSSL()
val request = CertificationData( val request = CertificationRequestData(
"hostname", "hostname",
"0.0.0.0", "0.0.0.0",
X509Utilities.createCertificateSigningRequest(legalName, "London", "admin@test.com", keyPair)) X509Utilities.createCertificateSigningRequest(legalName, "London", "admin@test.com", keyPair))

View File

@ -7,7 +7,7 @@ include 'core'
include 'node' include 'node'
include 'node:capsule' include 'node:capsule'
include 'client' include 'client'
include 'netpermission' include 'doorman'
include 'experimental' include 'experimental'
include 'experimental:sandbox' include 'experimental:sandbox'
include 'test-utils' include 'test-utils'