Search code examples
javaweb-servicessoapsoap-clientwebservice-client

Webservice template : How to pass headers in webservice template


I'm using following SOAP request at enterprise level

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      ....
  </soapenv:Header>
   <soapenv:Body>
<UserRQ xmlns="http://www.user.org/USER/INFO" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
  ...

For hitting the API using postman(or so), I'm using WebServiceClient and currently passing whole request(including Headers and Body) into it

ApplicationClient.java :

    public class ApplicationClient extends WebServiceGatewaySupport  {
       
        //Envelope is the whole request
        public ResponseEntity<String> getResults(Envelope envelope) {
            WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
            Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
            marshaller.setContextPath("org.test.wsdl");
            webServiceTemplate.setMarshaller(marshaller);
            webServiceTemplate.setUnmarshaller(marshaller);
          
            ResponseEntity<String> response = (ResponseEntity<String>) webServiceTemplate.marshalSendAndReceive("<URL>", envelope);
            log.info(response.getStatusCode());
            return response;
        }
    }
    

The response is coming as correct(getting 200 responsecode). Is there anyway to pass headers and body separately through webservice client? Or How can we marshall the headers?


Solution

  • There is no way to pass headers and body separately in a webservice call. Instead, there are mechanisms that can alter the constructed messages, which we can leverage for adding an authentication to header and also custom elements to header. For this we need additional spring-ws dependencies.

    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-security</artifactId>
        <version>3.0.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-support</artifactId>
        <version>3.0.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.wss4j</groupId>
        <artifactId>wss4j-parent</artifactId>
        <version>2.3.0</version>
        <type>pom</type>
    </dependency>
    

    Then create a bean that does the auth (Here, I am giving a sample of basic auth)

     @Bean
     public Wss4jSecurityInterceptor wsSecurityInterceptor() {
       Wss4jSecurityInterceptor wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
       wss4jSecurityInterceptor.setSecurementActions(WSHandlerConstants.USERNAME_TOKEN);
       wss4jSecurityInterceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
       wss4jSecurityInterceptor.setSecurementUsername("abc");
       wss4jSecurityInterceptor.setSecurementPassword("xxxxxxxx");
       return wss4jSecurityInterceptor;
    }
    

    Then add a WebServiceMessageCallback instance to override the finished message,

    webServiceTemplate.marshalSendAndReceive(url, request, new CustomWebServiceMessageCallback());
    

    Inside the CustomWebServiceMessageCallback, by using the following way, we can access the header and modify it.

    @Override
    public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException {
       SoapMessage soapMessage = (SoapMessage) webServiceMessage;
       SoapHeader header = soapMessage.getSoapHeader();
       StringSource headerSource = new StringSource("<additional-header-element>HEADER_TEXT</additional-header-element>");
       Transformer transformer =   TransformerFactory.newInstance().newTransformer();
       transformer.transform(headerSource, header.getResult());
    }