2

Background: I have the following problem: I have several WAR files I need to have deployed on same Websphere server. The WAR files use libraries that depend on having a specific version of XMLSec regisered as the XML Signature Provider (with the Java Security class). Currently I bundle this library with each WAR file (since the WAR files also need to work standalone and on Tomcat's without any special shared library configuration etc.). Each WAR files registers the provider with Security.addProvider() in a ServerContextListener. But this causes problems in the multi-WAR setup, because if one WAR file does the registration with Security.addProvider) and another WAR files tries to fetch it using the XMLSignatureFactory class (which is actually a javax.* class contained inside the XMLSec JAR itself, but which ultimately calls back to the global provider list configured with Security.addProvider), then it causes a ClassCastException inside XMLSignatureFactory, because this class does a cast of what it gets from Security into to its own version of the provider classes, which doesn't work. The exact stack trace is as follows:

Caused by: java.lang.ClassCastException: org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory incompatible with javax.xml.crypto.dsig.XMLSignatureFactory at javax.xml.crypto.dsig.XMLSignatureFactory.findInstance(XMLSignatureFactory.java:202) at javax.xml.crypto.dsig.XMLSignatureFactory.getInstance(XMLSignatureFactory.java:292)

By the way this is not a case of conflict with different versions of XMLSec being in play or conflicts with Websphere's own version. There is only one version albeit it is loaded from different WAR's.

Of course the solution is to have the xmlsec library loaded with a common classloader so that there is only one version of the classes loaded that all WAR files see, which would avoid ClassCastExceptions etc.. But here is the rub: I also need to have each application loaded with the "parent last" policy - or rather, I need the JAR files inside each application to take precedence over Websphere's built-in version of the libraries (for instance Axis2 that I also include in the WAR filesetc.). Furter, I would prefer that I can keep the xmlsec library in each WAR files' WEB-INF/lib folder, so that the WAR files can still work stand-alone (i.e. in other environments which might not have the shared library configured etc.).

So basically I want to have a common class loader loading the XMLSec library, say, somewhere from disk. Let's denote that [SHARED XMLSEC]. Then I want each application classpath to ultimately appear like this:

App1: [SHARED XMLSEC][App1 WEB-inf/lib][Websphere libraries][JDK libraries]

App2: [SHARED XMLSEC][App2 WEB-inf/lib][Websphere libraries][JDK libraries]

etc.

In such a configuration it doesn't matter if App1+App2 themselves contain the XMLSec library since the shared one will take precedence so they will use the common one. At the same time, App1+App2 are still free to override other built-in Websphere libraries (Axis2).

Is it possible to realize this configuration and what options do I need to set? Do you see alternative ways to achieve the same objective?

Morty
  • 1,706
  • 1
  • 12
  • 25
  • If your library is not conflicting with WAS libs, you may try to put the jars to `AppServer\lib\ext` directory. Its not a nice solution, but in that case library will be loaded by the server and shared among apps, so maybe it will work for you. – Gas Jun 03 '16 at 07:34
  • It doesn't conflict with the WAS libs but I would prefer to also have the classes in the individual WAR files themselves and that won't work since the JAR in the WAR files will take precedence over the ones contained in lib\ext, ruining the solution (since each application will still see its own copy of XMLSignatureFactory). – Morty Jun 04 '16 at 21:06
  • Either you want server level shared library loaded first, or want classes loaded from the war files with parent last. Some other settings you may try - 1) configure shared library with parent first setting, and use parent last in application or 2) use single classloader for the whole server (as long as you dont have conflicting jars between apps), 3) remove these xml jars from apps and use only in shared library. – Gas Jun 06 '16 at 11:14

1 Answers1

0

Since you have a conflict between classes here, I would suggest going for isolated class loaders for each application. On the server side, setting the class loader policy to 'Multiple' should provide isolation between applications.

Once you have this set, configure class loading at the application level to the 'Parent last' configuration for both the applications.

The following Knowledge Center link has the relevant instructions [Steps 2,3 & 4 under the 'Procedure' section] : http://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/trun_classload.html

[Note: The version of WAS in use is not specified in the question. The Knowledge Center link refers to version 8.5.5.]

Haxiel
  • 683
  • 7
  • 28
  • Hi but it is not a conflict in version of classes - it is just essential that the class seen on the classpath of each app corresponds to the one that is registered with Security.addProvider() (since only one can be registered). If I use an isolated classloader will this also mean that the applications will see different versions of the Security.addProvider() list? – Morty Jun 02 '16 at 13:54
  • @Morty To be honest, I can't help you debug the application at a detailed level, mostly because I don't have a lot of experience with the development side. That said, your classes in each WAR file should be running independent of each other when using isolated classloaders. You'll need to try this out and see if it resolves your particular case. – Haxiel Jun 02 '16 at 17:17
  • Yes they are running independently but the underlying Security class is shared. In my opinion the problem arises because XMLSec contains its own the javax "XMLSignatureFactory" and associated classes etc.(which is actually necessary since those are not part of the Websphere version we are using) but that those same classes query the underlying Security-interface which is shared. This means that when this JAR is bundled with the application in a "parent last" configuration different applications see their own XMLSignatureFactory class. That would be OK if it wasn't... – Morty Jun 04 '16 at 21:01
  • ... (continued) for the fact that the XMLSignatureFactory code in XMLSec didn't query the shared Security-interface hence creating a potential for mixing up of these different instances of XMLSignatueFactory (and other classes). Hope it makes sense. I'm currently leaning on modifying the XMLSignatureFactory.getInstance() method in XMLSec so that it simply doesn't query the Security interface but simply returns an instance of its own contained copy of the class. In this way each application will only access the XMLSec contained within itself and there will be no intermingling between apps. – Morty Jun 04 '16 at 21:03