I have a need to replace Axis's (1.4) default SecureSocketFactory with my own implementation. I've done this successfully running from a standalone JRE (1.6), and everything's tested just fine. But when I deploy to Tomcat 5.5 - where this application will eventually reside - as far as I can tell, Axis is still using the JSSESecureSocketFactory. I've tried both:
System.setProperty("org.apache.axis.components.net.SecureSocketFactory", "my.CustomSecureSocketFactory");
and
AxisProperties.setProperty("axis.socketSecureFactory", "my.CustomSecureSocketFactory");
as well as setting the JVM property for Tomcat:
-Dorg.apache.axis.components.net.SecureSocketFactory=my.CustomSecureSocketFactory
The JREs, libraries, key/trust stores, and everything else I can think of are identical. I've even run my standalone test on the server, using Tomcat's JRE and options, and still it works fine.
I'm out of ideas how how to troubleshoot this. Does anyone have any idea of where to look, or an alternate approach to telling Axis to use a specific SecureSocketFactory?
Relevant code snippets:
public class CustomKeyManager extends X509ExtendedKeyManager {
private final X509ExtendedKeyManager base;
public CustomKeyManager(X509ExtendedKeyManager base) {
this.base = base;
}
/* Lots of methods omitted */
static SSLContext SSL_CONTEXT;
static void updateSSL(String keyStoreFile, String keyStorePassword){
System.setProperty("org.apache.axis.components.net.SecureSocketFactory", "com.spanlink.cfg.crypto.HostNameSecureSocketFactory");
AxisProperties.setProperty("axis.socketSecureFactory", "com.spanlink.cfg.crypto.HostNameSecureSocketFactory");
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword.toCharArray());
KeyManager[] oldManagers = kmf.getKeyManagers();
KeyManager[] newManagers = new KeyManager[oldManagers.length];
for (int i = 0; i < oldManagers.length; i++) {
if (oldManagers[i] instanceof X509ExtendedKeyManager) {
newManagers[i] = new CustomKeyManager((X509ExtendedKeyManager) oldManagers[i]);
}else{
newManagers[i] = oldManagers[i];
}
}
SSL_CONTEXT = SSLContext.getInstance("SSL");
SSL_CONTEXT.init(newManagers, null, null);
}
}
public class CustomSecureSocketFactory extends JSSESocketFactory {
public CustomSecureSocketFactory(Hashtable table) {
super(table);
super.sslFactory = CustomKeyManager.SSL_CONTEXT.getSocketFactory();
}
}
Ended up figuring it out. On class load, Axis's SocketFactoryFactory resets the Axis property axis.socketSecureFactory to the default. From a JRE, the class loader loaded SocketFactoryFactory before my code ran; from Tomcat, it wasn't loaded until after my code ran, overwriting my custom settings.
I just added a Class.forName() call before setting axis.socketSecureFactory, and everything worked.