mirror of
https://github.com/corda/corda.git
synced 2024-12-22 14:22:28 +00:00
* set network registration poll interval via http cache control header from the server side * default poll interval to 10 seconds if cache header not found * address PR issues * address PR issues (cherry picked from commitdca8699
) (cherry picked from commit258b562
)
This commit is contained in:
parent
c90dba1eb0
commit
c6f01dc274
@ -14,6 +14,7 @@ import net.corda.core.utilities.seconds
|
|||||||
import net.corda.core.utilities.trace
|
import net.corda.core.utilities.trace
|
||||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||||
import net.corda.node.utilities.NamedThreadFactory
|
import net.corda.node.utilities.NamedThreadFactory
|
||||||
|
import net.corda.node.utilities.registration.cacheControl
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
@ -54,7 +55,7 @@ class NetworkMapClient(compatibilityZoneURL: URL, private val trustedRoot: X509C
|
|||||||
val connection = networkMapUrl.openHttpConnection()
|
val connection = networkMapUrl.openHttpConnection()
|
||||||
val signedNetworkMap = connection.responseAs<SignedDataWithCert<NetworkMap>>()
|
val signedNetworkMap = connection.responseAs<SignedDataWithCert<NetworkMap>>()
|
||||||
val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot)
|
val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot)
|
||||||
val timeout = CacheControl.parse(Headers.of(connection.headerFields.filterKeys { it != null }.mapValues { it.value[0] })).maxAgeSeconds().seconds
|
val timeout = connection.cacheControl().maxAgeSeconds().seconds
|
||||||
logger.trace { "Fetched network map update from $networkMapUrl successfully, retrieved ${networkMap.nodeInfoHashes.size} node info hashes. Node Info hashes: ${networkMap.nodeInfoHashes.joinToString("\n")}" }
|
logger.trace { "Fetched network map update from $networkMapUrl successfully, retrieved ${networkMap.nodeInfoHashes.size} node info hashes. Node Info hashes: ${networkMap.nodeInfoHashes.joinToString("\n")}" }
|
||||||
return NetworkMapResponse(networkMap, timeout)
|
return NetworkMapResponse(networkMap, timeout)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,10 @@ package net.corda.node.utilities.registration
|
|||||||
|
|
||||||
import com.google.common.net.MediaType
|
import com.google.common.net.MediaType
|
||||||
import net.corda.core.internal.openHttpConnection
|
import net.corda.core.internal.openHttpConnection
|
||||||
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||||
|
import okhttp3.CacheControl
|
||||||
|
import okhttp3.Headers
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -22,10 +25,13 @@ class HTTPNetworkRegistrationService(compatibilityZoneURL: URL) : NetworkRegistr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CertificateRequestException::class)
|
@Throws(CertificateRequestException::class)
|
||||||
override fun retrieveCertificates(requestId: String): List<X509Certificate>? {
|
override fun retrieveCertificates(requestId: String): CertificateResponse {
|
||||||
// Poll server to download the signed certificate once request has been approved.
|
// Poll server to download the signed certificate once request has been approved.
|
||||||
val conn = URL("$registrationURL/$requestId").openHttpConnection()
|
val conn = URL("$registrationURL/$requestId").openHttpConnection()
|
||||||
conn.requestMethod = "GET"
|
conn.requestMethod = "GET"
|
||||||
|
val maxAge = conn.cacheControl().maxAgeSeconds()
|
||||||
|
// Default poll interval to 10 seconds if not specified by the server, for backward compatibility.
|
||||||
|
val pollInterval = if (maxAge == -1) 10.seconds else maxAge.seconds
|
||||||
|
|
||||||
return when (conn.responseCode) {
|
return when (conn.responseCode) {
|
||||||
HTTP_OK -> ZipInputStream(conn.inputStream).use {
|
HTTP_OK -> ZipInputStream(conn.inputStream).use {
|
||||||
@ -34,9 +40,9 @@ class HTTPNetworkRegistrationService(compatibilityZoneURL: URL) : NetworkRegistr
|
|||||||
while (it.nextEntry != null) {
|
while (it.nextEntry != null) {
|
||||||
certificates += factory.generateCertificate(it)
|
certificates += factory.generateCertificate(it)
|
||||||
}
|
}
|
||||||
certificates
|
CertificateResponse(pollInterval, certificates)
|
||||||
}
|
}
|
||||||
HTTP_NO_CONTENT -> null
|
HTTP_NO_CONTENT -> CertificateResponse(pollInterval, null)
|
||||||
HTTP_UNAUTHORIZED -> throw CertificateRequestException("Certificate signing request has been rejected: ${conn.errorMessage}")
|
HTTP_UNAUTHORIZED -> throw CertificateRequestException("Certificate signing request has been rejected: ${conn.errorMessage}")
|
||||||
else -> throwUnexpectedResponseCode(conn)
|
else -> throwUnexpectedResponseCode(conn)
|
||||||
}
|
}
|
||||||
@ -66,3 +72,5 @@ class HTTPNetworkRegistrationService(compatibilityZoneURL: URL) : NetworkRegistr
|
|||||||
|
|
||||||
private val HttpURLConnection.errorMessage: String get() = IOUtils.toString(errorStream, charset)
|
private val HttpURLConnection.errorMessage: String get() = IOUtils.toString(errorStream, charset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun HttpURLConnection.cacheControl(): CacheControl = CacheControl.parse(Headers.of(headerFields.filterKeys { it != null }.mapValues { it.value[0] }))
|
||||||
|
@ -3,7 +3,6 @@ package net.corda.node.utilities.registration
|
|||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.utilities.seconds
|
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
@ -28,7 +27,6 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration,
|
|||||||
networkRootTrustStorePath: Path,
|
networkRootTrustStorePath: Path,
|
||||||
networkRootTruststorePassword: String) {
|
networkRootTruststorePassword: String) {
|
||||||
private companion object {
|
private companion object {
|
||||||
val pollInterval = 10.seconds
|
|
||||||
const val SELF_SIGNED_PRIVATE_KEY = "Self Signed Private Key"
|
const val SELF_SIGNED_PRIVATE_KEY = "Self Signed Private Key"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,17 +146,18 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration,
|
|||||||
* Poll Certificate Signing Server for approved certificate,
|
* Poll Certificate Signing Server for approved certificate,
|
||||||
* enter a slow polling loop if server return null.
|
* enter a slow polling loop if server return null.
|
||||||
* @param requestId Certificate signing request ID.
|
* @param requestId Certificate signing request ID.
|
||||||
* @return Map of certificate chain.
|
* @return List of certificate chain.
|
||||||
*/
|
*/
|
||||||
private fun pollServerForCertificates(requestId: String): List<X509Certificate> {
|
private fun pollServerForCertificates(requestId: String): List<X509Certificate> {
|
||||||
println("Start polling server for certificate signing approval.")
|
println("Start polling server for certificate signing approval.")
|
||||||
// Poll server to download the signed certificate once request has been approved.
|
// Poll server to download the signed certificate once request has been approved.
|
||||||
var certificates = certService.retrieveCertificates(requestId)
|
while (true) {
|
||||||
while (certificates == null) {
|
val (pollInterval, certificates) = certService.retrieveCertificates(requestId)
|
||||||
|
if (certificates != null) {
|
||||||
|
return certificates
|
||||||
|
}
|
||||||
Thread.sleep(pollInterval.toMillis())
|
Thread.sleep(pollInterval.toMillis())
|
||||||
certificates = certService.retrieveCertificates(requestId)
|
|
||||||
}
|
}
|
||||||
return certificates
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,6 +4,7 @@ import net.corda.core.CordaException
|
|||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
interface NetworkRegistrationService {
|
interface NetworkRegistrationService {
|
||||||
/** Submits a CSR to the signing service and returns an opaque request ID. */
|
/** Submits a CSR to the signing service and returns an opaque request ID. */
|
||||||
@ -11,8 +12,10 @@ interface NetworkRegistrationService {
|
|||||||
|
|
||||||
/** Poll Certificate Signing Server for the request and returns a chain of certificates if request has been approved, null otherwise. */
|
/** Poll Certificate Signing Server for the request and returns a chain of certificates if request has been approved, null otherwise. */
|
||||||
@Throws(CertificateRequestException::class)
|
@Throws(CertificateRequestException::class)
|
||||||
fun retrieveCertificates(requestId: String): List<X509Certificate>?
|
fun retrieveCertificates(requestId: String): CertificateResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class CertificateResponse(val pollInterval: Duration, val certificates: List<X509Certificate>?)
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
class CertificateRequestException(message: String) : CordaException(message)
|
class CertificateRequestException(message: String) : CordaException(message)
|
||||||
|
@ -12,6 +12,7 @@ import net.corda.core.identity.CordaX500Name
|
|||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.createDirectories
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.x500Name
|
import net.corda.core.internal.x500Name
|
||||||
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
@ -158,7 +159,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
private fun createRegistrationHelper(response: List<X509Certificate>): NetworkRegistrationHelper {
|
private fun createRegistrationHelper(response: List<X509Certificate>): NetworkRegistrationHelper {
|
||||||
val certService = rigorousMock<NetworkRegistrationService>().also {
|
val certService = rigorousMock<NetworkRegistrationService>().also {
|
||||||
doReturn(requestId).whenever(it).submitRequest(any())
|
doReturn(requestId).whenever(it).submitRequest(any())
|
||||||
doReturn(response).whenever(it).retrieveCertificates(eq(requestId))
|
doReturn(CertificateResponse(5.seconds, response)).whenever(it).retrieveCertificates(eq(requestId))
|
||||||
}
|
}
|
||||||
return NetworkRegistrationHelper(config, certService, config.certificatesDirectory / networkRootTrustStoreFileName, networkRootTrustStorePassword)
|
return NetworkRegistrationHelper(config, certService, config.certificatesDirectory / networkRootTrustStoreFileName, networkRootTrustStorePassword)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user