【问题标题】:Loading a custom key store in Google App Engine Java application在 Google App Engine Java 应用程序中加载自定义密钥库
【发布时间】:2012-10-14 02:15:59
【问题描述】:

我想使用URLFetch 服务在 Google App Engine 应用中打开 HTTPS 连接。为了能够验证我的应用正在与之通信的服务器的 SSL 证书,我正在使用我自己的密钥库文件。我想在加载我的应用程序时(即在执行任何 HTTPS 请求之前)在 warmup request 中读取此文件。密钥库文件是我的 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 中使用。

【问题讨论】:

标签: java google-app-engine https keystore urlfetch


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我最近遇到了同样的问题,并且使用与 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());
    

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

    【讨论】:

      【解决方案3】:

      您应该以 trusted tester 的身份注册 Outbound sockets support。在 Desired Features 下,他们使用 SSL。如果支持 JDK SSL API 的更多部分,构建这样的东西会很简单。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 可能是 java 策略问题。您是否编辑了策略文件并允许所有(作为测试)?
        猜你喜欢
        • 2013-02-25
        • 1970-01-01
        • 2017-08-22
        • 2011-01-07
        • 2011-03-31
        • 2018-06-28
        • 2021-05-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多