5 Replies Latest reply on Oct 24, 2008 5:10 PM by Mattias Öhrn

    Full control of client and server certificates with a JBossW

    Mattias Öhrn Newbie

      Hi,
      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?