我需要能够发送证书文件(我认为是 .pem),并使用 scala 和调度进行获取请求。
你是怎样做的?
基于@sbridges 示例中的Java 代码,我使用dispatch 提出了以下Scala 代码。它创建一个自定义 SSL 上下文,其中包含您提供的证书(并且仅包含那些证书;在验证远程主机时,此代码不使用受信任的根证书的默认存储)。
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)
这将用于:
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 或文件名存储在 SslCertificateData 案例类中可能更合适。
我假设您想使用客户端证书执行 https。我认为这需要在 jvm 级别设置,这里有一个很好的解释如何做到这一点。
似乎有一种方法可以直接用 ning 来做,正如这里所解释的,代码复制如下,
// read in PEM file and parse with commons-ssl PKCS8Key
// (ca.juliusdavies:not-yet-commons-ssl:0.3.11)
RandomAccessFile in = null;
byte[] b = new byte[(int) certFile.length()];
in = new RandomAccessFile( certFile, "r" );
in.readFully( b );
char[] password = hints.get( "password" ).toString().toCharArray();
PKCS8Key key = new PKCS8Key( b, password );
// create empty key store
store = KeyStore.getInstance( KeyStore.getDefaultType() );
store.load( null, password );
// cert chain is not important if you override the default KeyManager and/or
// TrustManager implementation, IIRC
store.setKeyEntry( alias, key.getPrivateKey(), password, new DefaultCertificate[0] );
// initialize key and trust managers -> default behavior
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( "SunX509" );
// password for key and store have to be the same IIRC
keyManagerFactory.init( store, password );
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
tmf.init( store );
TrustManager[] trustManagers = tmf.getTrustManagers();
// override key and trust managers with desired behavior - for example
// * 'trust everything the server gives us' -> TrustManager#checkServerTrusted
// * 'always return a preset alias to use for auth' -> X509ExtendedKeyManager#chooseClientAlias, X509ExtendedKeyManager#chooseEngineClientAlias
for ( int i = 0; i < keyManagers.length; i++ )
{
if ( keyManagers[i] instanceof X509ExtendedKeyManager )
{
AHCKeyManager ahcKeyManager = new AHCKeyManager( (X509ExtendedKeyManager) keyManagers[i] );
keyManagers[i] = ahcKeyManager;
}
}
for ( int i = 0; i < trustManagers.length; i++ )
{
if ( tm instanceof X509TrustManager )
{
AHCTrustManager ahcTrustManager = new AHCTrustManager( manager, (X509TrustManager) trustManagers[i] );
trustManagers[i] = ahcTrustManager;
}
}
// construct SSLContext and feed to AHC config
SSLContext context = SSLContext.getInstance( "TLS" );
context.init( keyManagers, trustManagers, null );
ahcCfgBuilder.setSSLContext(context);