21

我想使用URLFetch服务在 Google App Engine 应用程序中打开HTTPS连接。为了能够验证我的应用程序正在与之通信的服务器的 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,但无法自定义密钥库。它是否正确?

如果这是不可能的,那么该方法通常仍然有效吗?或者是否有其他方法仍然允许我验证 SSL 证书?

更新

2009 年,来自 Google 的 App Engine 开发人员 Nick Johnson 在https://groups.google.com/d/topic/google-appengine-python/C9RSDGeIraE/discussion上说:

urlfetch API 不允许您指定自己的客户端证书,因此不幸的是,您目前无法实现您想要实现的目标。

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

4

4 回答 4

4

我最近遇到了同样的问题,并且使用与 appengine-api-stubs 打包的 HttpClient 实现对我有用。

Maven依赖:

<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-api-stubs</artifactId>
  <version>1.9.18</version>
</dependency>

代码:

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

但是出于某种原因或其他应用程序引擎不会阻止它。

于 2015-04-29T17:10:34.583 回答
3

您应该注册为出站套接字支持的受信任测试人员。在所需功能下,他们使用 SSL。如果支持 JDK SSL API 的更多部分,构建这样的东西会很简单。

于 2012-12-07T16:01:16.993 回答
0

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

ServletContext context = getContext();
URL resourceUrl = context.getResource("/WEB-INF/keystore.p12");
于 2012-12-04T19:55:08.147 回答
0

我正在使用 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的是,它不再被列入黑名单,就像提出问题时一样。

于 2017-09-25T20:00:26.197 回答