如何使Play Framework WS使用我的SSLContext

时间:2015-02-11 23:09:02

标签: web-services ssl

我正在使用Play 2.3.7和Scala 2.11.4,Java 7.我想使用Play WS连接到HTTPS端点,这需要客户端提供其证书。为此,我创建了自己的SSLContext:

  val sslContext = {
    val keyStore = KeyStore.getInstance("pkcs12")
    keyStore.load(new FileInputStream(clientKey), clientKeyPass.to[Array])
    val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
    kmf.init(keyStore, clientKeyPass.to[Array])

    val trustStore = KeyStore.getInstance("jks")
    trustStore.load(new FileInputStream(trustStoreFile), trustStorePass.to[Array])
    val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    tmf.init(trustStore)

    val ctx = SSLContext.getInstance("TLSv1.2")
    ctx.init(kmf.getKeyManagers, tmf.getTrustManagers, new SecureRandom())
    ctx
  }

我知道,SSLContext是有效的,因为我可以成功地将它与URLConnection一起使用:

  def urlConnection = Action {
    val conn = new URL(url).openConnection()
    conn.asInstanceOf[HttpsURLConnection].setSSLSocketFactory(sslContext.getSocketFactory)
    conn.connect()
    Ok(scala.io.Source.fromInputStream(conn.getInputStream).getLines().mkString("\n"))
  }

但是当我尝试以下两种方法之一时,我会得到java.nio.channels.ClosedChannelException。

  def ning = Action.async {
    val builder = new AsyncHttpClientConfig.Builder()
    builder.setSSLContext(sslContext)
    val client = new NingWSClient(builder.build())
    client.url(url).get() map { _ => Ok("ok") }
  }

  def asyncHttpClient = Action {
    val builder = new AsyncHttpClientConfig.Builder()
    builder.setSSLContext(sslContext)
    val httpClient = new AsyncHttpClient(builder.build())
    httpClient.prepareGet(url).execute().get(10, TimeUnit.SECONDS)
    Ok("ok")
  }

当我继续使用Will Sargent的建议并使用带有解析配置的NingAsyncHttpClientConfigBuilder时,我也得到了相同的异常(注意,该配置引用了完全相同的值,手工制作的sslContext确实如此)。

  def ningFromConfig = Action.async {
    val config = play.api.Configuration(ConfigFactory.parseString(
      s"""
          |ws.ssl {
          |  keyManager = {
          |    stores = [
          |      { type: "PKCS12", path: "$clientKey", password: "$clientKeyPass" }
          |    ]
          |  }
          |  trustManager = {
          |    stores = [
          |      { type: "JKS", path: "$trustStoreFile", password: "$trustStorePass" },
          |    ]
          |  }
          |}
          |# Without this one I get InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
          |ws.ssl.disabledKeyAlgorithms="RSA keySize < 1024"
       """.stripMargin))
    val parser = new DefaultWSConfigParser(config, play.api.Play.application.classloader)
    val builder = new NingAsyncHttpClientConfigBuilder(parser.parse())
    val client = new NingWSClient(builder.build())
    client.url(url).get() map { _ => Ok("ok") }
  }

如何使用Play WS?