mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Merge branch 'release/os/4.5' into denis/merge_os_4.5_to_4.6
This commit is contained in:
commit
e837bb0ca8
@ -43,6 +43,7 @@ import net.corda.coretesting.internal.NettyTestServer
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.checkValidity
|
||||
import net.corda.nodeapi.internal.crypto.getSupportedKey
|
||||
@ -50,6 +51,7 @@ import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
|
||||
import net.corda.nodeapi.internal.crypto.save
|
||||
import net.corda.nodeapi.internal.crypto.toBc
|
||||
import net.corda.nodeapi.internal.crypto.x509
|
||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||
import net.corda.testing.internal.IS_OPENJ9
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@ -570,4 +572,16 @@ class X509UtilitiesTest {
|
||||
cert.checkValidity({ "Error text" }, { }, Date.from(today.toInstant() + 51.days))
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `check certificate serial number`() {
|
||||
val keyPair = generateKeyPair()
|
||||
val subject = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
||||
val cert = X509Utilities.createSelfSignedCACertificate(subject, keyPair)
|
||||
assertTrue(cert.serialNumber.signum() > 0)
|
||||
assertEquals(127, cert.serialNumber.bitLength())
|
||||
val serialized = X509Utilities.buildCertPath(cert).encoded
|
||||
val deserialized = X509CertificateFactory().delegate.generateCertPath(serialized.inputStream()).x509Certificates.first()
|
||||
assertEquals(cert.serialNumber, deserialized.serialNumber)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package net.corda.nodeapi.internal.crypto
|
||||
|
||||
import net.corda.core.CordaOID
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.crypto.newSecureRandom
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.core.utilities.millis
|
||||
@ -35,6 +35,8 @@ import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.experimental.and
|
||||
import kotlin.experimental.or
|
||||
|
||||
object X509Utilities {
|
||||
// Note that this default value only applies to BCCryptoService. Other implementations of CryptoService may have to use different
|
||||
@ -58,6 +60,7 @@ object X509Utilities {
|
||||
const val TLS_CERTIFICATE_DAYS_TO_EXPIRY_WARNING_THRESHOLD = 30
|
||||
private const val KEY_ALIAS_REGEX = "[a-z0-9-]+"
|
||||
private const val KEY_ALIAS_MAX_LENGTH = 100
|
||||
private const val CERTIFICATE_SERIAL_NUMBER_LENGTH = 16
|
||||
|
||||
/**
|
||||
* Checks if the provided key alias does not exceed maximum length and
|
||||
@ -184,7 +187,7 @@ object X509Utilities {
|
||||
nameConstraints: NameConstraints? = null,
|
||||
crlDistPoint: String? = null,
|
||||
crlIssuer: X500Name? = null): X509v3CertificateBuilder {
|
||||
val serial = BigInteger.valueOf(random63BitValue())
|
||||
val serial = generateCertificateSerialNumber()
|
||||
val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } })
|
||||
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded))
|
||||
val role = certificateType.role
|
||||
@ -364,6 +367,15 @@ object X509Utilities {
|
||||
builder.addExtension(Extension.cRLDistributionPoints, false, CRLDistPoint(arrayOf(distPoint)))
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun generateCertificateSerialNumber(): BigInteger {
|
||||
val bytes = ByteArray(CERTIFICATE_SERIAL_NUMBER_LENGTH)
|
||||
newSecureRandom().nextBytes(bytes)
|
||||
// Set highest byte to 01xxxxxx to ensure positive sign and constant bit length.
|
||||
bytes[0] = bytes[0].and(0x3F).or(0x40)
|
||||
return BigInteger(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// Assuming cert type to role is 1:1
|
||||
|
@ -23,9 +23,9 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import java.sql.Connection
|
||||
import java.sql.Statement
|
||||
import java.util.*
|
||||
import javax.sql.DataSource
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
/*
|
||||
@ -34,7 +34,7 @@ import kotlin.test.assertFailsWith
|
||||
*/
|
||||
@RunWith(Parameterized::class)
|
||||
class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) {
|
||||
private lateinit var node: NodeWithInfo
|
||||
private var node: NodeWithInfo? = null
|
||||
private lateinit var client: CordaRPCClient
|
||||
private lateinit var db: UsersDB
|
||||
|
||||
@ -97,8 +97,9 @@ class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) {
|
||||
)
|
||||
)
|
||||
|
||||
node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig)
|
||||
client = CordaRPCClient(node.node.configuration.rpcOptions.address)
|
||||
node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig).also { node ->
|
||||
client = CordaRPCClient(node.node.configuration.rpcOptions.address)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@ -219,6 +220,7 @@ class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) {
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
node?.node?.stop()
|
||||
db.close()
|
||||
}
|
||||
|
||||
@ -232,7 +234,7 @@ private data class RoleAndPermissions(val role: String, val permissions: List<St
|
||||
* Manage in-memory DB mocking a users database with the schema expected by Node's security manager
|
||||
*/
|
||||
private class UsersDB(name: String, users: List<UserAndRoles> = emptyList(), roleAndPermissions: List<RoleAndPermissions> = emptyList()) : AutoCloseable {
|
||||
val jdbcUrl = "jdbc:h2:mem:$name;DB_CLOSE_DELAY=-1"
|
||||
val jdbcUrl = "jdbc:h2:mem:$name"
|
||||
|
||||
companion object {
|
||||
const val DB_CREATE_SCHEMA = """
|
||||
@ -273,36 +275,34 @@ private class UsersDB(name: String, users: List<UserAndRoles> = emptyList(), rol
|
||||
}
|
||||
}
|
||||
|
||||
private val dataSource: DataSource
|
||||
private val connection: Connection
|
||||
private inline fun session(statement: (Statement) -> Unit) {
|
||||
dataSource.connection.use {
|
||||
it.autoCommit = false
|
||||
it.createStatement().use(statement)
|
||||
it.commit()
|
||||
}
|
||||
connection.createStatement().use(statement)
|
||||
connection.commit()
|
||||
}
|
||||
|
||||
init {
|
||||
dataSource = DataSourceFactory.createDataSource(Properties().apply {
|
||||
require(users.map { it.username }.toSet().size == users.size) {
|
||||
"Duplicate username in input"
|
||||
}
|
||||
connection = DataSourceFactory.createDataSource(Properties().apply {
|
||||
put("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||
put("dataSource.url", jdbcUrl)
|
||||
}, false)
|
||||
.connection
|
||||
.apply {
|
||||
autoCommit = false
|
||||
}
|
||||
session {
|
||||
it.execute(DB_CREATE_SCHEMA)
|
||||
}
|
||||
require(users.map { it.username }.toSet().size == users.size) {
|
||||
"Duplicate username in input"
|
||||
}
|
||||
users.forEach { insert(it) }
|
||||
roleAndPermissions.forEach { insert(it) }
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
dataSource.connection.use {
|
||||
it.createStatement().use {
|
||||
it.execute("DROP ALL OBJECTS")
|
||||
}
|
||||
}
|
||||
// Close the connection, at which point the database will shut down
|
||||
connection.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
|
||||
import net.corda.testing.node.internal.enclosedCordapp
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -29,6 +30,7 @@ import kotlin.test.assertEquals
|
||||
* Check that we can add lots of large attachments to a transaction and that it works OK, e.g. does not hit the
|
||||
* transaction size limit (which should only consider the hashes).
|
||||
*/
|
||||
@Ignore("ENT-5679: This test triggers OOM errors")
|
||||
class LargeTransactionsTest {
|
||||
private companion object {
|
||||
val BOB = TestIdentity(BOB_NAME, 80).party
|
||||
|
@ -52,6 +52,7 @@ import kotlin.test.assertTrue
|
||||
class VaultObserverExceptionTest {
|
||||
companion object {
|
||||
|
||||
val waitForFlowDuration = 45.seconds
|
||||
val log = contextLogger()
|
||||
|
||||
private fun testCordapps() = listOf(
|
||||
@ -99,7 +100,7 @@ class VaultObserverExceptionTest {
|
||||
"Syntax Error in Custom SQL",
|
||||
CreateStateFlow.errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError)
|
||||
).returnValue.then { testControlFuture.complete(false) }
|
||||
val foundExpectedException = testControlFuture.getOrThrow(30.seconds)
|
||||
val foundExpectedException = testControlFuture.getOrThrow(waitForFlowDuration)
|
||||
|
||||
Assert.assertTrue(foundExpectedException)
|
||||
}
|
||||
@ -133,7 +134,7 @@ class VaultObserverExceptionTest {
|
||||
"Syntax Error in Custom SQL",
|
||||
CreateStateFlow.errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError)
|
||||
).returnValue.then { testControlFuture.complete(false) }
|
||||
val foundExpectedException = testControlFuture.getOrThrow(30.seconds)
|
||||
val foundExpectedException = testControlFuture.getOrThrow(waitForFlowDuration)
|
||||
|
||||
Assert.assertTrue(foundExpectedException)
|
||||
}
|
||||
@ -224,7 +225,7 @@ class VaultObserverExceptionTest {
|
||||
assertFailsWith<TimeoutException>("PersistenceException") {
|
||||
aliceNode.rpc.startFlow(CreateStateFlow::Initiator, "EntityManager", errorTargetsToNum(
|
||||
CreateStateFlow.ErrorTarget.TxInvalidState))
|
||||
.returnValue.getOrThrow(30.seconds)
|
||||
.returnValue.getOrThrow(waitForFlowDuration)
|
||||
}
|
||||
}
|
||||
Assert.assertTrue("Flow has not been to hospital", counter > 0)
|
||||
@ -260,7 +261,7 @@ class VaultObserverExceptionTest {
|
||||
CreateStateFlow.ErrorTarget.TxInvalidState,
|
||||
CreateStateFlow.ErrorTarget.FlowSwallowErrors))
|
||||
val flowResult = flowHandle.returnValue
|
||||
assertFailsWith<TimeoutException>("PersistenceException") { flowResult.getOrThrow(30.seconds) }
|
||||
assertFailsWith<TimeoutException>("PersistenceException") { flowResult.getOrThrow(waitForFlowDuration) }
|
||||
Assert.assertTrue("Flow has not been to hospital", counter > 0)
|
||||
}
|
||||
}
|
||||
@ -291,7 +292,7 @@ class VaultObserverExceptionTest {
|
||||
log.info("Flow has finished")
|
||||
testControlFuture.set(false)
|
||||
}
|
||||
Assert.assertTrue("Flow has not been kept in hospital", testControlFuture.getOrThrow(30.seconds))
|
||||
Assert.assertTrue("Flow has not been kept in hospital", testControlFuture.getOrThrow(waitForFlowDuration))
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,7 +311,7 @@ class VaultObserverExceptionTest {
|
||||
CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError,
|
||||
CreateStateFlow.ErrorTarget.ServiceSwallowErrors))
|
||||
val flowResult = flowHandle.returnValue
|
||||
flowResult.getOrThrow(30.seconds)
|
||||
flowResult.getOrThrow(waitForFlowDuration)
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,7 +412,7 @@ class VaultObserverExceptionTest {
|
||||
testControlFuture.complete(true)
|
||||
}
|
||||
startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser), startInSameProcess = true).getOrThrow()
|
||||
assert(testControlFuture.getOrThrow(30.seconds))
|
||||
assert(testControlFuture.getOrThrow(waitForFlowDuration))
|
||||
} else {
|
||||
throw IllegalStateException("Out of process node is still up and running!")
|
||||
}
|
||||
@ -464,7 +465,7 @@ class VaultObserverExceptionTest {
|
||||
CreateStateFlow::Initiator,
|
||||
"AllGood",
|
||||
errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed)
|
||||
).returnValue.getOrThrow(30.seconds)
|
||||
).returnValue.getOrThrow(waitForFlowDuration)
|
||||
|
||||
println("Created new state")
|
||||
|
||||
@ -558,7 +559,7 @@ class VaultObserverExceptionTest {
|
||||
"AllGood",
|
||||
// should be a hospital exception
|
||||
errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed)
|
||||
).returnValue.getOrThrow(30.seconds)
|
||||
).returnValue.getOrThrow(waitForFlowDuration)
|
||||
|
||||
val flowHandle = aliceNode.rpc.startFlow(
|
||||
SendStateFlow::PassErroneousOwnableState,
|
||||
@ -642,7 +643,7 @@ class VaultObserverExceptionTest {
|
||||
CreateStateFlow::Initiator,
|
||||
"AllGood",
|
||||
errorTargetsToNum(CreateStateFlow.ErrorTarget.NoError)
|
||||
).returnValue.getOrThrow(30.seconds)
|
||||
).returnValue.getOrThrow(waitForFlowDuration)
|
||||
|
||||
aliceNode.rpc.startFlow(
|
||||
SendStateFlow::PassErroneousOwnableState,
|
||||
@ -722,7 +723,7 @@ class VaultObserverExceptionTest {
|
||||
CreateStateFlow::Initiator,
|
||||
"AllGood",
|
||||
errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed)
|
||||
).returnValue.getOrThrow(30.seconds)
|
||||
).returnValue.getOrThrow(waitForFlowDuration)
|
||||
|
||||
val flowHandle = aliceNode.rpc.startFlow(
|
||||
SendStateFlow::PassErroneousOwnableState,
|
||||
@ -777,7 +778,7 @@ class VaultObserverExceptionTest {
|
||||
"Flow ${SubscribingRawUpdatesFlow::class.java.name} tried to access VaultService.rawUpdates " +
|
||||
"- Rx.Observables should only be accessed outside the context of a flow "
|
||||
) {
|
||||
flowHandle.returnValue.getOrThrow(30.seconds)
|
||||
flowHandle.returnValue.getOrThrow(waitForFlowDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user