Based on the Java code in the @sbridges example, I came up with the following Scala code using dispatch. It creates a custom SSL context containing the certificates you provide (and only those that have the default trusted root certificate store used by this code when checking the remote host).
class SslAuthenticatingHttp(certData: SslCertificateData) extends Http {
override val client = new AsyncHttpClient(
(new AsyncHttpClientConfig.Builder).setSSLContext(buildSslContext(certData)).build
)
private def buildSslContext(certData: SslCertificateData): SSLContext = {
import certData._
val clientCertStore = loadKeyStore(clientCertificateData, clientCertificatePassword)
val rootCertStore = loadKeyStore(rootCertificateData, rootCertificatePassword)
val keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
keyManagerFactory.init(clientCertStore, clientCertificatePassword.toCharArray)
val keyManagers = keyManagerFactory.getKeyManagers()
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(rootCertStore)
val trustManagers = trustManagerFactory.getTrustManagers()
val context = SSLContext.getInstance("TLS")
context.init(keyManagers, trustManagers, null)
context
}
private def loadKeyStore(keyStoreData: Array[Byte], password: String): KeyStore = {
val store = KeyStore.getInstance(KeyStore.getDefaultType)
store.load(new ByteArrayInputStream(keyStoreData), password.toCharArray)
store
}
}
case class SslCertificateData (
clientCertificateData: Array[Byte],
clientCertificatePassword: String,
rootCertificateData: Array[Byte],
rootCertificatePassword: String)
to be used as:
val certificateData = SslCertificateData(/* bytes from .jks file for client cert here */, "secret!",
/* bytes from .jks file for root cert here */, "also secret!")
val http = new SslAuthenticatingHttp(certificateData)
val page = http(req OK as.String)
println(page())
, , . InputStream case SslCertificateData.