Search code examples
spring-bootsoapspring-wssiebel

Fail to consume SOAP WS with Spring-WS in Spring boot but works from SOAPUI


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.


Solution

  • 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...