使用客户端证书的GlassFish Metro出站Web服务调用失败

时间:2013-03-27 16:56:40

标签: ssl glassfish java-metro-framework client-certificates

我正在尝试使用GlassFish 3.1.2.2与Metro JAX-WS连接到合作伙伴Web服务,我收到HTTP错误403.7 - 禁止访问:需要SSL客户端证书。

我已将我们的合作伙伴提供的私钥导入GlassFish的密钥库:

$ keytool -importkeystore -srckeystore XXX.pfx -srcstoretype pkcs12 -destkeystore keystore.jks
$ keytool -changealias -alias "le-75e085d7-0ceb-4734-ac52-0e64646924c8" -destalias "XXX" -keystore keystore.jks
$ keytool -keypasswd -alias XXX -keystore keystore.jks

然后我将GlassFish的domain.xml中的httpsOutboundKeyAlias属性设置为这个新密钥:

$ grep sas domains/dev/config/domain.xml
        <jvm-options>-Dcom.sun.enterprise.security.httpsOutboundKeyAlias=XXX</jvm-options>

然后,当我进行WS调用时:

[#|2013-03-26T17:58:30.888-0700|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=137;_ThreadName=Thread-2;|#.: ---[HTTP request - https://XXX]---
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://XXX"
User-Agent: Metro/2.2.0-1 (tags/2.2.0u1-7139; 2012-06-02T10:55:19+0000) JAXWS-RI/2.2.6-2 JAXWS/2.2 svn-revision#unknown
<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body>[...]</S:Body></S:Envelope>--------------------
|#]

[#|2013-03-26T17:58:31.847-0700|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=137;_ThreadName=Thread-2;|#.: ---[HTTP response - https://XXX - 403]---
null: HTTP/1.1 403 Forbidden
Content-Length: 1913
Content-Type: text/html
Date: Wed, 27 Mar 2013 00:58:31 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
[...]
<h2>HTTP Error 403.7 - Forbidden: SSL client certificate is required.<br>Internet Information Services (IIS)</h2>

我有这个配置适用于其他Web服务,但由于某种原因没有这个...不确定IIS的行为是否不同?

我似乎能够使用curl呈现使用openssl从合作伙伴的pfx文件转换的pem客户端证书来正常连接:

$ openssl pkcs12 -in XXX.pfx -out XXX.pem -nodes
$ curl -vk -E XXX.pem -H "Accept: text/xml, multipart/related" -H "Content-Type: text/xml; charset=utf-8" -H "SOAPAction: \"http://XXX\"" -d @req.xml  https://XXX

所以不确定为什么GlassFish / Metro没有以预期的方式呈现客户端证书。

关于我可能缺少什么或如何排除故障的任何想法/建议?

我尝试设置-Djavax.net.debug = ssl,但字节在GlassFish日志中显示为单独的日志条目,因此它非常难以理解。 我还尝试从容器外部的独立Java程序运行它,但后来我遇到了classpath issues

谢谢

1 个答案:

答案 0 :(得分:0)

好的,对于后代来说,以防万一将来帮助其他人: 我们将其缩小为GlassFish中的一个错误。

我们使用javax.net.ssl库进行连接工作,因此无论出于何种原因,GlassFish拒绝向该特定服务器提供已配置的httpsOutboundKeyAlias。不清楚具体原因,因为它适用于其他人,但从ssl日志看起来可能是因为IIS服务器为客户端证书提供了很长的接受CA列表?列表可能比预期的要长,或者GlassFish在将客户端证书CA与提供的列表匹配时遇到问题?如果他们愿意解决这个错误,欢迎GlassFish开发人员直接与我联系。

无论如何,在此期间,这是让它运作的代码:

首先,使用提供的客户端证书密钥库创建自定义SSL套接字工厂:

  KeyStore ebKeyStore = KeyStore.getInstance("PKCS12");
  try (InputStream clientCertKeyInput = new FileInputStream(pfxFilePath)) {
      ebKeyStore.load(clientCertKeyInput, passwdChars);
  }
  KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  keyManagerFactory.init(ebKeyStore, passwdChars);

  SSLContext sslCtx = SSLContext.getInstance("TLS");
  sslCtx.init(keyManagerFactory.getKeyManagers(), 
              null, // default javax.net.ssl.trustStore
              new SecureRandom());

  sslSocketFactory = sslCtx.getSocketFactory();

然后让SOAP堆栈通过端口的RequestContext中的属性使用这个sslSocketFactory:

    Map<String, Object> ctxt = ((BindingProvider) port).getRequestContext();
    ctxt.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslSocketFactory);

一线希望是,如果您需要连接多个出站方,GlassFish提供客户端证书的方法无法扩展,因此现在至少此解决方案也可以解决此问题。 :)