在Google App Engine Java应用程序中加载自定义密钥库

我想使用URLFetch服务在Google App Engine应用中打开HTTPS连接。 为了能够validation我的应用正在与之交谈的服务器的SSL证书,我使用自己的密钥库文件 。 我想在我的应用程序加载时,即在执行任何HTTPS请求之前,在预热请求中读取此文件。 密钥库文件是我的WAR文件的一部分。

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(ClassLoader.getSystemResourceAsStream("myKeystoreFile"), "password".toCharArray()); trustManagerFactory.init(keystore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagers, null); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); 

但是,我不能使用这种方法,因为虽然HttpURLConnection在GAE的JRE白名单上,但HttpsUrlConnection不是。

还有另一种在GAE中使用自定义密钥库的方法吗? 我在GAE文档中没有找到任何相关信息。 看起来Google的URLFetch服务支持HTTPS时,无法自定义密钥库。 它是否正确?

如果这是不可能的,那么这种方法一般是否仍然有效? 或者是否有一种不同的方法仍然允许我validationSSL证书?

UPDATE

2009年,谷歌的App Engine开发者Nick Johnson在https://groups.google.com/d/topic/google-appengine-python/C9RSDGeIraE/discussion上说:

urlfetch API不允许您指定自己的客户端证书,因此很遗憾您目前无法实现所需的目标。

这还是正确的吗? 如果App Engine中的每个HTTP(s)请求都依赖于URLFetch,这意味着GAE中根本无法使用自定义证书。

我最近面临同样的问题,使用与appengine-api-stubs打包在一起的HttpClient实现对我有用。

Maven依赖:

  com.google.appengine appengine-api-stubs 1.9.18  

码:

 // create SSL Context which trusts your self-signed certificate TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(ClassLoader.getSystemResourceAsStream("myKeystoreFile"), "password".toCharArray()); trustManagerFactory.init(keystore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagers, null); // register your trusting SSL context Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) new SocketFactoryWrapper(sslContext.getSocketFactory()), 443)); // make the https call HttpClient httpclient = new HttpClient(); GetMethod httpget = new GetMethod("https://myendpoint.com"); httpclient.executeMethod(httpget); System.out.println(httpget.getStatusLine()); 

这与基本相同

 HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); 

但由于某种原因,应用程序引擎无法阻止它。

您应该注册为Outbound socket支持可信测试人员 。 在Desired Features下,他们登记SSL。 如果支持JDK SSL API的更多部分,那么构建这样的东西会很简单。

我有一个类似的问题…我需要一个keystore.p12来调用外部Web服务,但没有机会从类路径加载它。 我能够使用它的唯一方法是将它放在例如/WEB-INF/keystore.p12并从那里加载它。

 ServletContext context = getContext(); URL resourceUrl = context.getResource("/WEB-INF/keystore.p12"); 

我正在使用Appengine API 1.9.56以及Dima建议的内容

 Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) new SocketFactoryWrapper(sslContext.getSocketFactory()), 443)); 

不再工作了。 因此我也不需要appengine-api-stubs库。

但是, HttpsURLConnection.setDefaultSSLSocketFactory工作正常。

这是我完整的解决方案,解决了我的问题:

  KeyStore keystore = KeyStore.getInstance("JKS"); InputStream in = getClass().getResourceAsStream("/mytruststore.jks"); keystore.load(in, "password".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keystore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagers, null); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); 

幸运的是, HttpsURLConnection不再被列入黑名单,因为它是在提出问题的时候。