Uploaded image for project: 'Spring Web Services'
  1. Spring Web Services
  2. SWS-464

The use of WS Addressing results in malformed SOAP messages

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Critical
    • Resolution: Fixed
    • Affects Version/s: 1.5.5
    • Fix Version/s: 1.5.6
    • Component/s: Core
    • Labels:
      None

      Description

      When WS Addressing is being used the Axiom message factory appears to produce malformed SOAP messages (details to follow)

        Activity

        Hide
        olegk Oleg Kalnichevski added a comment -

        Axiom message factory appears to produce malformed messages. For instance, the problem can be triggered by the use of Web Addressing (see example below). The wsa name space declaration is missing in wsa:Action and wsa:MessageID header elements. Moreover, ideally the wsa namespace should be declared in the soapenv:Header. Please note at the same time the fault body seems sane.

        <?xml version="1.0" encoding="UTF-8"?>
        <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
        <soapenv:Header>
        <wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" soapenv:mustUnderstand="true">xxxxxxxxxx</wsa:To>
        <wsa:Action>xxxxxxxxxxxxxxxxxxxxxxxxx</wsa:Action>
        <wsa:MessageID>urn:uuid:cf9f8e79-9226-4237-b014-bf431778ddab</wsa:MessageID>
        </soapenv:Header>
        <soapenv:Body>
        <soapenv:Fault xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <soapenv:Code>
        <soapenv:Value>soapenv:Sender</soapenv:Value>
        <soapenv:Subcode>
        <soapenv:Value>wsa:MessageInformationHeaderRequired</soapenv:Value>
        </soapenv:Subcode>
        </soapenv:Code>
        <soapenv:Reason>
        <soapenv:Text xmlns:lang="en">A required message information header, To, MessageID, or Action, is not present.</soapenv:Text>
        </soapenv:Reason>
        </soapenv:Fault>
        </soapenv:Body>
        </soapenv:Envelope>

        Show
        olegk Oleg Kalnichevski added a comment - Axiom message factory appears to produce malformed messages. For instance, the problem can be triggered by the use of Web Addressing (see example below). The wsa name space declaration is missing in wsa:Action and wsa:MessageID header elements. Moreover, ideally the wsa namespace should be declared in the soapenv:Header. Please note at the same time the fault body seems sane. — <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"> <soapenv:Header> <wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" soapenv:mustUnderstand="true">xxxxxxxxxx</wsa:To> <wsa:Action>xxxxxxxxxxxxxxxxxxxxxxxxx</wsa:Action> <wsa:MessageID>urn:uuid:cf9f8e79-9226-4237-b014-bf431778ddab</wsa:MessageID> </soapenv:Header> <soapenv:Body> <soapenv:Fault xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"> <soapenv:Code> <soapenv:Value>soapenv:Sender</soapenv:Value> <soapenv:Subcode> <soapenv:Value>wsa:MessageInformationHeaderRequired</soapenv:Value> </soapenv:Subcode> </soapenv:Code> <soapenv:Reason> <soapenv:Text xmlns:lang="en">A required message information header, To, MessageID, or Action, is not present.</soapenv:Text> </soapenv:Reason> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope> —
        Hide
        olegk Oleg Kalnichevski added a comment -

        While admittedly this does look like a bug in Axiom, I think AxiomSoapHeader#addHeaderElement should register the namespace of the name passed as a parameter the same way the AxiomSoap12Fault#setText does.

        I managed to work the problem around by replacing the code of AxiomSoapHeader#addHeaderElement method with the follwing one

        public SoapHeaderElement addHeaderElement(QName name) {
        try {
        OMNamespace namespace = null;
        String prefix = QNameUtils.getPrefix(name);
        if (StringUtils.hasLength(name.getNamespaceURI()) && StringUtils.hasLength(prefix))

        { namespace = getAxiomHeader().findNamespaceURI(prefix); }

        else if (StringUtils.hasLength(name.getNamespaceURI())) {
        namespace = getAxiomHeader().findNamespace(name.getNamespaceURI(), null);
        if (namespace == null)

        { throw new IllegalArgumentException("Could not resolve namespace of code [" + name + "]"); }

        name = QNameUtils.createQName(name.getNamespaceURI(), name.getLocalPart(), namespace.getPrefix());
        }
        if (namespace == null)

        { namespace = getAxiomHeader().declareNamespace(name.getNamespaceURI(), QNameUtils.getPrefix(name)); }

        SOAPHeaderBlock axiomHeaderBlock = getAxiomHeader().addHeaderBlock(name.getLocalPart(), namespace);
        return new AxiomSoapHeaderElement(axiomHeaderBlock, getAxiomFactory());
        }
        catch (OMException ex)

        { throw new AxiomSoapHeaderException(ex); }

        }

        Show
        olegk Oleg Kalnichevski added a comment - While admittedly this does look like a bug in Axiom, I think AxiomSoapHeader#addHeaderElement should register the namespace of the name passed as a parameter the same way the AxiomSoap12Fault#setText does. I managed to work the problem around by replacing the code of AxiomSoapHeader#addHeaderElement method with the follwing one — public SoapHeaderElement addHeaderElement(QName name) { try { OMNamespace namespace = null; String prefix = QNameUtils.getPrefix(name); if (StringUtils.hasLength(name.getNamespaceURI()) && StringUtils.hasLength(prefix)) { namespace = getAxiomHeader().findNamespaceURI(prefix); } else if (StringUtils.hasLength(name.getNamespaceURI())) { namespace = getAxiomHeader().findNamespace(name.getNamespaceURI(), null); if (namespace == null) { throw new IllegalArgumentException("Could not resolve namespace of code [" + name + "]"); } name = QNameUtils.createQName(name.getNamespaceURI(), name.getLocalPart(), namespace.getPrefix()); } if (namespace == null) { namespace = getAxiomHeader().declareNamespace(name.getNamespaceURI(), QNameUtils.getPrefix(name)); } SOAPHeaderBlock axiomHeaderBlock = getAxiomHeader().addHeaderBlock(name.getLocalPart(), namespace); return new AxiomSoapHeaderElement(axiomHeaderBlock, getAxiomFactory()); } catch (OMException ex) { throw new AxiomSoapHeaderException(ex); } } —
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        I am not so sure about your proposed fix. For one thing, the following code fails with an IllegalArgumentException:

        String namespace = "http://springframework.org/spring-ws";
        QName headerName1 = new QName(namespace, "header1");
        QName headerName2 = new QName(namespace, "header2");

        SoapHeaderElement headerElement1 = soapHeader.addHeaderElement(headerName1);
        SoapHeaderElement headerElement2 = soapHeader.addHeaderElement(headerName2);

        I am working on another fix.

        Show
        arjen.poutsma Arjen Poutsma added a comment - I am not so sure about your proposed fix. For one thing, the following code fails with an IllegalArgumentException: String namespace = "http://springframework.org/spring-ws"; QName headerName1 = new QName(namespace, "header1"); QName headerName2 = new QName(namespace, "header2"); SoapHeaderElement headerElement1 = soapHeader.addHeaderElement(headerName1); SoapHeaderElement headerElement2 = soapHeader.addHeaderElement(headerName2); I am working on another fix.
        Hide
        arjen.poutsma Arjen Poutsma added a comment - - edited

        I'm afraid I can't reproduce this. The following, which is what WS-Addressing does internally:

        SoapMessageFactory messageFactory = new AxiomSoapMessageFactory();
        SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage();
         
        AddressingVersion version = new Addressing10();
         
        MessageAddressingProperties map = new MessageAddressingProperties(new URI("http://springframework/to"),
                new EndpointReference(new URI("http://springframework/from")),
                new EndpointReference(new URI("http://springframework/replyTo")),
                new EndpointReference(new URI("http://springframework/faultTo")),
                new URI("http://springframework/action"),
                new URI("http://springframework/messageId"));
        version.addAddressingHeaders(message, map);
         
        message.writeTo(System.out);

        ends up with:

        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <soapenv:Header>
        <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing" soapenv:mustUnderstand="1">http://springframework/to
        </wsa:To>
        <wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Address>http://springframework/from</wsa:Address>
        </wsa:From>
        <wsa:ReplyTo xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Address>http://springframework/replyTo</wsa:Address>
        </wsa:ReplyTo>
        <wsa:FaultTo xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Address>http://springframework/faultTo</wsa:Address>
        </wsa:FaultTo>
        <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://springframework/action</wsa:Action>
        <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">http://springframework/messageId</wsa:MessageID>
        </soapenv:Header>
        <soapenv:Body/>
        </soapenv:Envelope>

        What version of Axiom are you on? I'm using 1.2.7.

        Show
        arjen.poutsma Arjen Poutsma added a comment - - edited I'm afraid I can't reproduce this. The following, which is what WS-Addressing does internally: SoapMessageFactory messageFactory = new AxiomSoapMessageFactory(); SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage();   AddressingVersion version = new Addressing10();   MessageAddressingProperties map = new MessageAddressingProperties(new URI("http://springframework/to"), new EndpointReference(new URI("http://springframework/from")), new EndpointReference(new URI("http://springframework/replyTo")), new EndpointReference(new URI("http://springframework/faultTo")), new URI("http://springframework/action"), new URI("http://springframework/messageId")); version.addAddressingHeaders(message, map);   message.writeTo(System.out); ends up with: < soapenv :Envelope xmlns:soapenv = "http://schemas.xmlsoap.org/soap/envelope/" > < soapenv :Header> < wsa :To xmlns:wsa = "http://www.w3.org/2005/08/addressing" soapenv:mustUnderstand = "1" >http://springframework/to </ wsa :To> < wsa :From xmlns:wsa = "http://www.w3.org/2005/08/addressing" > < wsa :Address>http://springframework/from</ wsa :Address> </ wsa :From> < wsa :ReplyTo xmlns:wsa = "http://www.w3.org/2005/08/addressing" > < wsa :Address>http://springframework/replyTo</ wsa :Address> </ wsa :ReplyTo> < wsa :FaultTo xmlns:wsa = "http://www.w3.org/2005/08/addressing" > < wsa :Address>http://springframework/faultTo</ wsa :Address> </ wsa :FaultTo> < wsa :Action xmlns:wsa = "http://www.w3.org/2005/08/addressing" >http://springframework/action</ wsa :Action> < wsa :MessageID xmlns:wsa = "http://www.w3.org/2005/08/addressing" >http://springframework/messageId</ wsa :MessageID> </ soapenv :Header> < soapenv :Body/> </ soapenv :Envelope> What version of Axiom are you on? I'm using 1.2.7.
        Hide
        olegk Oleg Kalnichevski added a comment -

        Arjen,

        With all due respect I think you were too hasty in dismissing the issue. I am using Axiom 1.2.8, which explains the difference in behaviour. And yes, the problem is still there.

        (1) Spring WS is unusable with the latest release of Axiom, which, as I said, is likely to be the Axiom's fault in the first place, but it does not really change the fact.
        (2) Spring WS produces SOAP messages that are unnecessarily verbose. What is the point of declaring WSA namespace five times instead of one?
        (3) Spring WS's behaviour is inconsistent. It registers namespaces at the fault level (soapenv:Fault), but for some reason does not do the same at header level (soapenv:Header)

        Moreover there is no way to customize the way Spring WS generates SOAP messages except for a wholesale fork of the entire AxiomSoap* class hierarchy.

        Please consider re-opening the issue

        Oleg

        Show
        olegk Oleg Kalnichevski added a comment - Arjen, With all due respect I think you were too hasty in dismissing the issue. I am using Axiom 1.2.8, which explains the difference in behaviour. And yes, the problem is still there. (1) Spring WS is unusable with the latest release of Axiom, which, as I said, is likely to be the Axiom's fault in the first place, but it does not really change the fact. (2) Spring WS produces SOAP messages that are unnecessarily verbose. What is the point of declaring WSA namespace five times instead of one? (3) Spring WS's behaviour is inconsistent. It registers namespaces at the fault level (soapenv:Fault), but for some reason does not do the same at header level (soapenv:Header) Moreover there is no way to customize the way Spring WS generates SOAP messages except for a wholesale fork of the entire AxiomSoap* class hierarchy. Please consider re-opening the issue Oleg
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        With all due respect I think you were too hasty in dismissing the issue. I am using Axiom 1.2.8, which explains the difference in behaviour. And yes, the problem is still there.

        Ok, I've reopened the issue.

        (1) Spring WS is unusable with the latest release of Axiom, which, as I said, is likely to be the Axiom's fault in the first place, but it does not really change the fact.

        The latest release I can find is 1.2.7 (http://repo2.maven.org/maven2/org/apache/ws/commons/axiom/axiom-api/), I am not sure where to get 1.2.8.

        Could you try Axiom 1.2.7 and see if that works any better for you?

        (2) Spring WS produces SOAP messages that are unnecessarily verbose. What is the point of declaring WSA namespace five times instead of one

        True. I will fix it, and consider that the fix of this issue, if that's OK with you.

        (3) Spring WS's behaviour is inconsistent. It registers namespaces at the fault level (soapenv:Fault), but for some reason does not do the same at header level (soapenv:Header)

        This is actually Axiom doing it's thing. Whenever you call createSOAPFaultCode() on an Axiom SOAPFactory, it adds the namespace of the code at the fault level.

        Moreover there is no way to customize the way Spring WS generates SOAP messages except for a wholesale fork of the entire AxiomSoap* class hierarchy.

        You can always obtain a reference to the raw Axiom SOAPMessage object using getAxiomMessage(). You can manipulate that in any way you want to. I kept Spring-WS's the AxiomSoap* classes package private, because I cannot guarantee that the API will stay backwards compatible over time. In fact, changes in Axiom code already forced me to change the class hierarchy in the past.

        Show
        arjen.poutsma Arjen Poutsma added a comment - With all due respect I think you were too hasty in dismissing the issue. I am using Axiom 1.2.8, which explains the difference in behaviour. And yes, the problem is still there. Ok, I've reopened the issue. (1) Spring WS is unusable with the latest release of Axiom, which, as I said, is likely to be the Axiom's fault in the first place, but it does not really change the fact. The latest release I can find is 1.2.7 ( http://repo2.maven.org/maven2/org/apache/ws/commons/axiom/axiom-api/ ), I am not sure where to get 1.2.8. Could you try Axiom 1.2.7 and see if that works any better for you? (2) Spring WS produces SOAP messages that are unnecessarily verbose. What is the point of declaring WSA namespace five times instead of one True. I will fix it, and consider that the fix of this issue, if that's OK with you. (3) Spring WS's behaviour is inconsistent. It registers namespaces at the fault level (soapenv:Fault), but for some reason does not do the same at header level (soapenv:Header) This is actually Axiom doing it's thing. Whenever you call createSOAPFaultCode() on an Axiom SOAPFactory, it adds the namespace of the code at the fault level. Moreover there is no way to customize the way Spring WS generates SOAP messages except for a wholesale fork of the entire AxiomSoap* class hierarchy. You can always obtain a reference to the raw Axiom SOAPMessage object using getAxiomMessage(). You can manipulate that in any way you want to. I kept Spring-WS's the AxiomSoap* classes package private, because I cannot guarantee that the API will stay backwards compatible over time. In fact, changes in Axiom code already forced me to change the class hierarchy in the past.
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        The duplicate namespace declarations are now gone. I've added a 'addNamespaceDeclaration()' method to SoapElement.

        Show
        arjen.poutsma Arjen Poutsma added a comment - The duplicate namespace declarations are now gone. I've added a 'addNamespaceDeclaration()' method to SoapElement.
        Hide
        olegk Oleg Kalnichevski added a comment -

        Arjen,

        I apologize for being such a mess. Of course, the version Axiom I am using is 1.2.7, not 1.2.8. Stupid me. It turned out I was also unable to reproduce the problem when running the test snippet locally. The problem is perfectly reproducible, though, when code is executed inside the WebLogic Server 9.2 MP1 container. In fact, the following bit is pretty sufficient for triggering the problem.

        AxiomSoapMessageFactory messageFactory = new AxiomSoapMessageFactory();
        SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage();

        QName n1 = new QName("http://schemas.xmlsoap.org/ws/2004/08/addressing", "To", "wsa");
        QName n2 = new QName("http://schemas.xmlsoap.org/ws/2004/08/addressing", "Action", "wsa");

        SoapHeaderElement he1 = message.getEnvelope().getHeader().addHeaderElement(n1);
        he1.setText("whatever");
        SoapHeaderElement h2 = message.getEnvelope().getHeader().addHeaderElement(n2);

        setText("whatever");

        message.writeTo(System.out);

        I am no longer sure whether this is an Axiom issue at all, or Axiom simply ends up picking up a different implementation of some standard API when run inside an WLS container.

        Anyways, this issue has no longer anything to do with Spring WS

        > True. I will fix it, and consider that the fix of this issue, if that's OK with you.

        That would be perfectly fine with me.

        > This is actually Axiom doing it's thing. Whenever you call createSOAPFaultCode() on an Axiom SOAPFactory, it adds the namespace
        > of the code at the fault level

        I believe there is also an explicit call to SOAPFault#declareNamespace in the AxiomSoap12Fault#setValueText. I think AxiomSoapHeader#addHeaderElement ought to behave similarly.

        Thank you so much

        Oleg

        Show
        olegk Oleg Kalnichevski added a comment - Arjen, I apologize for being such a mess. Of course, the version Axiom I am using is 1.2.7, not 1.2.8. Stupid me. It turned out I was also unable to reproduce the problem when running the test snippet locally. The problem is perfectly reproducible, though, when code is executed inside the WebLogic Server 9.2 MP1 container. In fact, the following bit is pretty sufficient for triggering the problem. — AxiomSoapMessageFactory messageFactory = new AxiomSoapMessageFactory(); SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage(); QName n1 = new QName("http://schemas.xmlsoap.org/ws/2004/08/addressing", "To", "wsa"); QName n2 = new QName("http://schemas.xmlsoap.org/ws/2004/08/addressing", "Action", "wsa"); SoapHeaderElement he1 = message.getEnvelope().getHeader().addHeaderElement(n1); he1.setText("whatever"); SoapHeaderElement h2 = message.getEnvelope().getHeader().addHeaderElement(n2); setText("whatever"); message.writeTo(System.out); — I am no longer sure whether this is an Axiom issue at all, or Axiom simply ends up picking up a different implementation of some standard API when run inside an WLS container. Anyways, this issue has no longer anything to do with Spring WS > True. I will fix it, and consider that the fix of this issue, if that's OK with you. That would be perfectly fine with me. > This is actually Axiom doing it's thing. Whenever you call createSOAPFaultCode() on an Axiom SOAPFactory, it adds the namespace > of the code at the fault level I believe there is also an explicit call to SOAPFault#declareNamespace in the AxiomSoap12Fault#setValueText. I think AxiomSoapHeader#addHeaderElement ought to behave similarly. Thank you so much Oleg
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        One thing you could try is to swap the StAX implementation provided by BEA with Woodstox. This probably requires setting classloading to parent-last...

        FYI: the WS-Addressing module currently spits out:

        <?xml version='1.0' encoding='UTF-8'?>
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
            <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
                <wsa:To soapenv:mustUnderstand="1">http://springframework/to</wsa:To>
                <wsa:From>
                    <wsa:Address>http://springframework/from</wsa:Address>
                </wsa:From>
                <wsa:ReplyTo>
                    <wsa:Address>http://springframework/replyTo</wsa:Address>
                </wsa:ReplyTo>
                <wsa:FaultTo>
                    <wsa:Address>http://springframework/faultTo</wsa:Address>
                </wsa:FaultTo>
                <wsa:Action>http://springframework/action</wsa:Action>
                <wsa:MessageID>http://springframework/messageId</wsa:MessageID>
            </soapenv:Header>
            <soapenv:Body/>
        </soapenv:Envelope>

        Show
        arjen.poutsma Arjen Poutsma added a comment - One thing you could try is to swap the StAX implementation provided by BEA with Woodstox. This probably requires setting classloading to parent-last... FYI: the WS-Addressing module currently spits out: <? xml version = '1.0' encoding = 'UTF-8' ?> < soapenv :Envelope xmlns:soapenv = "http://schemas.xmlsoap.org/soap/envelope/" > < soapenv :Header xmlns:wsa = "http://www.w3.org/2005/08/addressing" > < wsa :To soapenv:mustUnderstand = "1" >http://springframework/to</ wsa :To> < wsa :From> < wsa :Address>http://springframework/from</ wsa :Address> </ wsa :From> < wsa :ReplyTo> < wsa :Address>http://springframework/replyTo</ wsa :Address> </ wsa :ReplyTo> < wsa :FaultTo> < wsa :Address>http://springframework/faultTo</ wsa :Address> </ wsa :FaultTo> < wsa :Action>http://springframework/action</ wsa :Action> < wsa :MessageID>http://springframework/messageId</ wsa :MessageID> </ soapenv :Header> < soapenv :Body/> </ soapenv :Envelope>
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Resolving as fixed.

        Show
        arjen.poutsma Arjen Poutsma added a comment - Resolving as fixed.
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Closing old issues

        Show
        arjen.poutsma Arjen Poutsma added a comment - Closing old issues

          People

          • Assignee:
            arjen.poutsma Arjen Poutsma
            Reporter:
            olegk Oleg Kalnichevski
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: