【问题标题】:Send certificate file with Scala Dispatch使用 Scala Dispatch 发送证书文件
【发布时间】:2012-09-06 18:56:24
【问题描述】:

我需要能够发送一个证书文件(我认为是 .pem),并使用 scala 和 dispatch 发送一个 get 请求。

你是怎么做到的?

【问题讨论】:

    标签: scala scala-dispatch


    【解决方案1】:

    基于@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 案例类中可能更合适。

    【讨论】:

      【解决方案2】:

      我假设您想使用客户端证书执行 https。我觉得这个需要在jvm级别设置,有很好的解释here怎么做。

      似乎有一种方法可以直接使用 ning 执行此操作,如 here 解释的那样, 代码复制如下,

      // 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);
      

      【讨论】:

      • 太糟糕了!我希望你是错的! :-/ BTW,Dispatch 0.9 基于 Ning Async HttpClient,它基于 NIO。所以答案必须对此有效——不是说您提供的链接无效,只是在这里为其他出现的人发表一些评论。
      猜你喜欢
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 1970-01-01
      • 2012-06-26
      • 2013-04-21
      相关资源
      最近更新 更多