Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a Spring Soap interceptor modify the contents of a message?

I'm trying to write an interceptor for a web service that will modify the contents of the Soap message before is sent on to the endpoint. If a client sent a message where the value of some element is 1, I want to be able to alter that element to a 2 so that, when the message arrives at the endpoint, it looks as if the client submitted a 2 instead of a 1. I'm not sure if this is a difficult task which is elluding me, or an easy task which I am making harder than it needs to be.

I have stepped through some of the Spring interceptors; but the validation and logging interceptors don't every alter the message that is in transit. The Wss4jSecurityInterceptor does add some properties to the MessageContext; but I haven't been able to leverage anything that it is doing. I have a shell of an interceptor; but nothing that is doing anything of any value.

public boolean handleRequest(MessageContext messageContext, Object endpoint)
        throws Exception {

    SaajSoapMessage saajSoapMessage = (SaajSoapMessage) messageContext
            .getRequest();
    SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
    SOAPBody soapBody = soapMessage.getSOAPBody();

    return true;
}

I was hoping there was a chance that soembody else had already solved this particular problem. Any insight would be appreciated. Thanks.

like image 982
Dave Avatar asked Jul 08 '10 19:07

Dave


People also ask

How do you intercept SOAP response in spring boot?

Spring WS Intercept Soap MessagesInterceptors must implement the EndpointInterceptor interface. This interface defines 4 methods. handleRequest this method is invoked before the endpoint and returns a boolean value. You can use this method to interrupt or continue the processing of the invocation chain.

How do you intercept a SOAP request?

How do I intercept SOAP message and where I have to do it? You need a SoapHandler to capture the soap request before the execution of the bussiness logic of the endpoint, and other SoapHandler to transform the outbound response.

What is ClientInterceptor?

public interface ClientInterceptor. Workflow interface that allows for customized client-side message interception. Applications can register any number of existing or custom interceptors on a WebServiceTemplate , to add common pre- and postprocessing behavior without needing to modify payload handling code.


2 Answers

Modifying the payload is a little bit tricky. The only way I've found to make this work is to use the getPayloadSource() and getPayloadResult() methods on SoapBody, which expose javax.xml.transform-friendly objects for manipulating the data.

It's annoyingly heavyweight, but you can do something like this:

Transformer identityTransform = TransformerFactory.newInstance().newTransformer();
DOMResult domResult = new DOMResult();
identityTransform.transform(soapBody.getPayloadSource(), domResult);

Node bodyContent = domResult.getNode(); // modify this

identityTransform.transform(new DOMSource(bodyContent), soapBody.getPayloadResult());

I'd love to see a better way of doing this.

like image 177
skaffman Avatar answered Oct 06 '22 00:10

skaffman


I modified the code in this answer to insert an <authentication/> element into all SOAP body requests:

@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
    logger.trace("Enter handleMessage");
    try {
        SaajSoapMessage request = (SaajSoapMessage) messageContext.getRequest();
        addAuthn(request);
    } catch (Exception e) {
        logger.error(e.getMessage(),e);
    }

    return true;
}

protected void addAuthn(SaajSoapMessage request) throws TransformerException {
    Transformer identityTransform = TransformerFactory.newInstance().newTransformer();
    DOMResult domResult = new DOMResult();
    identityTransform.transform(request.getPayloadSource(), domResult);

    Node bodyContent = domResult.getNode();
    Document doc = (Document) bodyContent;
    doc.getFirstChild().appendChild(authNode(doc));

    identityTransform.transform(new DOMSource(bodyContent), request.getPayloadResult());
}

protected Node authNode(Document doc) {
    Element authentication = doc.createElementNS(ns, "authentication");
    Element username = doc.createElementNS(ns, "username");
    username.setTextContent(authn.getUsername());
    Element password = doc.createElementNS(ns, "password");
    password.setTextContent(authn.getPassword());
    authentication.appendChild(username);
    authentication.appendChild(password);
    return authentication;
}

This solution was used because the WebServiceMessageCallback would require me to change the Document, and the SaajSoapMessageFactory is activated before the soap body has been inserted by the configured Jaxb2Marshaller.

like image 24
K St. Clair Avatar answered Oct 06 '22 01:10

K St. Clair