This was the task. We are hooking up Jive SBS to an SSO server for authentication and I am writing a plugin to handle this task. In the plugin, I come to the part of the code where I need to communicate with an external webservice. In order for java to communicate with this webservice, the security certificate must be part of the keystore of the jre and the keystore must be recognized by the application. By default, Jive SBS does not have an assigned keystore.

Here is how I resolved it.

1. Download the security certificate of the webservice using a browser. You should be able to save the certificate as a .cer or .crt file name. Then transfer the certificate to your Linux server that is running Jive SBS. Save this file in a unique place we will call “somedirectory”. If the step of downloading a certificate is new to you, from IE, go to File -> Properties -> Certificates -> Details -> Copy to File.

2. Run these commands from the Linux console, modified to your environment.

/usr/local/jive/java/bin/keytool -import -alias somename -file /usr/local/jive/etc/httpd/ssl/somename.cer -keystore /usr/local/jive/java/jre/lib/security/cacerts

When it asks for the password, use the default of – changeit

3. Test getting a connection using the SSLPoke class – described below.

4. Add the truststore into the setenv file located at /usr/local/jive/applications/sbs/bin/setenv.
export JAVA_OPTS=”\
-XX:+UseParNewGC \
-XX:+UseConcMarkSweepGC \
-XX:CMSInitiatingOccupancyFraction=75 \
-XX:+CMSParallelRemarkEnabled \
-XX:+CMSScavengeBeforeRemark \
-XX:CMSMaxAbortablePrecleanTime=1000 \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-XX:+PrintClassHistogram \
-Djava.awt.headless=true \
-Djava.net.preferIPv4Stack=true \
-Djavax.net.ssl.trustStore=/somedirectory/keystore.jks \
-Xloggc:${JIVE_LOGS}/${JIVE_NAME}-gc.log”

Another command I found useful in troubleshooting this issue was as follows:
ps -ef | grep java

Using SSLPoke
I actually picked this up from an attlasian web page so I am not the original author. But here is the source code.


import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;

/** Establish a SSL connection to a host and port, writes a byte and
 * prints the response. See
 * http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services
 */
public class SSLPoke {
    public static void main(String[] args) {
    if (args.length != 2) {
      System.out.println("Usage: "+SSLPoke.class.getName()+" <host> <port>");
      System.exit(1);
    }
    try {
      SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
      SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));

      InputStream in = sslsocket.getInputStream();
      OutputStream out = sslsocket.getOutputStream();

      // Write a test byte to get a reaction :)
      out.write(1);

      while (in.available() > 0) {
        System.out.print(in.read());
      }
      System.out.println("Successfully connected");

    } catch (Exception exception) {
      exception.printStackTrace();
    }
  }
}

Compile this simple class and test your connection with this expected behavior:

works
java -Djavax.net.ssl.trustStore=/somedirectory/keystore.jks SSLPoke webserviceurl.com 443
Successfully Connected

Does not work
java SSLPoke webserviceurl.com 443

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path bui lding failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find vali d certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1623)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:198)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:192)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.j ava:1074)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java :128)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:465)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.j ava:1120)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:623)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:73)
at SSLPoke.main(SSLPoke.java:23)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security .provider.certpath.SunCertPathBuilderException: unable to find valid certification path to re quested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:294)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:200)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.ja va:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustMana gerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustMana gerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.j ava:1053)
… 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid c ertification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.j ava:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:289)
… 15 more