Keywords: Java | SSL | JAX-WS | Certificate
Abstract: This article explores how to programmatically set the SSLContext for a JAX-WS client in Java distributed applications, preventing conflicts with global SSL configurations. It covers custom KeyManager and SSLSocketFactory implementation, secure connections to third-party servers, and handling WSDL bootstrapping issues, with detailed code examples and analysis.
Problem Background and Challenges
In distributed Java applications, servers often need to act as JAX-WS clients to securely connect to third-party services via HTTPS/SSL. However, using system properties like -Djavax.net.ssl.keyStore to set a global SSLContext can cause conflicts with other components (e.g., XMPP), as they share the same underlying SSL context. Users report that despite namespace configurations (e.g., my.xmpp.keystore), global settings affect all SSL communications, indicating a need to isolate JAX-WS client SSL configurations.
Core Solution: Custom SSL Configuration
To address this, a programmatic approach can be used to create an independent SSLContext. Key steps involve customizing KeyManager and SSLSocketFactory. First, load the client certificate via KeyStore, then initialize KeyManagerFactory and SSLContext. Example code:
// Create SSLContext
SSLContext sc = SSLContext.getInstance("SSLv3");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(certPath), certPasswd.toCharArray());
kmf.init(ks, certPasswd.toCharArray());
sc.init(kmf.getKeyManagers(), null, null);Next, apply the custom SSLSocketFactory to the JAX-WS client by setting a proprietary property in the WebService context, suitable for Sun/Oracle JAX-WS implementations:
service = getWebServicePort(getWSDLLocation());
BindingProvider bindingProvider = (BindingProvider) service;
bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory());This ensures that JAX-WS interactions use isolated SSL configurations without interfering with other system components. Note that the property string "com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory" is implementation-specific and may require adjustments based on the JAX-WS runtime.
Handling WSDL Bootstrapping Issues
When WSDL is loaded from a secure server, initial HTTPS requests might not use the same certificates, leading to bootstrapping failures. Solutions include making the WSDL locally available (e.g., via file:// protocol) or dynamically changing the endpoint address. Example code:
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, webServiceLocation);This avoids relying on global SSL configurations during bootstrapping, ensuring the entire communication chain uses custom certificates.
Alternative Methods and Supplementary Notes
Beyond the above approach, other options include using standard properties like JAXWSProperties.SSL_SOCKET_FACTORY, which may be more compatible in some JAX-WS implementations. For example:
bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, getCustomSocketFactory());Additionally, simpler code variants (as shown in Answer 2) follow the same principle but reduce custom class creation, suitable for straightforward scenarios. However, the core idea remains programmatically building an SSLContext to avoid global dependencies.
Conclusion
By programmatically setting the SSLContext, JAX-WS clients can achieve secure HTTPS communication while isolating configuration conflicts. It is recommended to choose appropriate properties based on the specific JAX-WS runtime and address WSDL bootstrapping to refine the solution. This method enhances flexibility and security in distributed applications.