Reputation: 155
I am trying to consume a SOAP webservice using spring-ws. I am able to successfully consume this web service from SOAP UI. However I receive an unauthorized exception:
org.springframework.ws.client.WebServiceTransportException: Unauthorized [401]
at org.springframework.ws.client.core.WebServiceTemplate.handleError(WebServiceTemplate.java:699)
How do I successfully authenticate?
My code is as follows:
WebServiceTemplate configuration:
@Bean
public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marshaller){
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setDefaultUri("http://ultron.illovo.net:9704/AdminService");
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.setUnmarshaller(marshaller);
Credentials credentials = new UsernamePasswordCredentials("biqa", "welcome1");
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
messageSender.setCredentials(credentials);
messageSender.setReadTimeout(5000);
messageSender.setConnectionTimeout(5000);
webServiceTemplate.setMessageSender(messageSender);
return webServiceTemplate;
}
Client:
@Autowired
WebServiceTemplate webServiceTemplate;
public CallProcedureWithResultsResponse callProcedureWithResults(String procedureName){
CallProcedureWithResults request = new CallProcedureWithResults();
request.setProcedureName(procedureName);
log.info("Calling procedure " + procedureName);
CallProcedureWithResultsResponse response = (CallProcedureWithResultsResponse) webServiceTemplate.marshalSendAndReceive("http://ultron.illovo.net:9704/AdminService/AdminService", request);
return response;
}
JUnit Test
@Test
public void testWebService(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ObieeConfiguration.class);
ObieeClient client = context.getBean(ObieeClient.class);
CallProcedureWithResultsResponse response = client.callProcedureWithResults("GetOBISVersion()");
client.printResponse(response);
context.close();
}
Upvotes: 0
Views: 14268
Reputation: 4805
The MessageSender has to be a bean because it's setting the credentials to the underlying HttpClient
in its afterPropertiesSet
method which only gets automatically called by Spring when it's a bean. See https://github.com/spring-projects/spring-ws/blob/02cf3b7e2107d5ba728e9210cb705f31931c702a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsMessageSender.java#L221-L227
So in your case this never happens and you end up with a HttpClient
instance without credentials which results correctly in a 401.
Other ways would be:
HttpClient
with credentials and set it to the HttpComponentsMessageSender
But I would just define the message sender as a bean.
Upvotes: 0
Reputation: 59
use HttpsUrlConnectionMessageSender for secure Https connections. This is part of spring-ws-support dependency. Also, you can bypass various certificate issue by using HttpsUrlConnectonMessageSender, like certificate common name mis-matching.
Dont use BASE64Encoder, it is the class of sun.misc jar which is not much secure. use Base64 of java util present in java 1.8 and Base64 of apache for java version less then java 1.8
public class WebServiceMessageSenderWithAuth extends HttpsUrlConnectionMessageSender {
String user;
String password;
public WebServiceMessageSenderWithAuth(String user, String password) {
this.user = user;
this.password = password;
}
@Override
protected void prepareConnection(HttpURLConnection connection) throws IOException {
String userpassword = user+":"+password;
String encodedAuthorization = Base64.encode( userpassword.getBytes() );
connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
//set various properties by using reference of connection according to your requirement
}
}
Upvotes: 0
Reputation: 345
I run into the same issue and managed to resolved by defining a MessageSender with Credentials and then setting it to the client. I didn't have to create a custom MessageSender.
@Bean
public WebServiceMessageSender messageSender(Credentials credentials) throws Exception{
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
messageSender.setCredentials(credentials);
return messageSender;
}
@Bean
public Credentials credentials(){
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(USERNAME, PASSWORD);
return credentials;
}
Upvotes: 2
Reputation: 155
I managed to resolve this issue by doing the following:
Create a subclass of HttpUrlConnectionMessageSender as follows:
public class WebServiceMessageSenderWithAuth extends HttpUrlConnectionMessageSender {
String user;
String password;
public WebServiceMessageSenderWithAuth(String user, String password) {
this.user = user;
this.password = password;
}
@Override
protected void prepareConnection(HttpURLConnection connection) throws IOException {
BASE64Encoder enc = new BASE64Encoder();
String userpassword = user+":"+password;
String encodedAuthorization = enc.encode( userpassword.getBytes() );
connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
super.prepareConnection(connection);
}
}
My client is defines as follows:
public class ObieeClient extends WebServiceGatewaySupport {
private static final Logger log = LoggerFactory.getLogger(ObieeClient.class);
public CallProcedureWithResultsResponse callProcedureWithResults(String procedureName, String webServiceURL){
CallProcedureWithResults request = new CallProcedureWithResults();
request.setProcedureName(procedureName);
log.info("Calling procedure " + procedureName);
CallProcedureWithResultsResponse response = (CallProcedureWithResultsResponse) ((JAXBElement) getWebServiceTemplate().marshalSendAndReceive(webServiceURL, request)).getValue();
return response;
}
}
And finally the client is configured to use the credentials by setting the message sender:
Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("za.co.adaptit.smartdeployment.webservices.wsdl");
//set up web service client
ObieeClient client = new ObieeClient();
client.setDefaultUri(host);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
client.setMessageSender(new WebServiceMessageSenderWithAuth("user", "password"));
response = client.callProcedureWithResults("NQSModifyMetadata('" + obieeObjectsXML +"')", server.getHost());
Hope this helps.
Upvotes: 4