How to use spring-ws client to call the same webservice using different keystore

ElPysCampeador picture ElPysCampeador · Jan 27, 2015 · Viewed 10.2k times · Source

I have some application that need to run in the same Application server. Each application need to authenticate through the same web service using a certificate specific for that application. Obviously I can put all the certificates inside the same keystore, but how can I specify which one I have to use? For the calls I'm using a Spring WebServiceTemplate and I want to find something that can be easily configure inside the spring xml configuration file.

I'm trying to follow this: How can I have multiple SSL certificates for a Java server

The whole concept is clear but I can't understand how to link it with Spring WebServiceTemplate and how to specify inside the call which certificate I have to use.

Answer

Aaron Wilson picture Aaron Wilson · Apr 7, 2016

There is a much easier approach rather than using a custom HTTP Client factory bean that manually sets up the SSL context and uses interceptors to remove the content length headers (little Hokie if you ask me).

Spring has a HttpsUrlConnectionMessageSender that will automatically setup the SSLContext correctly and allow you to specify different keystore and truststore via the KeyStoreManager and TrustStoreManager. This approach makes it much cleaner to do mutual SSL authentication from the client side.

public class MyWebServiceClient extends WebServiceGatewaySupport implements MyWebServicePortType {

@Configuration
public static class MyClientConfig {
    @Value("${myws.endpoint.url}")
    private String url;

    @Value("${myws.keystore}")
    private Resource keyStore;
    @Value("${myws.keystore.password}")
    private String keyStorePass;
    @Value("${myws.truststore}")
    private Resource trustStore;
    @Value("${myws.truststore.password}")
    private String trustStorePass;

    @Bean 
    public Jaxb2Marshaller myWebServiceClientMarshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.myws.types");
        return marshaller;
    }

    @Bean
    public MyWebServiceClient myWebServiceClient() throws Exception {
        MyWebServiceClient client = new MyWebServiceClient();
        client.setDefaultUri(this.url);
        client.setMarshaller(myWebServiceClientMarshaller());
        client.setUnmarshaller(myWebServiceClientMarshaller());

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(keyStore.getInputStream(), keyStorePass.toCharArray());
        logger.info("Loaded keyStore: "+keyStore.getURI().toString());
        try { keyStore.getInputStream().close(); } catch(IOException e) {}
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(ks, keyStorePass.toCharArray());

        KeyStore ts = KeyStore.getInstance("JKS");
        ts.load(trustStore.getInputStream(), trustStorePass.toCharArray());
        logger.info("Loaded trustStore: "+trustStore.getURI().toString());
        try { trustStore.getInputStream().close(); } catch(IOException e) {}
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(ts);

        HttpsUrlConnectionMessageSender msgSender = new HttpsUrlConnectionMessageSender();
        msgSender.setKeyManagers(keyManagerFactory.getKeyManagers());
        msgSender.setTrustManagers(trustManagerFactory.getTrustManagers());

        client.setMessageSender(msgSender);

        return client;
    }


    // client port method implementations ...
    public MyOperationResponse processMyOperation(MyOperationRequest request) {
        return (MyOperationResponse) getWebServiceTemplate().marshalSendAndReceive(request, new SoapActionCallback("urn:ProcessMyOperation"));
    }

}