Thursday, February 26, 2015

Webservice over SSL

I've been working on an application that simulates a webservice call from a third-party application to our system. Initially a plain WAR running in vanilla Jetty/Tomcat, we eventually migrated it into WebSphere, the same platform we've been working on for the rest of the project. I didn't want to deal with the intricacies of SSL in Tomcat when it'd be much easier to manage in AS7... or so I'd thought.

Everything else was fine and dandy until I hit bits of error with messages in the log:

SRVE0068E: Uncaught exception created in one of the service methods of the servlet 

Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem

Caused by: com.ibm.jsse2.util.g: PKIX path building failed: java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl could not build a valid CertPath.; internal cause is:
    java.security.cert.CertPathValidatorException: The certificate issued by XXXXXXX is not trusted; internal cause is:
    java.security.cert.CertPathValidatorException: Certificate chaining error


I found this solution and poked around in the WebSphere Admin Console. It was a straightforward task of instructing WebSphere to contact the webservice host (even if in my case, it was actually itself) in order to retrieve the SSL information in the form of a "handshake".

This simple step closed the loop. My original assumption was that WebSphere would use the SSL certificate from the same keystore. This was incorrect. The keystore used by the application server as a host is different from the truststore that it uses when it performs the role of a webservice client.

Thursday, January 29, 2015

External log4j configuration in WebSphere AS7

TL;DR - Zip your log4j.xml into an archive, and assign it as a Shared Library reference in an isolated ClassLoader for the deployed ear file.

We had all our configurations stored somewhere in our single EAR file. Somebody didn't like it this way, and we had to externalise the logging properties.

Our interim solution of setting the -Dlog4j.configuration= into the JVM runtime parameters was not well received. My next idea was to make use of the WebSphere Variables, but this old article proved that it will be costly to implement the AdminOperations MBean. This did not help either.

My colleague had attempted to reference the log4j XML file directly in the Shared Libraries reference, but did not succeed in getting WebSphere to adopt the properties. I tried referencing ${LOG_DIR} within the XML file, to a JVM custom property linked to the WebSphere ${LOG_ROOT} also to no avail.

What finally did work, was this:
  1. I extracted the log4j.xml from our EAR,
  2. Zipped this lone XML into an archive, 
  3. Placed it on the server in a path accessible by WebSphere,
  4. Create a Shared Library (WebSphere > Environment > Shared Libraries) mapping the classpath to this archive,
  5. Make sure to select "Use an isolated class loader for this shared library" or you'd have to assign reference for each module of your application rather than just the parent EAR.
  6. Assigning the reference within our EAR (WebSphere > ...Applications... > References > Shared library references),
  7. Restart the server node
Checks via the Class loader viewer (WebSphere > Troubleshooting > Class loader viewer) proved that the lone XML in our newly added archive is loaded for our application, overriding what we'd placed within the EAR file.

An additional tip useful for deployment I found was this. Simply put, the deployment.xml for WebSphere I had created (probably deserves another post after this) just needed another entry added as a child node of the <classloader> module to our EAR file:
<libraries libraryName="Log4j_XML" sharedClassloader="true"/>

Adding this would relieve us of extra steps that can potentially be missed out during deployment, because the shared library would already be configured by default. Keep in mind though, that the libraryName has to be an exact match to what was configured in the WebSphere Shared Libraries.

Tuesday, January 20, 2015

Skipping the java:/comp/env/jdbc context in JBoss AS7

The project started off on JBoss but we're now in mid-swing towards WebSphere. The properties file for the JDBC configuration has the significant difference in the JNDI context to the databases.

The version for JBoss originally was
datasource.jndi=java:/comp/env/jdbc/ourDS

The new one in use for WebSphere will be
datasource.jndi=jdbc/ourDS

Jetty that ran on my development localhost machine, found both versions acceptable without complaining. Thus, I sought to level the playing field such that our project could comfortably support either Application Server without too big a variation.

A number of solutions I'd found catered to the older versions of JBoss 4/5. They are not applicable because of the major change of the configuration XML since AS7. This is how the datasource configuration looks like for AS7.

Initially, I found this, and then this. It led me to conclude that there is a "resourceRef" flag that I could use. I tested adding the <property name="resourceRef" value="true"/> into the XML to no avail. As I began learning more about this topic, I gathered from the hints that a reference anchor was needed. I just had to figure out the correct place to do this. Since our configuration for JBoss required a standalone.xml to be located on the application server, I started digging there. And from my recent experiences, this was the biggest game-changer since earlier versions of JBoss.

An official documentation I found pointed to usage of naming bindings. I tried locating the detailed configuration for this Naming subsystem. Taking a potshot, I added this line:

<subsystem xmlns="urn:jboss:domain:naming:1.1">
    <bindings>
        <lookup name="jdbc/ourDS" lookup="java:/comp/env/jdbc/ourDS"/>
    </bindings>
</subsystem>

And it worked!

Note that there was already a separate configuration of the datasources in the Datasources subsystem configuration within this XML file. And with this, the properties file for the JDBC setup will not require the additional java:/comp context that only JBoss is looking for. Have fun!