Search code examples
spring-ws

"Pre-Emptive" Basic Auth for Spring-WS Client


I'm trying to use build a simple web service client using Spring-WS and am hitting a wall. The SOAP service I'm attempting to call uses HTTP Basic Authentication for security.

Using the Spring-WS tutorial example, I have configured myWebServiceTemplate to use the HttpComponentsMessageSender with my credentials provided:

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
    <constructor-arg ref="messageFactory"/>
    <property name="messageSender">
        <bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
            <property name="credentials">
                <bean class="org.apache.http.auth.UsernamePasswordCredentials">
                    <constructor-arg value="john:secret"/>
                </bean>
            </property>
        </bean>
    </property>
    <property name="defaultUri" value="http://example.com/WebService"/>
</bean>

When I try to execute the client, I get the following error:

org.springframework.ws.client.WebServiceTransportException: Authorization Required [401]

My previous (WebServiceTemplate with Basic Auth using HttpComponentsMessageSender and HttpClientBuilder basic auth) searches indicate the problem is that Spring-WS is attempting to first connect to the endpoint without the credentials, which is causing the endpoint to reject the initial connection.

It seems that this is a pretty common issue with web services that still use HTTP Basic Authentication.

My question is how can I get Spring to present the credentials on the initial connection attempt?

I would like to avoid re-implementing the entire framework for something seemingly trivial.

(For reference, the endpoint is an internal web service that I don't have control over, and there's no other option to use HTTP Basic Authentication, regardless of how defunct or insecure one might think it is).

Thanks!


Solution

  • I assume you have created a client that extends WebServiceGatewaySupport. In this case when defining the client in your Configuration class set the MessageSender there. MessageSender must be configured with Credentials.

    @Bean
    public ValidateCustomerClient customerClient(Jaxb2Marshaller marshaller, WebServiceMessageSender messageSender){
        ValidateCustomerClient client = new ValidateCustomerClient();
        client.setDefaultUri(DEFAULT_URI);
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        client.setMessageSender(messageSender);//set MessageSender here instead on WebServiceTemplate
        return client;
    }
    

    I find that setting the MessageSender with Credentials on the WebServiceTemplate does not keep Credentials when client is invoked thereby causing 401.

    While this solution have worked on our case, I would welcome any feedback.