Introducing the InputReader interface (#102)

* Introducing the InputReader interface

* Addressing review comments

* Addressing review comments
This commit is contained in:
mkit 2017-11-15 08:36:24 +00:00 committed by GitHub
parent c56ea4088f
commit fffcdb47da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 42 deletions

View File

@ -125,7 +125,7 @@ dependencies {
testCompile "com.nhaarman:mockito-kotlin:0.6.1"
testRuntime "net.corda:corda-rpc:$corda_dependency_version"
testCompile "com.spotify:docker-client:8.9.1"
integrationTestCompile "net.corda:corda-test-utils:$corda_dependency_version"
integrationTestCompile "net.corda:corda-test-common:$corda_dependency_version"
integrationTestRuntime "net.corda:corda-rpc:$corda_dependency_version"
compile('com.atlassian.jira:jira-rest-java-client-core:4.0.0') {

View File

@ -5,12 +5,12 @@ import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.whenever
import com.r3.corda.networkmanage.HsmSimulator
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
import com.r3.corda.networkmanage.hsm.authentication.InputReader
import com.r3.corda.networkmanage.hsm.authentication.createProvider
import com.r3.corda.networkmanage.hsm.configuration.Parameters
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.io.Console
import kotlin.test.assertTrue
class HsmTest {
@ -19,11 +19,11 @@ class HsmTest {
@JvmField
val hsmSimulator: HsmSimulator = HsmSimulator()
private var console: Console? = null
private lateinit var inputReader: InputReader
@Before
fun setUp() {
console = mock()
inputReader = mock()
}
@Test
@ -35,9 +35,9 @@ class HsmTest {
keySpecifier = 1,
keyGroup = "*"
)
whenever(console?.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
whenever(console?.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password.toCharArray())
val authenticator = Authenticator(parameters.createProvider(), console = console)
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)
val authenticator = Authenticator(parameters.createProvider(), inputReader = inputReader)
var executed = false
// when

View File

@ -4,7 +4,6 @@ import CryptoServerJCE.CryptoServerProvider
import com.r3.corda.networkmanage.hsm.configuration.Parameters
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.Console
import java.nio.file.Path
import kotlin.reflect.full.memberProperties
@ -17,7 +16,7 @@ class Authenticator(private val provider: CryptoServerProvider,
private val authKeyFilePath: Path? = null,
private val authKeyFilePass: String? = null,
private val authStrengthThreshold: Int = 2,
val console: Console? = System.console()) {
inputReader: InputReader = ConsoleInputReader()) : InputReader by inputReader {
/**
* Interactively (using console) authenticates a user against the HSM. Once authentication is successful the
@ -32,7 +31,7 @@ class Authenticator(private val provider: CryptoServerProvider,
loop@ while (true) {
val user = if (autoUsername.isNullOrEmpty()) {
print("Enter User Name (or Q to quit): ")
val input = readConsoleLine(console)
val input = readLine()
if (input != null && "q" == input.toLowerCase()) {
authenticated.clear()
break
@ -47,7 +46,7 @@ class Authenticator(private val provider: CryptoServerProvider,
AuthMode.KEY_FILE -> {
println("Authenticating using preconfigured key file")
val password = if (authKeyFilePass == null) {
val input = readPassword("Enter key file password (or Q to quit): ", console)
val input = readPassword("Enter key file password (or Q to quit): ")
if ("q" == input.toLowerCase()) {
authenticated.clear()
break@loop
@ -60,7 +59,7 @@ class Authenticator(private val provider: CryptoServerProvider,
provider.loginSign(user, authKeyFilePath.toString(), password)
}
AuthMode.PASSWORD -> {
val password = readPassword("Enter password (or Q to quit): ", console)
val password = readPassword("Enter password (or Q to quit): ")
if ("q" == password.toLowerCase()) {
authenticated.clear()
break@loop
@ -125,23 +124,4 @@ fun Parameters.createProvider(): CryptoServerProvider {
val provider = CryptoServerProvider(cfg)
cfg.close()
return provider
}
/** Read password from console, do a readLine instead if console is null (e.g. when debugging in IDE). */
internal fun readPassword(fmt: String, console: Console? = System.console()): String {
return if (console != null) {
String(console.readPassword(fmt))
} else {
print(fmt)
readLine()!!
}
}
/** Read console line */
internal fun readConsoleLine(console: Console?): String? {
return if (console == null) {
readLine()
} else {
console.readLine()
}
}

View File

@ -0,0 +1,40 @@
package com.r3.corda.networkmanage.hsm.authentication
/**
* User input reader interface
*/
interface InputReader {
/**
* Reads a single line from user's input.
*/
fun readLine(): String?
/**
* Reads a single line from user's input. The characters from the input are masked while being entered.
* @param format message string displayed before user's input
*/
fun readPassword(format: String): String
}
class ConsoleInputReader : InputReader {
private val console = System.console()
/** Read password from console, do a readLine instead if console is null (e.g. when debugging in IDE). */
override fun readPassword(format: String): String {
return if (console != null) {
String(console.readPassword(format))
} else {
print(format)
kotlin.io.readLine() ?: throw IllegalArgumentException("Password required")
}
}
/** Read console line */
override fun readLine(): String? {
return if (console == null) {
kotlin.io.readLine()
} else {
console.readLine()
}
}
}

View File

@ -1,7 +1,6 @@
package com.r3.corda.networkmanage.hsm.signer
import com.r3.corda.networkmanage.hsm.authentication.Authenticator
import com.r3.corda.networkmanage.hsm.authentication.readPassword
import com.r3.corda.networkmanage.hsm.persistence.ApprovedCertificateRequestData
import com.r3.corda.networkmanage.hsm.persistence.SignedCertificateRequestStorage
import com.r3.corda.networkmanage.hsm.utils.X509Utilities.buildCertPath
@ -36,7 +35,7 @@ class HsmCsrSigner(private val storage: SignedCertificateRequestStorage,
// This should be changed once we allow for more certificates in the chain. Preferably we should use
// keyStore.getCertificateChain(String) and assume entire chain is stored in the HSM (depending on the support).
val caParentCertificate = keyStore.getCertificate(caParentCertificateName)
val caPrivateKeyPass = caPrivateKeyPass ?: readPassword("CA Private Key Password: ", authenticator.console)
val caPrivateKeyPass = caPrivateKeyPass ?: authenticator.readPassword("CA Private Key Password: ")
val caCertAndKey = retrieveCertificateAndKeys(caCertificateName, caPrivateKeyPass, keyStore)
toSign.forEach {
it.certPath = buildCertPath(createClientCertificate(caCertAndKey, it.request, validDays, provider), caParentCertificate)

View File

@ -5,20 +5,19 @@ import com.nhaarman.mockito_kotlin.*
import com.r3.corda.networkmanage.TestBase
import org.junit.Before
import org.junit.Test
import java.io.Console
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class AuthenticatorTest : TestBase() {
private lateinit var provider: CryptoServerProvider
private lateinit var console: Console
private lateinit var inputReader: InputReader
@Before
fun setUp() {
provider = mock()
whenever(provider.cryptoServer).thenReturn(mock())
console = mock()
inputReader = mock()
}
@Test
@ -28,7 +27,7 @@ class AuthenticatorTest : TestBase() {
var executed = false
// when
Authenticator(provider = provider, console = console).connectAndAuthenticate { _, _ -> executed = true }
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> executed = true }
// then
assertFalse(executed)
@ -47,7 +46,7 @@ class AuthenticatorTest : TestBase() {
var executed = false
// when
Authenticator(provider = provider, console = console).connectAndAuthenticate { _, _ -> executed = true }
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> executed = true }
// then
verify(provider).loginPassword(username, password)
@ -64,7 +63,7 @@ class AuthenticatorTest : TestBase() {
var executed = false
// when
Authenticator(provider = provider, console = console, mode = AuthMode.CARD_READER).connectAndAuthenticate { _, _ -> executed = true }
Authenticator(provider = provider, inputReader = inputReader, mode = AuthMode.CARD_READER).connectAndAuthenticate { _, _ -> executed = true }
// then
verify(provider).loginSign(username, ":cs2:cyb:USB0", null)
@ -83,7 +82,7 @@ class AuthenticatorTest : TestBase() {
var executed = false
// when
Authenticator(provider = provider, console = console).connectAndAuthenticate { _, _ -> executed = true }
Authenticator(provider = provider, inputReader = inputReader).connectAndAuthenticate { _, _ -> executed = true }
// then
verify(provider, times(3)).loginPassword(username, password)
@ -99,11 +98,11 @@ class AuthenticatorTest : TestBase() {
}
private fun givenUserConsoleInputOnReadPassword(input: String) {
whenever(console.readPassword(any<String>())).thenReturn(input.toCharArray())
whenever(inputReader.readPassword(any<String>())).thenReturn(input)
}
private fun givenUserConsoleInputOnReadLine(input: String) {
whenever(console.readLine()).thenReturn(input)
whenever(inputReader.readLine()).thenReturn(input)
}
}