Configuring Glassfish as a client of web services using mutual SSL

10,095

Solution 1

I faced the same exception that Jacques Pritchard described above:

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

I solved it importing the root certificate in both cacerts.jks and keystore.jks, using the following commands:

/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

It's important to say that the alias rootca is a name I defined myself to label the certificate. You can choose any name also.

Solution 2

Instead of using the global system properties, you should create a separate SSLContext for your client. Whether or not it runs within a Glassfish server doesn't really matter, then.

Here is a question that should be relevant (about client-certificates for WS): Choosing SSL client certificate in Java

Solution 3

I had this exact problem (with Glassfish 3.0.1).

Here are the exact steps we took to resolve this.

    • a. Use java keytool command to view the keystore to see what's in it. This is helpful later on to see if there are any changes. The command goes something like

      keytool -list -keystore MyKeyStore.jks   
      
    • b. Convert the pfx to a pem using openssl. Note that I used the correct password for the input pfx and the same password as my java keystore for the pem file output.

      openssl pkcs12 -in MyPfxFile.pfx -out MyPemFile.pem
      
  1. Convert the pem file to a p12 which can easily be imported into a java keystore. Note that I used the same password from my java keystore as I did on the input and output files.

    openssl pkcs12 -export -in MyPemFile.pem -out MyP12File.p12
    
  2. Now I finally import the p12 into my java keystore. Note that I used java 6, java 5 keytool doesn't have support for the -importkeystore argument.

    keytool -importkeystore -deststorepass MyPassword -destkeystore PathToMyKeystore/keystore.jks -srckeystore MyP12File.p12 -srcstoretype PKCS12 -srcstorepass MyPassword
    
  3. You can list the keystore contents here, something like this keytool -list -keystore keystore.jks just to ensure that your new key was imported correctly.

If you're lucky like I am you'll find that starting up your app server at this point will be of no use. You'll see errors like something about pkix path or something about HTTP 403 Forbidden.

The steps used above worked perfectly for Sun Application Server 9.1_1 but not for Oracle Glassfish 3.0.1. I'm thinking this has something to do with the version of JSSE used in ogs 3 compared to Sun App Server or jdk versions. Adding the jvm option below to your ogs 3 domain.xml file should resolve the issue if simply adding the client cert to the keystore didn't.

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

I did notice that someone said to not use the jvm options statement above but it's part of the fix, don't use it and see if it works, I'll bet it won't. Maybe just changing the handlers is why it works?

Here's where I found the details: http://onjava.com/pub/a/onjava/2001/05/03/java_security.html?page=4

I also stumbled across a final issue (only for ogs 3), if you get fails every now and again I'd suggest finding the InstallCert app (its out there) and give it the following command line parameters: I was getting these PKIX errors every third attempt at calling the web service.

Hopefully this helped someone else out. These kind of issues really make me want to rip my hair out :)

Share:
10,095

Related videos on Youtube

Jacques Pritchard
Author by

Jacques Pritchard

Updated on May 31, 2022

Comments

  • Jacques Pritchard
    Jacques Pritchard almost 2 years

    I'm trying to request data from a web service which requires a client certificate to be presented by a client. The server uses SSL for all communications, and uses a self-signed certificate. I gave Netbeans the service's WSDL file and it generated client code with wsimport.

    I have no issues when my client code is written in a regular Java application; I set the trust store to the cacerts file containing the server's certificate, set the key store to be a file provided by the server admin in JKS format containing 2 keys - a client private key and the server's public key, build the request object, and send the request.

    The problem comes when I move it to an enterprise Java environment. Requirements dictate that the code must be an Enterprise JavaBean inside an Enterprise Archive running on the Glassfish application server. It appears that Glassfish has its own security settings which override the JVM's settings. When the EJB method containing the web service call runs, the SSL negotiation fails: 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. I don't know how to set Glassfish's security settings up like my JVM's settings, can anyone explain Glassfish's security settings? The research I have done has only shown how to set up Glassfish as a web service server, not as a web service client.

    I have a .cer certificate file for the server which I added it to my trust store by using Java's keytool to add it to the default cacerts file. Would it be better to modify cacerts file with InstallCert to include the self-signed certificate, following the steps at http://blog.johnryding.com/post/1548502059/acquire-an-ssl-certificate-for-your-java-programs-in-win?

    I have the trust store file, key store file, along with a .cer certificate file and a .p12 browser certificate, stored in $JAVA_HOME/jre/lib/security and $JAVA_HOME/lib/security.

    I'm using Netbeans 6.9.1 and Glassfish 3.1 Final. The relevant piece of code is below, copied from my EJB. The exception occurs at the last line.

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