diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt index 732f049443..cb86c9af6f 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/NetworkMapStorage.kt @@ -3,6 +3,7 @@ package com.r3.corda.networkmanage.common.persistence import com.r3.corda.networkmanage.common.utils.SignedNetworkMap import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters import net.corda.core.crypto.SecureHash +import net.corda.core.internal.DigitalSignatureWithCert import net.corda.nodeapi.internal.network.NetworkParameters /** @@ -31,26 +32,28 @@ interface NetworkMapStorage { fun saveNetworkMap(signedNetworkMap: SignedNetworkMap) /** - * Return the signed network parameters object which matches the given hash. The hash is that of the underlying - * [NetworkParameters] object and not the `SignedData` object that's returned. + * Retrieve the signed with certificate network parameters by their hash. The hash is that of the underlying + * [NetworkParameters] object and not the `SignedWithCert` object that's returned. + * @return signed network parameters corresponding to the given hash or null if it does not exist (parameters don't exist or they haven't been signed yet) */ fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? /** * Retrieve network map parameters. - * @return current network map parameters or null if they don't exist + * @return signed current network map parameters or null if they don't exist */ - fun getCurrentNetworkParameters(): NetworkParameters? + fun getCurrentSignedNetworkParameters(): SignedNetworkParameters? /** - * Persists given network parameters. - * @return hash corresponding to newly create network parameters entry + * Persists given network parameters with signature if provided. + * @return hash corresponding to newly created network parameters entry */ - fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash + fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash /** * Retrieves the latest (i.e. most recently inserted) network parameters + * Note that they may not have been signed up yet. * @return latest network parameters */ - fun getLatestNetworkParameters(): NetworkParameters + fun getLatestUnsignedNetworkParameters(): NetworkParameters } \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt index 740885dee0..0e328f853a 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentNetworkMapStorage.kt @@ -3,9 +3,9 @@ package com.r3.corda.networkmanage.common.persistence import com.r3.corda.networkmanage.common.persistence.entity.* import com.r3.corda.networkmanage.common.utils.SignedNetworkMap import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters -import com.r3.corda.networkmanage.doorman.signer.LocalSigner import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 +import net.corda.core.internal.DigitalSignatureWithCert import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize @@ -16,7 +16,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence /** * Database implementation of the [NetworkMapStorage] interface */ -class PersistentNetworkMapStorage(private val database: CordaPersistence, private val localSigner: LocalSigner?) : NetworkMapStorage { +class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage { override fun getCurrentNetworkMap(): SignedNetworkMap? { return database.transaction { getCurrentNetworkMapEntity()?.let { @@ -26,11 +26,11 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat } } - override fun getCurrentNetworkParameters(): NetworkParameters? { + override fun getCurrentSignedNetworkParameters(): SignedNetworkParameters? { return database.transaction { getCurrentNetworkMapEntity()?.let { val netParamsHash = it.networkMap.deserialize().networkParameterHash - getNetworkParametersEntity(netParamsHash.toString())?.networkParameters() + getSignedNetworkParameters(netParamsHash) } } } @@ -46,12 +46,8 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat } } - // TODO The signing cannot occur here as it won't work with an HSM. The signed network parameters needs to be persisted - // into the database. override fun getSignedNetworkParameters(hash: SecureHash): SignedNetworkParameters? { - val netParamsBytes = getNetworkParametersEntity(hash.toString())?.parametersBytes ?: return null - val sigWithCert = localSigner!!.signBytes(netParamsBytes) - return SignedNetworkParameters(SerializedBytes(netParamsBytes), sigWithCert) + return getNetworkParametersEntity(hash.toString())?.signedParameters() } override fun getNodeInfoHashes(certificateStatus: CertificateStatus): List { @@ -69,31 +65,32 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence, privat } } - override fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash { + override fun saveNetworkParameters(networkParameters: NetworkParameters, sig: DigitalSignatureWithCert?): SecureHash { return database.transaction { val bytes = networkParameters.serialize().bytes val hash = bytes.sha256() - session.save(NetworkParametersEntity( + session.saveOrUpdate(NetworkParametersEntity( parametersBytes = bytes, - parametersHash = hash.toString() + parametersHash = hash.toString(), + signature = sig?.bytes, + certificate = sig?.by?.encoded )) hash } } - override fun getLatestNetworkParameters(): NetworkParameters = getLatestNetworkParametersEntity().networkParameters() + override fun getLatestUnsignedNetworkParameters(): NetworkParameters = getLatestNetworkParametersEntity().networkParameters() private fun getLatestNetworkParametersEntity(): NetworkParametersEntity { return database.transaction { val builder = session.criteriaBuilder val query = builder.createQuery(NetworkParametersEntity::class.java).run { - // TODO a limit of 1 since we only need the first result from(NetworkParametersEntity::class.java).run { - orderBy(builder.desc(get(NetworkParametersEntity::version.name))) + orderBy(builder.desc(get(NetworkParametersEntity::created.name))) } } - // We just want the last signed entry - session.createQuery(query).resultList.first() + // We just want the last entry + session.createQuery(query).setMaxResults(1).resultList.singleOrNull() ?: throw IllegalArgumentException("No network parameters found in network map storage") } } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkParametersEntity.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkParametersEntity.kt index 639787ed70..ca445a1f02 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkParametersEntity.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/entity/NetworkParametersEntity.kt @@ -1,22 +1,47 @@ package com.r3.corda.networkmanage.common.persistence.entity +import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters +import net.corda.core.internal.DigitalSignatureWithCert +import net.corda.core.internal.SignedDataWithCert +import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize +import net.corda.nodeapi.internal.crypto.X509CertificateFactory import net.corda.nodeapi.internal.network.NetworkParameters +import org.hibernate.annotations.CreationTimestamp +import java.time.Instant import javax.persistence.* @Entity -@Table(name = "network_parameters") +@Table(name = "network_parameters", indexes = arrayOf(Index(name = "IDX_NET_PARAMS_HASH", columnList = "hash"))) class NetworkParametersEntity( @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) - val version: Long? = null, - @Column(name = "hash", length = 64, unique = true) val parametersHash: String, + @CreationTimestamp + val created: Instant = Instant.now(), + @Lob - @Column(name = "bytes") - val parametersBytes: ByteArray + @Column(name = "parameters_bytes") + val parametersBytes: ByteArray, + + // Both of the fields below are nullable, because of the way we sign network map data. NetworkParameters can be + // inserted into database without signature. Then signing service will sign them. + @Lob + @Column(name = "signature") + val signature: ByteArray?, + + @Lob + @Column(name = "certificate") + val certificate: ByteArray? ) { fun networkParameters(): NetworkParameters = parametersBytes.deserialize() + + // Return signed network parameters or null if they haven't been signed yet. + fun signedParameters(): SignedNetworkParameters? { + return if (certificate != null && signature != null) { + val sigWithCert = DigitalSignatureWithCert(X509CertificateFactory().generateCertificate(certificate.inputStream()), signature) + SignedDataWithCert(SerializedBytes(parametersBytes), sigWithCert) + } else null + } } \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt index cafc5e7469..5d3d3b15e8 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/NetworkMapSigner.kt @@ -5,19 +5,33 @@ import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import net.corda.core.internal.SignedDataWithCert import net.corda.core.serialization.serialize import net.corda.nodeapi.internal.network.NetworkMap +import net.corda.nodeapi.internal.network.NetworkParameters class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private val signer: Signer) { /** - * Signs the network map. + * Signs the network map and latest network parameters if they haven't been signed yet. */ fun signNetworkMap() { + // TODO There is no network parameters update process in place yet. We assume that latest parameters are to be used + // in current network map. + val latestNetworkParameters = networkMapStorage.getLatestUnsignedNetworkParameters() + val currentNetworkParameters = networkMapStorage.getCurrentSignedNetworkParameters() + if (currentNetworkParameters?.verified() != latestNetworkParameters) + signNetworkParameters(latestNetworkParameters) val currentSignedNetworkMap = networkMapStorage.getCurrentNetworkMap() val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID) - val networkParameters = networkMapStorage.getLatestNetworkParameters() - val serialisedNetworkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash).serialize() + val serialisedNetworkMap = NetworkMap(nodeInfoHashes, latestNetworkParameters.serialize().hash).serialize() if (serialisedNetworkMap != currentSignedNetworkMap?.raw) { val newSignedNetworkMap = SignedDataWithCert(serialisedNetworkMap, signer.signBytes(serialisedNetworkMap.bytes)) networkMapStorage.saveNetworkMap(newSignedNetworkMap) } } + + /** + * Signs latest inserted network parameters. + */ + fun signNetworkParameters(networkParameters: NetworkParameters) { + val digitalSignature = signer.signObject(networkParameters).sig + networkMapStorage.saveNetworkParameters(networkParameters, digitalSignature) + } } \ No newline at end of file diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt index 40a030c2b0..0fadd2f69c 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/signer/Signer.kt @@ -9,7 +9,7 @@ import net.corda.core.serialization.serialize */ interface Signer { /** - * Signs given bytes. The signing key selction strategy is left to the implementing class. + * Signs given bytes. The signing key selection strategy is left to the implementing class. * @return [DigitalSignatureWithCert] that encapsulates the signature and the certificate path used in the signing process. * @throws [AuthenticationException] if fails authentication */ diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt index 9cce45f4ec..74fe5885b0 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/Main.kt @@ -52,14 +52,15 @@ class NetworkManagementServer : Closeable { } private fun getNetworkMapService(config: NetworkMapConfig, database: CordaPersistence, signer: LocalSigner?, updateNetworkParameters: NetworkParameters?): NodeInfoWebService { - val networkMapStorage = PersistentNetworkMapStorage(database, signer) + val networkMapStorage = PersistentNetworkMapStorage(database) val nodeInfoStorage = PersistentNodeInfoStorage(database) + val localNetworkMapSigner = if (signer != null) NetworkMapSigner(networkMapStorage, signer) else null updateNetworkParameters?.let { // Persisting new network parameters - val currentNetworkParameters = networkMapStorage.getCurrentNetworkParameters() + val currentNetworkParameters = networkMapStorage.getCurrentSignedNetworkParameters() if (currentNetworkParameters == null) { - networkMapStorage.saveNetworkParameters(it) + localNetworkMapSigner?.signNetworkParameters(it) ?: networkMapStorage.saveNetworkParameters(it, null) } else { throw UnsupportedOperationException("Network parameters already exist. Updating them via the file config is not supported yet.") } @@ -67,21 +68,19 @@ class NetworkManagementServer : Closeable { // This call will fail if parameter is null in DB. try { - val latestParameter = networkMapStorage.getLatestNetworkParameters() + val latestParameter = networkMapStorage.getLatestUnsignedNetworkParameters() logger.info("Starting network map service with network parameters : $latestParameter") } catch (e: NoSuchElementException) { logger.error("No network parameter found, please upload new network parameter before starting network map service. The server will now exit.") exitProcess(-1) } - val networkMapSigner = if (signer != null) NetworkMapSigner(networkMapStorage, signer) else null - // Thread sign network map in case of change (i.e. a new node info has been added or a node info has been removed). - if (networkMapSigner != null) { + if (localNetworkMapSigner != null) { val scheduledExecutor = Executors.newScheduledThreadPool(1) val signingThread = Runnable { try { - networkMapSigner.signNetworkMap() + localNetworkMapSigner.signNetworkMap() } catch (e: Exception) { // Log the error and carry on. logger.error("Error encountered when processing node info changes.", e) @@ -141,7 +140,6 @@ class NetworkManagementServer : Closeable { val services = mutableListOf() val serverStatus = NetworkManagementServerStatus() - // TODO: move signing to signing server. startNetworkMap?.let { services += getNetworkMapService(it.config, database, it.signer, it.updateNetworkParameters) } doormanServiceParameter?.let { services += getDoormanService(it, database, doormanSigner, serverStatus) } diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt index 0408aa5f56..57418b3d9c 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/NodeInfoWebService.kt @@ -7,6 +7,7 @@ import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage import com.r3.corda.networkmanage.common.persistence.NodeInfoWithSigned import com.r3.corda.networkmanage.common.utils.SignedNetworkMap +import com.r3.corda.networkmanage.common.utils.SignedNetworkParameters import com.r3.corda.networkmanage.doorman.NetworkMapConfig import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService.Companion.NETWORK_MAP_PATH import net.corda.core.crypto.SecureHash @@ -41,7 +42,7 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage, private val networkMapCache: LoadingCache> = CacheBuilder.newBuilder() .expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS) - .build(CacheLoader.from { _ -> Pair(networkMapStorage.getCurrentNetworkMap(), networkMapStorage.getCurrentNetworkParameters()) }) + .build(CacheLoader.from { _ -> Pair(networkMapStorage.getCurrentNetworkMap(), networkMapStorage.getCurrentSignedNetworkParameters()?.verified()) }) @POST @Path("publish") diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt index 5b8668cfbf..4e25900f68 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/hsm/Main.kt @@ -46,8 +46,7 @@ fun run(parameters: Parameters) { checkNotNull(dataSourceProperties) val database = configureDatabase(dataSourceProperties, databaseConfig) val csrStorage = DBSignedCertificateRequestStorage(database) - // TODO Remove the dependency for a local signer to make signing of network parameters work with an HSM - val networkMapStorage = PersistentNetworkMapStorage(database, localSigner = null) + val networkMapStorage = PersistentNetworkMapStorage(database) val hsmNetworkMapSigningThread = HsmNetworkMapSigner( networkMapStorage, networkMapCertificateName, diff --git a/network-management/src/main/resources/migration/network-manager.changelog-init.xml b/network-management/src/main/resources/migration/network-manager.changelog-init.xml index 59a5f4985e..0b9be92b91 100644 --- a/network-management/src/main/resources/migration/network-manager.changelog-init.xml +++ b/network-management/src/main/resources/migration/network-manager.changelog-init.xml @@ -93,11 +93,13 @@ - + - - + + + + @@ -120,7 +122,7 @@ - + @@ -167,6 +169,11 @@ + + + + + ().apply { verify(networkMapStorage).saveNetworkMap(capture()) val capturedNetworkMap = firstValue.verifiedNetworkMapCert(rootCaCert) - assertEquals(networkParameters.serialize().hash, capturedNetworkMap.networkParameterHash) + assertEquals(latestNetworkParameters.serialize().hash, capturedNetworkMap.networkParameterHash) assertEquals(signedNodeInfoHashes.size, capturedNetworkMap.nodeInfoHashes.size) assertThat(capturedNetworkMap.nodeInfoHashes).containsAll(signedNodeInfoHashes) } @@ -79,7 +87,8 @@ class NetworkMapSignerTest : TestBase() { val signedNetworkMap = networkMap.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate) whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap) whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList()) - whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) + whenever(networkMapStorage.getLatestUnsignedNetworkParameters()).thenReturn(networkParameters) + whenever(networkMapStorage.getCurrentSignedNetworkParameters()).thenReturn(networkParameters.signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)) // when networkMapSigner.signNetworkMap() @@ -95,17 +104,21 @@ class NetworkMapSignerTest : TestBase() { val networkParameters = testNetworkParameters(emptyList()) whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null) whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList()) - whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters) + whenever(networkMapStorage.getLatestUnsignedNetworkParameters()).thenReturn(networkParameters) whenever(signer.signBytes(any())).then { DigitalSignatureWithCert(networkMapCa.certificate, Crypto.doSign(networkMapCa.keyPair.private, it.arguments[0] as ByteArray)) } + whenever(signer.signObject(networkParameters)).then { + val serialised = networkParameters.serialize() + SignedDataWithCert(serialised, signer.signBytes(serialised.bytes)) + } // when networkMapSigner.signNetworkMap() // then // Verify networkMapStorage calls verify(networkMapStorage).getNodeInfoHashes(any()) - verify(networkMapStorage).getLatestNetworkParameters() + verify(networkMapStorage).getLatestUnsignedNetworkParameters() argumentCaptor().apply { verify(networkMapStorage).saveNetworkMap(capture()) val networkMap = firstValue.verifiedNetworkMapCert(rootCaCert) diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt index f615d8d7ff..037daf4892 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/NodeInfoWebServiceTest.kt @@ -56,7 +56,7 @@ class NodeInfoWebServiceTest { @Test fun `submit nodeInfo`() { val networkMapStorage: NetworkMapStorage = mock { - on { getCurrentNetworkParameters() }.thenReturn(testNetworkParameters(emptyList())) + on { getCurrentSignedNetworkParameters() }.thenReturn(testNetworkParameters(emptyList()).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)) } // Create node info. val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB")) @@ -72,7 +72,7 @@ class NodeInfoWebServiceTest { @Test fun `submit old nodeInfo`() { val networkMapStorage: NetworkMapStorage = mock { - on { getCurrentNetworkParameters() }.thenReturn(testNetworkParameters(emptyList(), minimumPlatformVersion = 2)) + on { getCurrentSignedNetworkParameters() }.thenReturn(testNetworkParameters(emptyList(), minimumPlatformVersion = 2).signWithCert(networkMapCa.keyPair.private, networkMapCa.certificate)) } // Create node info. val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1) @@ -88,7 +88,7 @@ class NodeInfoWebServiceTest { @Test fun `submit nodeInfo when no network parameters`() { val networkMapStorage: NetworkMapStorage = mock { - on { getCurrentNetworkParameters() }.thenReturn(null) + on { getCurrentSignedNetworkParameters() }.thenReturn(null) } // Create node info. val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1) @@ -155,7 +155,6 @@ class NodeInfoWebServiceTest { verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash) assertThat(netParamsResponse.verified()).isEqualTo(networkParameters) assertThat(netParamsResponse.sig.by).isEqualTo(networkMapCa.certificate) - assertThatExceptionOfType(IOException::class.java) .isThrownBy { it.doGet("network-parameters/${randomSHA256()}") } .withMessageContaining("404") diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/RegistrationWebServiceTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/RegistrationWebServiceTest.kt index 39a6d58630..dc1b0d1949 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/RegistrationWebServiceTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/doorman/RegistrationWebServiceTest.kt @@ -41,9 +41,9 @@ import javax.ws.rs.core.MediaType import kotlin.test.assertEquals class RegistrationWebServiceTest : TestBase() { + private lateinit var webServer: NetworkManagementWebServer private lateinit var rootCaCert: X509Certificate private lateinit var intermediateCa: CertificateAndKeyPair - private lateinit var webServer: NetworkManagementWebServer @Before fun init() {