WebServiceTemplate with Basic Auth using HttpComponentsMessageSender

authentication, spring, spring-security, spring-ws, web-services

Solution

Use `HttpComponentsMessageSender` with `UsernamePasswordCredentials`. Note that `HttpComponentsMessageSender` must be created as Spring bean or you must call `afterPropertiesSet` manually to be http client correctlly set up. This works for me:

@Configuration
public class WsClientConfiguration {


    @Bean
    public ESignatureProcessorClient eSignatureProcessorClient() {
        ESignatureProcessorClient client = new ESignatureProcessorClient();
        client.setWebServiceTemplate(mwWebServiceTemplate());
        return client;
    }

    @Bean
    public WebServiceTemplate mwWebServiceTemplate() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("cz.csas.services.esignatureprocessor.v02_02");
        WebServiceTemplate template = new WebServiceTemplate(marshaller, marshaller);
        template.setDefaultUri("https://osb-st2.vs.csin.cz:5001/CSMW/WS_MW_ESignatureProcessor_v02_02");
        template.setMessageSender(defaultMwMessageSender());
        return template;
    }

    @Bean
    public HttpComponentsMessageSender defaultMwMessageSender() {
        HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
        messageSender.setCredentials(new UsernamePasswordCredentials("user", "password"));
        return messageSender;
    }

}

Problem

I am trying to test a Spring Web Service which is currently secured with Basic Authentication underneath. For these tests, I have written a Web Service client using Spring's `WebServiceTemplate` class. My Web Service client calls to the Web Service work okay when I create the template's MessageSender as a `org.springframework.ws.transport.http.CommonsHttpMessageSender` object bean with `org.apache.commons.httpclient.UsernamePasswordCredentials` and, although the client works, the code has a warning highlighted saying that the `CommonsHttpMessageSender` class is now deprecated and that I should be using `HttpComponentsMessageSender` instead. I have tried re-configuring the client's `WebServiceTemplate` to work using the newer `HttpComponentsMessageSender` class, but I am unable to have the basic auth part configured correctly with it. For the new `HttpComponentsMessageSender` class, I have created credentials using the `org.apache.http.auth.UsernamePasswordCredentials` class but, when I make a call to the Web Service, the credentials seem to not be available with the request? Is there a working example of a WebServiceTemplate client anywhere that uses these newer classes for authenticating requests, etc? Jars that my working code with old deprecated classes uses: `commons-httpclient-3.1`, `spring-ws-core-2.2.0.RELEASE`. Jars that my NON-working code with newer classes uses: `httpclient-4.3.4`, `httpcore-4.3.2`, `spring-ws-core-2.2.0.RELEASE`. Test Configuration as it stands for NON-working code: ``` package com.company.service.a.ws.test.config; import java.io.IOException; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.transport.http.HttpComponentsMessageSender; @PropertySource("classpath:/${environment}-use-case-data.properties") @ComponentScan(basePackages = "com.company.service.a.ws.test") @Configuration public class TestConfig { @Value("${ws.url}") private String wsUrl; @Value("${ws.username}") private String username; @Value("${ws.password}") private String password; private static final Logger logger = LogManager.getLogger(); @Bean public SaajSoapMessageFactory messageFactory() { return new SaajSoapMessageFactory(); } @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("com.company.service.a.ws.model.data"); return marshaller; } @Bean RequestConfig requestConfig() { RequestConfig requestConfig = RequestConfig.custom() .setAuthenticationEnabled(true) .build(); return requestConfig; } @Bean @DependsOn( value = "propertyConfigurer" ) public UsernamePasswordCredentials credentials() { logger.debug("creating credentials for username: {} passowrd={}", username, password); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( username, password); return credentials; } @Bean public CredentialsProvider credentialsProvider() { CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, credentials()); return credentialsProvider; } private static class ContentLengthHeaderRemover implements HttpRequestInterceptor{ @Override public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { // fighting org.apache.http.protocol.RequestContent's // ProtocolException("Content-Length header already present"); request.removeHeaders(HTTP.CONTENT_LEN); } } @Bean public HttpComponentsMessageSender messageSender() { RequestConfig requestConfig = RequestConfig.custom() .setAuthenticationEnabled(true) .build(); HttpClientBuilder httpClientBuilder = HttpClients.custom(); HttpClient httpClient = httpClientBuilder .addInterceptorFirst(new ContentLengthHeaderRemover()) .setDefaultRequestConfig(requestConfig) .setDefaultCredentialsProvider(credentialsProvider()) .build(); HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(httpClient); return messageSender; } @Bean( name = "propertyConfigurer" ) public static PropertySourcesPlaceholderConfigurer propertyConfigurer() { PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); return configurer; } @Bean public WebServiceTemplate webServiceTemplate() { logger.debug("creating webServiceTemplate to url: {}", wsUrl); WebServiceTemplate webServiceTemplate = new WebServiceTemplate(messageFactory()); webServiceTemplate.setDefaultUri(wsUrl); webServiceTemplate.setMarshaller(marshaller()); webServiceTemplate.setUnmarshaller(marshaller()); webServiceTemplate.setMessageSender(messageSender()); return webServiceTemplate; } } ``` Thanks in advance, PM

Original source

Related problems