Full control of client and server certificates with a JBossW
yhrn Jan 16, 2008 9:57 AMHi,
I want to invoke a web service over https with client certificate authentication. The problem is that I need to control exactly which client certificate/key is used and what server certificates to trust per invocation. All examples i can find involves setting global properties and that is not good enough for me.
My application is an EJB3 application running in in JBoss AS 4.2.2 with JBossWS as JAX-WS provider. In JAX-WS 2.1 RI there is a simple way of doing what I want by setting a passing a SSLSocketFactory in the RequestContext of the SEI proxy (see my example below).
package org.acme.ejb3;
import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import javax.ejb.Remote;
import javax.ejb.Stateless;import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceRef;
@Stateless
@Remote(MyTestClient.class)
public class MyTestClientBean implements MyTestClient {
@WebServiceRef(SomeWebService.class)
private SomeWebServicePortType sei;
@Override
public String saySometing(String message, String endpointAddress,
X509Certificate[] clientCertChain, PrivateKey clientKey,
X509Certificate trustedCaCert) throws Exception {
Map<String, Object> reqCtx = ((BindingProvider)sei).getRequestContext();
// Standard JAX-WS method to set the endpoint address.
reqCtx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress);
// My custom key manager
KeyManager[] keyMgrs = { new MyClientKeyManager(clientCertChain, clientKey) };
// My custom trust manager
TrustManager[] trustMgrs = { new MyClientTrustManager(trustedCaCert) };
// Get an SSL context and initialize it with my custom key and trust managers.
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(keyMgrs, trustMgrs, SecureRandom.getInstance("SHA1PRNG"));
// Use the JAX-WS 2.1 RI specific property to ensure that
// my custom managers are used.
reqCtx.put(com.sun.xml.ws.developer.JAXWSProperties.SSL_SOCKET_FACTORY,
sslCtx.getSocketFactory());
// Finally invoke the web service.
return sei.saySometing(message);
}
}
class MyClientKeyManager implements X509KeyManager {
private X509Certificate[] clientCertChain;
private PrivateKey clientKey;
public MyClientKeyManager(X509Certificate[] clientCertChain,
PrivateKey clientKey) {
this.clientCertChain = clientCertChain;
this.clientKey = clientKey;
}
// Here comes my custom KeyManager implementation
}
class MyClientTrustManager implements X509TrustManager {
private X509Certificate trustedCaCertificate;
public MyClientTrustManager(X509Certificate trustedCaCertificate) {
this.trustedCaCertificate = trustedCaCertificate;
}
// Here comes my custom TrustManager implementation
}
Is there any way of doing something similar in JBossWS?