使用相互SSL将Glassfish配置为Web服务的客户端

时间:2011-06-07 05:48:06

标签: authentication ssl java-ee glassfish ejb

我正在尝试从Web服务请求数据,该服务需要客户端提供客户端证书。服务器使用SSL进行所有通信,并使用自签名证书。我向Netbeans提供了服务的WSDL文件,并使用wsimport生成了客户端代码。

当我的客户端代码是在常规Java应用程序中编写时,我没有问题;我将信任库设置为包含服务器证书的cacerts文件,将密钥库设置为服务器管理员以JKS格式提供的文件,包含2个密钥 - 客户端私钥和服务器的公钥,构建请求对象,并发送请求。

当我将其移至企业Java环境时,问题就出现了。要求规定代码必须是在Glassfish应用程序服务器上运行的Enterprise Archive中的Enterprise JavaBean。看来Glassfish有自己的安全设置,可以覆盖JVM的设置。当运行包含Web服务调用的EJB方法时,SSL协商将失败:javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target。我不知道如何像我的JVM设置一样设置Glassfish的安全设置,任何人都可以解释Glassfish的安全设置吗?我所做的研究仅展示了如何将Glassfish设置为Web服务服务器,而不是将其设置为Web服务客户端

我有一个服务器的.cer证书文件,我将它添加到我的信任库,使用Java的keytool将其添加到默认的cacerts文件中。 使用cacerts修改InstallCert文件以包含自签名证书,按照http://blog.johnryding.com/post/1548502059/acquire-an-ssl-certificate-for-your-java-programs-in-win的步骤进行操作会更好吗?

我有信任存储文件,密钥存储文件,以及.cer证书文件和.p12浏览器证书,存储在$ JAVA_HOME / jre / lib / security和$ JAVA_HOME / lib / security中。

我正在使用Netbeans 6.9.1和Glassfish 3.1 Final。下面的相关代码段是从我的EJB复制而来的。例外发生在最后一行。

System.setProperty("javax.net.ssl.trustStore", "C:\\jssecacerts"); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); System.setProperty("javax.net.ssl.keyStore", "C:\\userCertificate.jks"); System.setProperty("javax.net.ssl.keyStorePassword", "password");
RequestObject request = new RequestObject;
request.setQuery("some data");
request.setUsername("user");
request.setPassword("pass");
Service service = new Service();
Endpoint port = service.getWebServicePort();
Result result = port.specificWebServiceMethod(request);

4 个答案:

答案 0 :(得分:5)

我遇到了雅克普里查德描述的同样的例外:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

解决了它使用以下命令在cacerts.jks和keystore.jks中导入根证书:

/usr/java/jdk1.6.0_25/bin/keytool -import -trustcacerts -file root_ca.cer -alias rootca -keystore cacerts.jks

/usr/java/jdk1.6.0_25/bin/keytool -import -trustcacerts -file root_ca.cer -alias rootca -keystore keystore.jks

重要的是,别名rootca是我自己定义的名称以标记证书。您也可以选择任何名称。

答案 1 :(得分:1)

您应该为您的客户创建单独的SSLContext,而不是使用全局系统属性。然后,它是否在Glassfish服务器中运行并不重要。

这是一个应该相关的问题(关于WS的客户端证书):Choosing SSL client certificate in Java

答案 2 :(得分:1)

我遇到了这个问题(使用Glassfish 3.0.1)。

以下是我们解决此问题的具体步骤。

    • 一个。使用java keytool命令查看密钥库以查看其中的内容。这有助于稍后查看是否有任何更改。该命令类似于

      keytool -list -keystore MyKeyStore.jks   
      
    • 湾使用openssl将pfx转换为pem。请注意,我使用输入pfx的正确密码和与我的java密钥库相同的密码作为pem文件输出。

      openssl pkcs12 -in MyPfxFile.pfx -out MyPemFile.pem
      
  1. 将pem文件转换为p12,可以轻松导入到java密钥库中。请注意,我在输入和输出文件中使用了与我的java密钥库相同的密码。

    openssl pkcs12 -export -in MyPemFile.pem -out MyP12File.p12
    
  2. 现在我终于将p12导入到我的java密钥库中了。注意我使用java 6,java 5 keytool不支持-importkeystore参数。

    keytool -importkeystore -deststorepass MyPassword -destkeystore PathToMyKeystore/keystore.jks -srckeystore MyP12File.p12 -srcstoretype PKCS12 -srcstorepass MyPassword
    
  3. 您可以在此处列出密钥库内容,例如此keytool -list -keystore keystore.jks,以确保您的新密钥已正确导入。

  4. 如果你像我一样幸运,你会发现在这一点上启动你的应用服务器是没有用的。您将看到有关pkix路径或HTTP 403 Forbidden的错误。

    上面使用的步骤适用于Sun Application Server 9.1_1,但不适用于Oracle Glassfish 3.0.1。我认为这与ogs 3中使用的JSSE版本相比,与Sun App Server或jdk版本相比。如果只是将客户端证书添加到密钥库,则将下面的jvm选项添加到ogs 3 domain.xml文件应该可以解决问题。

    <jvm-options>-Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol</jvm-options>
    

    我注意到有人说不使用上面的jvm选项声明,但它是修复的一部分,不要使用它,看它是否有效,我敢打赌它不会。也许只是改变处理程序是它的工作原理?

    我在这里找到了详细信息:http://onjava.com/pub/a/onjava/2001/05/03/java_security.html?page=4

    我也偶然发现了最后一期(仅适用于ogs 3),如果你一次又一次失败我会建议找到InstallCert应用程序(它在那里)并给它以下命令行参数: 我每三次尝试调用Web服务就会收到这些PKIX错误。

    希望这有助于其他人。这些问题真的让我想撕掉我的头发:)

答案 3 :(得分:0)

我终于明白了。

从我的keytool中删除了所有证书。

命令示例:keytool -list -v -keystore keystore.jks -alias mydomain

我将证书响应从服务器转换为bas64 DER并将它们复制到一个.PEM文件中,然后将.PEM上传到我的keytool中:

命令示例:keytool -importcert -keystore keystore.jks -alias mydomain -file my.pem

然后我加载了密钥库:

KeyStore myStore = KeyStore.getInstance("JKS");
InputStream keyInputx = new FileInputStream("C:\\myStore.jks");
myStore.load(keyInputx, "xxx".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyInputx.close();
/*Enumeration enumeration = myStore.aliases();
 while (enumeration.hasMoreElements()) {
     String alias = (String) enumeration.nextElement();
     System.out.println("alias name: " + alias);
     Certificate certificate = myStore.getCertificate(alias);
     System.out.println(certificate.toString());
 }*/
keyManagerFactory.init(myStore, "xxx".toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
SSLSocketFactory sockFact = context.getSocketFactory();

很多参考文献都很乐意使用。