Home > Web Services > How to dynamically select a certificate alias when invoking web services

How to dynamically select a certificate alias when invoking web services

Hi, boys and girls! First of all, I would like to say that, yes, this blog´s posts are gonna be all written in English, so they can affect more people around the world. That said, I also would like to say that, although the language has changed, the content is gonna be the same, so I will write and, where it fits, make a critical analysis on the solution.

So, what is the problem?

Web services that use certificates are specially tough to invoke. Along with the complexity that involves almost everything that concern to web services, it also involves the complexity that involves almost everything that concerns to secure communication over the web. So, putting these problems together may give a very strong headache to whoever that wishes to invoke secure web services in Java. Invoking services in a secure way is relatively easy when they do not use more than one certificate in the same VM. But, when it involves more than one certificate, it may be useful to give aliases to the certificates, and to have the ability to select between these certificates in runtime. Also, it may be useful even to change from keystore to keystore in runtime. So, the intent, here, is to provide a simple solution to this problem.

What am I gonna need?

First, you need to assemble a key store and a trust store. I´m not gonna show how to do it here; however, the reader may google it (using a query like this one) to find out how to do it. Second, you must (obviously) have the contract for the service to be invoked. Be warned that, probably, you won´t be able to access it directly, because it will be protected by HTTPS. So, get in touch with the responsibles for the service that you want to invoke. Third, and finally, remember to read carefully the analysis that I am providing at the end of the text (the penalty for not accomplishing this requirement may be an incompatibility between environments).

I´m aware of the requirements, let´s go!

The code consists of the following pieces:

  • A SSL Socket Factory Generator
  • An Alias Selector
  • A Service Invoker

The code for the SSL Socket Factory Generator is like the one below:

import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.logging.Logger;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;

public class SSLSocketFactoryGenerator {
	private String alias = null;
	private String keyStore = null;
	private String trustStore = null;
	public SSLSocketFactoryGenerator (String alias, String keyStore, String trustStore) {
		if (alias == null)
			throw new IllegalArgumentException("The alias may not be null");
		this.alias = alias;
		this.keyStore = keyStore;
		this.trustStore = trustStore;


	public SSLSocketFactory getSSLSocketFactory() throws IOException, GeneralSecurityException {
		KeyManager[] keyManagers = getKeyManagers();
		TrustManager[] trustManagers =getTrustManagers();
		//For each key manager, check if it is a X509KeyManager (because we will override its 		//functionality
		for (int i=0; i<keyManagers.length; i++) {
			if (keyManagers[i] instanceof X509KeyManager) {
				keyManagers[i]=new AliasSelectorKeyManager((X509KeyManager)keyManagers[i], alias);

		SSLContext context=SSLContext.getInstance("SSL");
		context.init(keyManagers, trustManagers, null);

		SSLSocketFactory ssf=context.getSocketFactory();
    		return ssf;
	public String getKeyStorePassword() {
		return "keyStorePassword";
	public String getTrustStorePassword() {
		return "trustStorePassword";

	public String getKeyStore() {
		return keyStore;

	public String getTrustStore() {
		return trustStore;

	private KeyManager[] getKeyManagers()
	throws IOException, GeneralSecurityException
		//Init a key store with the given file.
		String alg=KeyManagerFactory.getDefaultAlgorithm();
		KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg);

		FileInputStream fis=new FileInputStream(getKeyStore());
		KeyStore ks=KeyStore.getInstance("jks");
		ks.load(fis, getKeyStorePassword().toCharArray());

		//Init the key manager factory with the loaded key store
		kmFact.init(ks,  getKeyStorePassword().toCharArray());

		KeyManager[] kms=kmFact.getKeyManagers();
		return kms;

	protected TrustManager[] getTrustManagers() throws IOException, GeneralSecurityException
		String alg=TrustManagerFactory.getDefaultAlgorithm();
		TrustManagerFactory tmFact=TrustManagerFactory.getInstance(alg);
		FileInputStream fis=new FileInputStream(getTrustStore());
		KeyStore ks=KeyStore.getInstance("jks");
		ks.load(fis, getTrustStorePassword().toCharArray());


		TrustManager[] tms=tmFact.getTrustManagers();
		return tms;

So, the SSLSocketFactory will act as a provider for our secure sockets. Note that the class AliasSelectorKeyManager is our alias selector. It´s code is shown below:

import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509KeyManager;

public class AliasSelectorKeyManager implements X509KeyManager{

	private X509KeyManager sourceKeyManager=null;
	private String alias;

	public AliasSelectorKeyManager(X509KeyManager keyManager, String alias)
		this.alias = alias;


	public String chooseClientAlias(String[] keyType, Principal[] issuers,
			Socket socket)
		boolean aliasFound=false;

		//Get all aliases from the key manager. If any matches with the managed alias,
		//then return it.
		//If the alias has not been found, return null (and let the API to handle it, 
		//causing the handshake to fail).

		for (int i=0; i<keyType.length && !aliasFound; i++) {
			String[] validAliases=sourceKeyManager.getClientAliases(keyType[i], issuers);
			if (validAliases!=null) {
				for (int j=0; j<validAliases.length && !aliasFound; j++) {
					if (validAliases[j].equals(alias)) aliasFound=true;

		if (aliasFound) {
			return alias;
		else return null;

	public String chooseServerAlias(String keyType, Principal[] issuers,
			Socket socket)
		return sourceKeyManager.chooseServerAlias(keyType, issuers, socket);

	public X509Certificate[] getCertificateChain(String alias)
		return sourceKeyManager.getCertificateChain(alias);

	public String[] getClientAliases(String keyType, Principal[] issuers)
		return sourceKeyManager.getClientAliases(keyType, issuers);

	public PrivateKey getPrivateKey(String alias)

		return sourceKeyManager.getPrivateKey(alias);

	public String[] getServerAliases(String keyType, Principal[] issuers)
		return sourceKeyManager.getServerAliases(keyType, issuers);


So, at this point we have a custom SSLSocketFactory, that can generate a custom selection for aliases. The final step is to force our web services to use it. To do so, the trick is to generate a Dispatch, which is a JAX-WS interface responsible for calling web services. The Dispatch may accept custom parameters to do the invocations, and we may pass a SSLSocketFactory as parameter, by using a Sun interface called JAXWSProperties. The code is shown below:

public Dispatch<SOAPMessage> getDispatcher(String alias) throws IOException, GeneralSecurityException {
		String namespace = "http://alesaudate.com/Services/";
		String wsdlLocation = "http://alesaudate.com/Services/MyService?wsdl";
		String serviceName = "MyService";
		String portName = "MyServiceSoap";
		String soapActionUri = "http://alesaudate.com/Services/testAction";
		String keyStoreLocation = "C:\\chains\\myKeystore.jks";
		String trustStoreLocation = "C:\\chains\\myTrustStore.jks";

		//Load a dispatcher with the givend data.
		Dispatch<SOAPMessage> dispatcher = getDispatcher(wsdlLocation, namespace, serviceName, portName);
		//Create our custom SSLSocketFactory
		SSLSocketFactory socketFactory = new SSLSocketFactoryGenerator().generateSocketFactory(alias, keyStoreLocation, trustStoreLocation);

		//Be aware: don´t use the com.sun.xml.internal.ws.developer.JAXWSProperties interface instead !!!!
		dispatcher.getRequestContext().put (com.sun.xml.ws.developer.JAXWSProperties.SSL_SOCKET_FACTORY, socketFactory);
		dispatcher.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, soapActionUri);
		return dispatcher;
	public Dispatch<SOAPMessage> getDispatcher (String wsdl, String namespace, String servicename, String portName){
		try {
			//create a representation of the service
			Service service = Service.create(new URL(wsdl), new QName(
					namespace, servicename));
			final Iterator<QName> ports = service.getPorts();
			QName methodToBeCalled = null;

			//Select the port to be called
			if (portName == null)
				methodToBeCalled = ports.next();
			else {
				while (methodToBeCalled == null || !methodToBeCalled.getLocalPart().equals(portName)) {
					methodToBeCalled = ports.next();
			//Create the dispatcher, given the data.
			Dispatch<SOAPMessage> dispatch = service.createDispatch(
					methodToBeCalled, SOAPMessage.class, Service.Mode.MESSAGE);

			return dispatch;
		} catch (Exception e) {
			throw new RuntimeException("Error calling web-service", e);

Here, I create the dispatch to invoke the service. All I have to do, now, is to create a SOAPMessage and use the invoke method, on the Dispatch interface, to invoke the web service in a secure way. If it interests the reader, you may improve the code to use some sort of JAXB piece to create a SOAPMessage from an object.

What should I pay attention to?

The reader must be aware that JAXWSProperties is part of a Sun library and, so, may not work with some application servers and/or Virtual Machine implementations. I tested it using Sun´s JDK 1.6.0_20, with a JBoss AS 5 (which already has the JAR that contains JAXWSProperties). Also, be aware that the solution presented here is not easy to use, and the reader may be interested in creating some sort of Object-to-SOAPMessage translator (maybe using Reflections?). Finally, be sure that speed is not critical, because this code is going to generate a new SSLSocketFactory (including a IO call) to every call, so it may be more interesting to use some kind of cache (of the SSLSocketFactory), in order not to create a new one at every call, but to reuse them.

Nice coding!

  1. Rodrigo Plumari
    08/14/2010 at 1:18 AM

    Hi there! It’s a wise decision to write everything in this blog in english and it is a nice post too but I think I saw something similar somewhere… LOL. Congrats man.

  2. Bill Korb
    02/17/2012 at 6:52 PM


    I was looking to do exactly what you describe, and your information was very valuable, thanks. One difference is that I didn’t need to use the Dispatch stuff you described – it was enough for me to get the JAX-WS request context and set the factory as my customize factory like so:

    ( (BindingProvider) port ).getRequestContext().put(
    “com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory”, factory);


  3. Douglas Brauner
    04/12/2013 at 7:34 PM

    Parabéns pelo blog! Precisava selecionar um certificado do windows para fazer um socket e funcionou com o seu código!

  4. 11/08/2013 at 8:50 PM

    Do you know how can I do the same with a pfx file? I have the password and I cannot use the System.properties because my pfx will change for different clients and I can’t restart my tomcat everytime I change of client.


    • 11/09/2013 at 1:00 PM

      Hi, Fernando!

      Have you tried exchanging the line

      KeyStore keyStore = KeyStore.getInstance("JKS");


      KeyStore keyStore = KeyStore.getInstance("PKCS12"); ?

      A PFX is actually a PKCS12 store. The rest of the code should work fine, but if you still experience issues, post a new comment here, OK?


  5. 11/14/2013 at 4:06 PM

    Im still not able to connect correctly, I have changed the JKS instance to PKCS12 but it doesn’t work with your code, I’ve made a few changes as follows:

    System.setProperty(“sun.security.ssl.allowUnsafeRenegotiation”, “true”);

    SSLContext sslCtx = SSLContext.getInstance(“SSL”);
    char[ ] password = pass.toCharArray();

    String alg=KeyManagerFactory.getDefaultAlgorithm();
    KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg);

    FileInputStream fis=new FileInputStream(rutaPFX);
    KeyStore ks;
    ks = KeyStore.getInstance(“PKCS12”);

    ks.load(fis, password);

    //Init the key manager factory with the loaded key store
    kmFact.init(ks, password);
    KeyManager[] kms=kmFact.getKeyManagers();

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(“SunX509”);
    //sslCtx.init(kms, tmf.getTrustManagers(),null);
    sslCtx.init(kms, null,null);

    QName serviceName = new QName(“www.buzonfiscal.com/TimbradoCFDI/”, “TimbradoCFDI”);

    //QName for Port As defined in wsdl.
    QName portName = new QName(“www.buzonfiscal.com/TimbradoCFDI/”, “TimbradoCFDISOAP”);

    // Create a dynamic Service instance
    Service service = Service.create(serviceName);

    // Add a port to the Service
    service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);

    //Create a dispatch instance
    Dispatch dispatch =
    service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);

    MessageFactory factory = MessageFactory.newInstance();

    SOAPMessage request = factory.createMessage();

    // Object for message parts
    SOAPPart sp = request.getSOAPPart();
    StreamSource prepMsg = new StreamSource(new FileInputStream(rutaXML));

    // Save message

    SOAPMessage reply = null;

    String respuesta = “”;
    try {
    //Invoke Endpoint Operation and read response
    reply = dispatch.invoke(request);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    catch (WebServiceException wse)
    exito = false;
    And it works but when I change of pfx file I receive the SSLHandshakeException.

    I’ll try to make it work with your code today, thanks!!

  6. KevinS
    04/28/2014 at 4:21 PM

    Thanks for the worked example, I had been looking for details of how to make multiple connections with different clients for a test client framework for a tcp/ip ssl socket project. Your first 2 classes have been very helpful.

  7. Akash Aggarwal
    05/12/2017 at 7:58 AM

    Thanks for the detailed example. It was really helpful. Just one question I have, is there anyway to specify default cert for some one who is calling our service from upstream which has multiple certs in keystore. I understand that when we make call to downstream system based on alias, the keystore certificate can be selected but the problem is for the case when some client is calling our service. Please respond if you have any update on it.

    • 05/12/2017 at 10:57 AM

      Hi, Akash, how are you doing? I understand you need certificate authentication, am I correct? If so, there are choices based on each app server out there, and solutions are different for every of them. It could be substantially easier, though, than the scenario I wrote here. Is there any app server you are using?


  8. Akash Aggarwal
    05/15/2017 at 1:02 PM

    Thanks Alexandre….I am doing good….as I mentioned to establish authentication with downstream partners I used the approach you mentioned…i.e, select certificate based on alias name…For our upstream client, I just need to use default certificate which I found can easily be define in tomcat app server using “keyAlias” param in connector definition in server.xml.

    Thanks again for you help.

  1. 11/03/2010 at 1:24 AM

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: