Merge pull request #717 from corda/os-merge-ecce64b

O/S merge from ecce64b
This commit is contained in:
Shams Asari 2018-04-11 13:25:54 +01:00 committed by GitHub
commit 973f6c0c08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 22 additions and 37 deletions

View File

@ -43,6 +43,7 @@ import java.io.*
import java.lang.reflect.Field import java.lang.reflect.Field
import java.math.BigDecimal import java.math.BigDecimal
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.HttpURLConnection.HTTP_OK
import java.net.URL import java.net.URL
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.charset.Charset import java.nio.charset.Charset
@ -362,10 +363,11 @@ val KClass<*>.packageName: String get() = java.`package`.name
fun URL.openHttpConnection(): HttpURLConnection = openConnection() as HttpURLConnection fun URL.openHttpConnection(): HttpURLConnection = openConnection() as HttpURLConnection
fun URL.post(serializedData: OpaqueBytes): ByteArray { fun URL.post(serializedData: OpaqueBytes, vararg properties: Pair<String, String>): ByteArray {
return openHttpConnection().run { return openHttpConnection().run {
doOutput = true doOutput = true
requestMethod = "POST" requestMethod = "POST"
properties.forEach { (key, value) -> setRequestProperty(key, value) }
setRequestProperty("Content-Type", "application/octet-stream") setRequestProperty("Content-Type", "application/octet-stream")
outputStream.use { serializedData.open().copyTo(it) } outputStream.use { serializedData.open().copyTo(it) }
checkOkResponse() checkOkResponse()
@ -374,12 +376,13 @@ fun URL.post(serializedData: OpaqueBytes): ByteArray {
} }
fun HttpURLConnection.checkOkResponse() { fun HttpURLConnection.checkOkResponse() {
if (responseCode != 200) { if (responseCode != HTTP_OK) {
val message = errorStream.use { it.reader().readText() } throw IOException("Response Code $responseCode: $errorMessage")
throw IOException("Response Code $responseCode: $message")
} }
} }
val HttpURLConnection.errorMessage: String? get() = errorStream?.let { it.use { it.reader().readText() } }
inline fun <reified T : Any> HttpURLConnection.responseAs(): T { inline fun <reified T : Any> HttpURLConnection.responseAs(): T {
checkOkResponse() checkOkResponse()
return inputStream.readObject() return inputStream.readObject()

View File

@ -20,6 +20,7 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.CertRole import net.corda.core.internal.CertRole
import net.corda.core.internal.errorMessage
import net.corda.core.internal.post import net.corda.core.internal.post
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
@ -28,7 +29,6 @@ import net.corda.node.utilities.registration.cacheControl
import net.corda.nodeapi.internal.crypto.* import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
import net.corda.testing.internal.createDevIntermediateCaCertPath import net.corda.testing.internal.createDevIntermediateCaCertPath
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.ASN1ObjectIdentifier import org.bouncycastle.asn1.ASN1ObjectIdentifier
import org.bouncycastle.asn1.DERUTF8String import org.bouncycastle.asn1.DERUTF8String
@ -47,7 +47,6 @@ import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.HttpURLConnection.* import java.net.HttpURLConnection.*
import java.net.URL import java.net.URL
import java.nio.charset.StandardCharsets.UTF_8
import java.security.KeyPair import java.security.KeyPair
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
@ -252,8 +251,8 @@ class RegistrationWebServiceTest : TestBase() {
} }
PollResponse.Ready(certificates) PollResponse.Ready(certificates)
} }
HTTP_NO_CONTENT -> PollResponse.NotReady(conn.cacheControl().maxAgeSeconds()) HTTP_NO_CONTENT -> PollResponse.NotReady(conn.cacheControl.maxAgeSeconds())
HTTP_UNAUTHORIZED -> PollResponse.Unauthorised(IOUtils.toString(conn.errorStream, UTF_8)) HTTP_UNAUTHORIZED -> PollResponse.Unauthorised(conn.errorMessage)
else -> throw IOException("Cannot connect to Certificate Signing Server, HTTP response code : ${conn.responseCode}") else -> throw IOException("Cannot connect to Certificate Signing Server, HTTP response code : ${conn.responseCode}")
} }
} }
@ -269,6 +268,6 @@ class RegistrationWebServiceTest : TestBase() {
private interface PollResponse { private interface PollResponse {
data class NotReady(val pollInterval: Int) : PollResponse data class NotReady(val pollInterval: Int) : PollResponse
data class Ready(val certChain: List<X509Certificate>) : PollResponse data class Ready(val certChain: List<X509Certificate>) : PollResponse
data class Unauthorised(val message: String) : PollResponse data class Unauthorised(val message: String?) : PollResponse
} }
} }

View File

@ -58,7 +58,7 @@ class NetworkMapClient(compatibilityZoneURL: URL, val trustedRoot: X509Certifica
val connection = networkMapUrl.openHttpConnection() val connection = networkMapUrl.openHttpConnection()
val signedNetworkMap = connection.responseAs<SignedNetworkMap>() val signedNetworkMap = connection.responseAs<SignedNetworkMap>()
val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot) val networkMap = signedNetworkMap.verifiedNetworkMapCert(trustedRoot)
val timeout = connection.cacheControl().maxAgeSeconds().seconds val timeout = connection.cacheControl.maxAgeSeconds().seconds
logger.trace { "Fetched network map update from $networkMapUrl successfully: $networkMap" } logger.trace { "Fetched network map update from $networkMapUrl successfully: $networkMap" }
return NetworkMapResponse(networkMap, timeout) return NetworkMapResponse(networkMap, timeout)
} }

View File

@ -10,13 +10,14 @@
package net.corda.node.utilities.registration package net.corda.node.utilities.registration
import com.google.common.net.MediaType import net.corda.core.internal.errorMessage
import net.corda.core.internal.openHttpConnection import net.corda.core.internal.openHttpConnection
import net.corda.core.internal.post
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.seconds 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.CacheControl
import okhttp3.Headers import okhttp3.Headers
import org.apache.commons.io.IOUtils
import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.PKCS10CertificationRequest
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
@ -31,7 +32,7 @@ class HTTPNetworkRegistrationService(compatibilityZoneURL: URL) : NetworkRegistr
companion object { companion object {
// TODO: Propagate version information from gradle // TODO: Propagate version information from gradle
val clientVersion = "1.0" const val CLIENT_VERSION = "1.0"
} }
@Throws(CertificateRequestException::class) @Throws(CertificateRequestException::class)
@ -39,7 +40,7 @@ class HTTPNetworkRegistrationService(compatibilityZoneURL: URL) : NetworkRegistr
// 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() val maxAge = conn.cacheControl.maxAgeSeconds()
// Default poll interval to 10 seconds if not specified by the server, for backward compatibility. // 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 val pollInterval = if (maxAge == -1) 10.seconds else maxAge.seconds
@ -54,33 +55,15 @@ class HTTPNetworkRegistrationService(compatibilityZoneURL: URL) : NetworkRegistr
} }
HTTP_NO_CONTENT -> CertificateResponse(pollInterval, 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 -> throw IOException("Response Code ${conn.responseCode}: ${conn.errorMessage}")
} }
} }
override fun submitRequest(request: PKCS10CertificationRequest): String { override fun submitRequest(request: PKCS10CertificationRequest): String {
// Post request to certificate signing server via http. return String(registrationURL.post(OpaqueBytes(request.encoded), "Client-Version" to CLIENT_VERSION))
val conn = URL("$registrationURL").openHttpConnection()
conn.doOutput = true
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", MediaType.OCTET_STREAM.toString())
conn.setRequestProperty("Client-Version", clientVersion)
conn.outputStream.write(request.encoded)
return when (conn.responseCode) {
HTTP_OK -> IOUtils.toString(conn.inputStream, conn.charset)
HTTP_FORBIDDEN -> throw IOException("Client version $clientVersion is forbidden from accessing permissioning server, please upgrade to newer version.")
else -> throwUnexpectedResponseCode(conn)
} }
} }
private fun throwUnexpectedResponseCode(connection: HttpURLConnection): Nothing { val HttpURLConnection.cacheControl: CacheControl get() {
throw IOException("Unexpected response code ${connection.responseCode} - ${connection.errorMessage}") return CacheControl.parse(Headers.of(headerFields.filterKeys { it != null }.mapValues { it.value[0] }))
} }
private val HttpURLConnection.charset: String get() = MediaType.parse(contentType).charset().or(Charsets.UTF_8).name()
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] }))