I'm using Spring Boot to consume a SOAP WS which I generate from a WSDL. I added the spring-ws-security so I can pass the user/password as security header as shown in the configuration:
@Configuration
public class ClientConfig {
public static final String SIEBEL_ENDPOINT = "http://...";
@Bean
public CustomerClient customerClient() {
CustomerClient client = new CustomerClient();
client.setDefaultUri(SIEBEL_ENDPOINT);
client.setWebServiceTemplate(webServiceTemplate(marshaller()));
return client;
}
@Bean
public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marshaller) {
WebServiceTemplate template = new WebServiceTemplate(marshaller, marshaller);
template.setDefaultUri(SIEBEL_ENDPOINT);
ClientInterceptor[] interceptors = new ClientInterceptor[] {new LogHttpHeaderClientInterceptor(), wsSecurityInterceptor()};
template.setInterceptors(interceptors);
return template;
}
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.test.dms.gen");
return marshaller;
}
@Bean
public Wss4jSecurityInterceptor wsSecurityInterceptor() {
Wss4jSecurityInterceptor wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
wss4jSecurityInterceptor.setSecurementActions(WSHandlerConstants.USERNAME_TOKEN);
wss4jSecurityInterceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
wss4jSecurityInterceptor.setSecurementUsername("rf_USER");
wss4jSecurityInterceptor.setSecurementPassword("rf_USER");
return wss4jSecurityInterceptor;
}
}
And the service call:
public class CustomerClient extends WebServiceGatewaySupport {
public CustomerInfoOutput getCustomerInfo(String vin) {
ObjectFactory request = new ObjectFactory();
final CustomerInfoInput custInfoInput = request.createCustomerInfoInput();
custInfoInput.setVINNumber(vin);
return (CustomerInfoOutput) getWebServiceTemplate().marshalSendAndReceive(ClientConfig.SIEBEL_ENDPOINT, custInfoInput);
}
}
everything is well generated, and this logged output:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken wsu:Id="UsernameToken-e8f183db-44db-4c0b-90d9-ca57e89225fd">
<wsse:Username>rf_USER</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">rf_USER</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns3:CustomerInfo_Input xmlns:ns2="http://siebel.com/testdashboard"
xmlns:ns3="http://test.com/rf/customerinfo" xmlns:ns4="http://test.com/rf"
xmlns:ns5="http://www.siebel.com/xml/IBM%20test%20Dashboard">
<ns3:VINNumber>123456789</ns3:VINNumber>
</ns3:CustomerInfo_Input>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
When I send this request using SOAP UI, it works perfectly. But when it's sent using the generated objects from the WSDL, I have this error:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>There is no active Web Service with operation named
'http://test.com/rf/customerinfo:CustomerInfo_Input'.(SBL-EAI-04313)
</faultstring>
<detail>
<siebelf:siebdetail xmlns:siebelf="http://www.siebel.com/ws/fault">
<siebelf:logfilename>EAIObjMgr_enu_0023_24117286.log</siebelf:logfilename>
<siebelf:errorstack>
<siebelf:error>
<siebelf:errorcode>SBL-EAI-04313</siebelf:errorcode>
<siebelf:errorsymbol>IDS_EAI_WS_OP_NOT_FOUND</siebelf:errorsymbol>
<siebelf:errormsg>There is no active Web Service with operation named
'http://test.com/rf/customerinfo:CustomerInfo_Input'.(SBL-EAI-04313)
</siebelf:errormsg>
</siebelf:error>
</siebelf:errorstack>
</siebelf:siebdetail>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Any ideas please?
PS: please don't focus on URIs because I changed them, but the generated request works fine in SOAPUI.
With the hint of @RanjithR I processed as follow:
I traced the SOAP Call using Wireshark, and I discovered that Spring WS doesn't include the header SOAPAction
. The following SOF question talks about this, and how to configure it (it sends you to the spring documentation which explains well the thing). Spring-WS client not setting SOAPAction header
The second thing is that, even if I added the header, it continues to tell me that the endpoint is not sent.
In my WSDL, the SOAPAction is defined as follows:
<soap:operation soapAction="document/http://test.com/rf/customerinfo:CustomerInfo"></soap:operation>
And my Spring ws call was like that:
return getWebServiceTemplate().marshalSendAndReceive(ClientConfig.SIEBEL_ENDPOINT,
customerInfoInput,
webServiceMessage -> ((SoapMessage)webServiceMessage).setSoapAction("document/http://ripl.com/rforce/customerinfo:CustomerInfo"));
In Wireshark, I had:
SOAPAction: "http://ripl.com/rforce/customerinfo:CustomerInfo"
But when I trace the same call from SOAP UI I have: SOAPAction: "document/http://ripl.com/rforce/customerinfo:CustomerInfo"
So I tried to send a string literal as a SOAPAction:
"\"document/http://ripl.com/rforce/customerinfo:CustomerInfo\"";
Note the \"\"
around the action and it works :)
Maybe it can help someone that have to integrate with Jurasik Park systems...