Rectangle 27 4

Recently I have wrote a class which adds user credentials to SOAP header. To do that you need to create a class which implements SOAPHandler<SOAPMessageContext> interface. For e.g.:

public class MyHandler implements SOAPHandler<SOAPMessageContext> {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class);

    private String username;

    private String password;

    /**
     * Handles SOAP message. If SOAP header does not already exist, then method will created new SOAP header. The
     * username and password is added to the header as the credentials to authenticate user. If no user credentials is
     * specified every call to web service will fail.
     *
     * @param context SOAP message context to get SOAP message from
     * @return true
     */
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        try {
            SOAPMessage message = context.getMessage();
            SOAPHeader header = message.getSOAPHeader();
            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
            if (header == null) {
                header = envelope.addHeader();
            }
            QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials");
            SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials);

            QName qNameUsername = new QName("https://your.target.namespace/", "Username");
            SOAPHeaderElement username = header.addHeaderElement(qNameUsername );
            username.addTextNode(this.username);
            QName qNamePassword = new QName("https://your.target.namespace/", "Password");
            SOAPHeaderElement password = header.addHeaderElement(qNamePassword);
            password.addTextNode(this.password);

            userCredentials.addChildElement(username);
            userCredentials.addChildElement(password);

            message.saveChanges();
            //TODO: remove this writer when the testing is finished
            StringWriter writer = new StringWriter();
            message.writeTo(new StringOutputStream(writer));
            LOGGER.debug("SOAP message: \n" + writer.toString());
        } catch (SOAPException e) {
            LOGGER.error("Error occurred while adding credentials to SOAP header.", e);
        } catch (IOException e) {
            LOGGER.error("Error occurred while writing message to output stream.", e);
        }
        return true;
    }

    //TODO: remove this class after testing is finished
    private static class StringOutputStream extends OutputStream {

        private StringWriter writer;

        public StringOutputStream(StringWriter writer) {
            this.writer = writer;
        }

        @Override
        public void write(int b) throws IOException {
            writer.write(b);
        }
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        LOGGER.debug("handleFault has been invoked.");
        return true;
    }

    @Override
    public void close(MessageContext context) {
        LOGGER.debug("close has been invoked.");
    }

    @Override
    public Set<QName> getHeaders() {
        LOGGER.debug("getHeaders has been invoked.");
        return null;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Note that I am just adding the credentials to the header and returning true. You do what ever you want with whole message and return false if something that is expected fails.

<bean id="soapHandler" class="your.package.MyHandler">
    <property name="username" value="testUser"/>
    <property name="password" value="testPassword"/>
</bean>

<jaxws:client "...">
    <jaxws:handlers>
        <ref bean="soapHandler"/>
    </jaxws:handlers>
</jaxws:client>

But it also can be implemented on the endpoint.

Yes it comes from javax.xml.ws.handler.soap package. I do not know if it will work with JAX-RPC, I only used it with JAX-WS. You should try and see if it works :)

If you have a handler and you can receive the message into that handler, that means that you can do anything to the message. You just need figure out how to modify the message of RPC style. Here is the examples how it is done via JAX-RPC: ibm.com/developerworks/xml/library/ws-tip-extend/index.html

I don't know anything about RPC because I haven't used it. I suggest you to consider taking a look at Apache CXF: cxf.apache.org/docs/writing-a-service-with-spring.html. It is the newest web service stack. It is based on JAX-WS but has a lot of other features which sometimes are very useful.

If you would be using JAX-WS there a lot of documentation on how to make this work. The solution with JAX-WS is to annotate your java parameter: @XmlElement(required=true). But I don't know about JAX-RPC

java - Adding elements in SOAP Header request for authentication - Sta...

java xml web-services soap soapheader
Rectangle 27 5

I have followed the steps mentioned by @LaabidiRaissi. The code works fine but it never appends the security element under the header. I have confirmed it by printing out the outbound SOAP message to System.out. After a deep research, I have found that the SOAPMessage needs to be explicitly saved for reflecting the updated message header.

soapMessage.saveChanges();

The code from @Laabidi's answer used to work for me with Java 7 and tomcat 7. After upgrading to Java 8 and tomcat 8 soapMessage.saveChanges() is needed.

java - How to add header to SOAP request? - Stack Overflow

java web-services jax-ws webservice-client
Rectangle 27 3

I've managed to solve this somehow, thanks @GPI for tips. I'm fairly new to the Spring WS and javax.xml.whatever, so I can't tell if this is either the right or elegant way of doing this, but it does exactly what I want.

This code adds custom header elements to <SOAP-ENV:Header>, based on my objects generated from XSD schemas via JAXB. I have no idea how does the Transformer know where I want to put these elements, but it places them correctly in Header section.

public class HeaderComposingCallback implements WebServiceMessageCallback {

    private final String action;

    public HeaderComposingCallback( String action ) {
        this.action = action;
    }

    @Override
    public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException {

    SoapHeader soapHeader = ((SoapMessage)webServiceMessage).getSoapHeader();

    try {
        JAXBContext context = JAXBContext.newInstance( MessageHeader.class, Security.class );

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        Document securityDocument = builder.newDocument();
        Document headerDocument = builder.newDocument();

        Marshaller marshaller = context.createMarshaller();
        marshaller.marshal( HeaderFactory.getHeader( action ), headerDocument );
        marshaller.marshal( SecurityFactory.getSecurity(), securityDocument );

        Transformer t = TransformerFactory.newInstance().newTransformer();

        DOMSource headerSource = new DOMSource( headerDocument );
        DOMSource securitySource = new DOMSource( securityDocument );

        t.transform( headerSource, soapHeader.getResult() );
        t.transform( securitySource, soapHeader.getResult() );

    } catch (JAXBException | ParserConfigurationException e) {
        e.printStackTrace();
    }
}

}
HeaderComposingCallback
marshalSendAndReceive()
doWithMessage
@Override
    public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException {

    SoapHeader soapHeader = ((SoapMessage)webServiceMessage).getSoapHeader();

    try {
        JAXBContext context = JAXBContext.newInstance( MessageHeader.class, Security.class );

        Marshaller marshaller = context.createMarshaller();
        marshaller.marshal( header, soapHeader.getResult() );
        marshaller.marshal( security, soapHeader.getResult() );

    } catch (JAXBException e) {
        e.printStackTrace();
    }
}

Not sure why you need to create the document here, why don't you simply marshal to the header's Result directly? As in: marshaller.marshal(marshaller.marshal(HeaderFactory.getHeader(action), soapHeader.getResult()). Also, you might want to consider wiring up a Spring OXM Jaxb2Marshaller and inject that into the callback class. That would save you the hassle of creating the JAXB context and the marshaller.

java - Add custom element to SOAP header in Spring WS - Stack Overflow

java spring web-services soap spring-ws
Rectangle 27 2

I ran into a similar issue. I am not sure if this is useful or not.

The setup here is Certificate based, Oracle Application Server 10g, and .Net to consume the services. Using SOAPUi was very useful while trying to figure out what was happening with the Request and then the response.

I have not tried modifying the code to use basicHttpBinding, but I used WSHttpBinding as the base of my configuration in code. Then used

WSHttpBinding binding = new WSHttpBinding()
        {
            CloseTimeout = new TimeSpan(0, 1, 0),
            OpenTimeout = new TimeSpan(0, 1, 0),
            SendTimeout = new TimeSpan(0, 1, 0),
            AllowCookies = false,
            BypassProxyOnLocal = false,
            HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
            MaxBufferPoolSize = 524288,
            MaxReceivedMessageSize = 65536,
            MessageEncoding = WSMessageEncoding.Text,
            UseDefaultWebProxy = false,
            ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
            {
                MaxDepth = 32,
                MaxArrayLength = 16384,
                MaxBytesPerRead = 4096,
                MaxNameTableCharCount = 16384,
                MaxStringContentLength = 8192
            }
        };
        binding.Security.Mode = SecurityMode.Transport;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
        binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
        binding.Security.Transport.Realm = string.Empty;
        binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
        binding.Security.Message.EstablishSecurityContext = true;
        binding.Security.Message.NegotiateServiceCredential = true;

        CustomBinding customBinding = new CustomBinding();
        BindingElementCollection collection = binding.CreateBindingElements();
foreach (BindingElement element in collection)
        {
            if (typeof(TextMessageEncodingBindingElement) == element.GetType())
            {
                TextMessageEncodingBindingElement item = element as TextMessageEncodingBindingElement;
                if (null != item)
                {
                    item.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None);
                    customBinding.Elements.Add(item);
                }
            }
            else
                customBinding.Elements.Add(element);
        }

I used the ChannelFactory and added an EndPoint Behavior for a Message Inspector. At this point I then had control of the request and I could add the appropriate header and modified the mustUnderstand on the Action.

Using SOAPUi I took my Message.ToString() and put that in SOAPUI and tested the request. Once the items that were needed were added to the request, it was then determined that the OAS server was not replying with all the necessary elements. Using the message inspector for the reply I modified the message to include the missing headers. I can't remember where I found the base code for the message inspector, but you would need to modify your code to utlize it properly.

For the transform message in

public object BeforeSendRequest

I needed to modify the Header, so using a for loop I grabbed the XElement and added the OASIS header and added a To header.

XNamespace xmlns = "http://schemas.xmlsoap.org/soap/envelope/";
                XElement securityHeader = new XElement(
                    xmlns + "Security", 
                    new XAttribute(xmlns + "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"), 
                    new XAttribute(xmlns + "xmlns", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"), 
                    new XAttribute(xmlns + "mustUnderstand", "0"));
                element.Add(securityHeader);
else if (localName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
            {
                foreach (XAttribute a in element.Attributes())
                {
                    if (a.Name.LocalName == "mustUnderstand")
                        a.Value = "0";
                }
            }

My problem was that the Service didn't reply with an Action Header

So in the

public void AfterReceiveReply

I called my TransformReply returning type Message with something like the following. You may need to modify values for the string.Empty, but this is just an example.

Message reply = Message.CreateMessage(message.Version, null, reader);
        reply.Headers.Add(MessageHeader.CreateHeader("Action", string.Empty, string.Empty, false));
        reply.Properties.CopyProperties(message.Properties);

I would really suggest using a tool such as SOUPUI to beable to mess with the envelope and see the reply. If you do SSL, you'll need to create a cacert file and place it in the SSLSettings of the preferences.

Thanks Adam! looks like interesting info. I've moved on to a different consulting engagement now though, so can no longer try things out against that system. Fyi, previously client ultimately solved the issue via a different architectural approach.

web services - WCF Client - How to process or ignore a MustUnderstand ...

wcf web-services jboss wcf-binding ws-security
Rectangle 27 2

When working with SOAP messages the dispatching in the server side is done according to the soap action header, which instructs the dispatcher what is the corresponding method which should handle the message.

Sometimes soap action is empty or invalid (java interop).

I think you best option is to implement an IDispatchOperationSelector. With this, you can override the default way the server assigns incoming messages to operations.

In the next sample, the dispatcher will map the name of the first element inside the SOAP body to an operation name to which the message will be forward for processing.

public class DispatchByBodyElementOperationSelector : IDispatchOperationSelector
    {
        #region fields

        private const string c_default = "default";
        readonly Dictionary<string, string> m_dispatchDictionary;

        #endregion

        #region constructor

        public DispatchByBodyElementOperationSelector(Dictionary<string, string> dispatchDictionary)
        {
            m_dispatchDictionary = dispatchDictionary;
            Debug.Assert(dispatchDictionary.ContainsKey(c_default), "dispatcher dictionary must contain a default value");
        }

        #endregion

        public string SelectOperation(ref Message message)
        {
            string operationName = null;
            var bodyReader = message.GetReaderAtBodyContents();
            var lookupQName = new
               XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);

            // Since when accessing the message body the messageis marked as "read"
            // the operation selector creates a copy of the incoming message 
            message = CommunicationUtilities.CreateMessageCopy(message, bodyReader);

            if (m_dispatchDictionary.TryGetValue(lookupQName.Name, out operationName))
            {
                return operationName;
            }
            return m_dispatchDictionary[c_default];
        }
    }

Thank you. This is a coorect answer. It works, but not for all problems.

c# - WCF add custom HTTP header into request - Stack Overflow

c# wcf soap
Rectangle 27 0

The SOAP protocol message format defines 3 elements: Envelope, Header and Body. Of the three, the Header is optional and can be omitted, the other two are mandatory (SOAP 1.1 Specification: 4. SOAP Envelope, SOAP 1.2 Specification: 5. SOAP Message Construct).

Thus, You can't completely get rid of the Envelope element, as it is required by the SOAP protocol message format. But, You can use some ready-made library that could prepare the message for You implicitly, so that You don't have to deal with it. It will also allow You to keep the SOAP message construction code in one place somewhere deep where You don't see it. And it will definitely make Your code cleaner.

A quick googling tells that there is a jQuery Plugin called jqSOAPClient available to us, but unfortunately, the jQuery Plugins website is off-line at the moment. Other alternative is JavaScript SOAP Client.

Call SOAP-XML Web Services with jQuery Ajax - Minified implementation?...

jquery ajax web-services soap
Rectangle 27 0

This was asked some time ago but I found this question in my search for a solution.

So here is what worked for me. Just set the enableUnsecuredResponse="true" in the custom binding.

<customBinding>
    <binding name="WsHttpSoap11" >          
        <textMessageEncoding messageVersion="Soap11WSAddressing10" />            
        <security authenticationMode="UserNameOverTransport" enableUnsecuredResponse="true"></security>
        <httpsTransport/>
    </binding>
  </customBinding>

c# - WCF & SOAP Headers - How to ensure that the default header elemen...

c# .net xml wcf soap
Rectangle 27 0

soap:Header is an XML element inside the XML/SOAP data "payload". This is different than an HTTP headers. In the contract, SOAPAction (along with Content-Length, etc) is an HTTP header.

XmlHttpRequest.setRequestHeader is used for specifying HTTP headers. It has nothing to do with anything inside the XML (directly).

xmlhttp.setRequestHeader("SOAPAction", "http://www.webserviceX.NET/GetQuote");
xmlhttp.setRequestHeader("Content-Type", "text/xml");
...
var xml = '<?xml version="1.0" encoding="utf-8"?>' +
    '<soap:Envelope...' + etc;
xmlhttp.send(xml)

It is the XML which contains soap:Envelope and the child elements soap:Header and soap:Body.

asp.net - How to add custom header to ASMX web service call using jque...

asp.net jquery ajax asmx soapheader
Rectangle 27 0

Are truly sure your target (Java-based) web service requires a Microsoft-based namespace element in the SOAP body instead of the SOAP header? That seems bogus to me.

<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">GetCapabilities</Action>

Most web services only need the Action in the HTTP header, not as part of the SOAP body:

POST /StockQuote HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://electrocommerce.org/abc#MyMessage"

<SOAP-ENV:Envelope...

Can you provide a raw, working SOAP request (including HTTP headers) for comparison? You can test it out independent from .NET by using this little web-page based client: Simplest SOAP example using Javascript. I assume from your other posting here which shows a "working" request that you really don't need the Microsoft Action element in your SOAP body.

Thanks for your post. The target web service does NOT require a Microsoft-based namespace element. It does however require the operation to be in the BODY of the SOAP Request and not in the Header. That is why i need the firs to look more like the second soap request. Second soap request (SOAP envelope WITHOUT "/messageContract") is a RAW example of a working SOAP request. I tested it out independent of .NET using SOAPUI.

Right, so you don't need the Action element in the body at all, just the actual operation element in the body. Where's the problem, then?

I would still like to use "/messageContract" because for some (weird) reason i thought it might make my code work. I GUESS THE REAL problem is still stackoverflow.com/questions/5460107/ Should i close this post? It is pretty redonkulous now that you point it out. My real problem is the above link.

Tell you what, i'll leave this open, but help me figure out why objects are not populating (stackoverflow.com/questions/5460107/) and i'll give you BOTH answers :)

.net - How to get message contract to send soap action in body and not...

.net wcf web-services soap
Rectangle 27 0

Points to Note

Below mentioned are few important ponts about SOAP header element to take note of

Rectangle 27 0

The problem you're having is because the X3 Web Service is unable to identify header parameters without the namespace reference

Moreover, you should use a SoapVar instead of the basic array to build a correct header

$ns = 'http://www.adonix.com/WSS';
 $headerParams = array('ns1:codeLang'      => 'FRA',
                       'ns1:codeUser'      => 'ADM',
                       'ns1:password'      => 'XXX',
                       'ns1:poolAlias'     => 'TEST',
                       'ns1:requestConfig' => 'trace');
 $soapStruct = new SoapVar($headerParams, SOAP_ENC_OBJECT);
 $header     = new SoapHeader($ns, 'CAdxCallingContext', $soapStruct, false);

PHP : Subnode of SOAP Header element is not found or recognized - Stac...

php soap header
Rectangle 27 0

Each SOAP header block (immediate child of the Header element) must according to the SOAP specification be namespace qualified. Your intended XML, will hence violate the SOAP specification.

You can of course use other means or plain XML libraries to create the XML you want, but when using soapHeader.addHeaderElement, the JAX-RS implementation (at least in Oracle's JRE) verifies this requirement and throws an exception if you try to add a header block with an empty namepsace.

java - How to remove the namespace of SOAPHeaderElement - Stack Overfl...

java xml jaxb
Rectangle 27 0

It's impossible and the fault message states it pretty clear.

Note: All immediate child elements of the Header element must be namespace-qualified

Thanks a lot !, I thought it was possible. That output mentioned is generated from SoapUI indeed, and I was trying to replicated it using JAX-WS RI 2.2. The 'endpoint' is a WFC service build with .net 3.5; and that's the way this service accept request.

java - Adding SOAP header elements without namespace - Stack Overflow

java xml web-services soap soapheader
Rectangle 27 0

public class Custom : MessageHeader
{
    private string _attr;
    private string _headerName = "HeaderInfo";
    private string _elementName = "ProcType";
    private string _headerNamespace = "http://schemas.tempuri.fi/process/2016/04/";

    public ProcessGuidHeader(string attr)
    {
        _attr = attr;
    }

    public string Attr
    {
        get { return _attr; }
    } 

    public override string Name
    {
        get { return _headerName; }
    }

    public override string Namespace
    {
        get { return _headerNamespace; }
    }

    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        writer.WriteElementString(_elementName, _attr);
    }
}

This does not set any namespace for header child element and solves the issue.

c# - How to set soap message header element namespace explicitly in .N...

c# .net web-services wcf soap
Rectangle 27 0

The problem with your code is lack of Authentication element in the SOAP header. Take a look at the WSDL, it should always be there:

<wsdl:operation name="CheckIfAuthorized">
    <soap:operation soapAction="http://www.cmicdataservices.com/CheckIfAuthorized" style="document"/>
    <wsdl:input>
        <soap:body use="literal"/>
        <soap:header message="tns:CheckIfAuthorizedAuthentication" part="Authentication" use="literal"/>
    </wsdl:input>
    <wsdl:output>
        <soap:body use="literal"/>
    </wsdl:output>
</wsdl:operation>

You server fails with exception because of incorrect XML when there is no Authentication element in the CheckIfAuthorized request. Here is sample client in Python to demonstrate the idea of solving the problem, I think it's not a problem for you to convert it to Java.

from suds.client import Client

client = Client("http://www.cmicdataservices.com/datacenter/service.asmx?wsdl")
auth = client.factory.create('Authentication')
auth.UserName = "username"
auth.Password = "password"
client.set_options(soapheaders=auth)
client.service.CheckIfAuthorized()

java - soap ui generated code - Stack Overflow

java soap netbeans soapui
Rectangle 27 0

It is possible to make a .NET 2.0 client support WS Addressing. You can accomplish this by downloading and installing Webservice Enhancements 3.0 (WSE). http://www.microsoft.com/en-us/download/details.aspx?id=14089 When you add a reference to the Microsoft.Web.Services3 assembly and change the code generated by adding the web service reference. Change System.Web.Services.Protocols.SoapHttpClientProtocol into Microsoft.Web.Services3.WebServicesClientProtocol and the code will support WS Adressing. The action element will now be added to the SOAP header.

Although this workaround does the job I still would prefer a WCF service reference connection.

c# - Binding problems .NET client to HPOM web service - Stack Overflow

c# .net web-services soap binding
Rectangle 27 0

final String datPrefix = "dat";
final String datNamespaceUri = "UPRS/Services/IProviderDataManagement/Datatypes";

final String mesPrefix = "mes";
final String mesNamespaceUri = "UPRS/Services/IProviderDataManagement/Messages";

SoapEnvelope se = s.getEnvelope();
se.addNamespaceDeclaration(mesPrefix,
        mesNamespaceUri);
se.addNamespaceDeclaration(datPrefix,
        datNamespaceUri);

SoapMessage s = (SoapMessage) message;

Element root = new Element("requestContext", mesPrefix, mesNamespaceUri);
Element child = new Element("commandId", datPrefix, datNamespaceUri).addContent(guid);
root.addContent(child);

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new JDOMSource(root), s.getSoapHeader().getResult());
<SOAP-ENV:Header>
        <mes:requestContext xmlns:mes="UPRS/Services/IProviderDataManagement/Messages">
            <dat:commandId xmlns:dat="UPRS/Services/IProviderDataManagement/Datatypes">ba7b1e13-8a06-49b6-a264-fc0298f55f4f</dat:commandId>
        </mes:requestContext>
    </SOAP-ENV:Header>

Welcome to SO! Please include explanation of what your code does and how it answers the question. If you get a code snippet as an answer, you may not know what to do with it. Answer should give the OP guidance on how to debug and fix their problem. Pointing out, what the idea behind your code is, greatly helps in understanding the issue and applying or modifying your solution.

Add child elements to custom SOAP header in Spring-WS - Stack Overflow

soap header spring-ws saaj
Rectangle 27 0

UsernameToken
wsse:Username

First, thanks for your answer. Is there an element which can be used the same way like the "tenant"-tag, but which isn't a custom extension?(To write into the soap which user is the tenant)

Doesn't look like it from the schema.

One last question. How can I check if such a structure allows arbitrary elements?

xs:any

structure - SOAP WS-Security header UsernameToken is element tenant va...

soap structure ws-security usernametoken
Rectangle 27 0

In your model correct XML, you have 'APIKey' and such nested inside a 'Credentials' element, inside the SOAP header. Your PHP code won't generate this.

You need something like this function that permits you to add headers to your soap request. The header you want to add is something like this:

$ns = 'http://tempuri.org/'; //Namespace of the webservice
$headerbody = array("APIKey" => "HISY20Y4-8405-91SK-L0S7-9A17252E548A");

//Create Soap Header.        
$header = new SOAPHeader($ns, 'Credentials', $headerbody);        

//set the Headers of Soap Client. 
$client->__setSoapHeaders($header);

At that point, your request should work (although that code is untested).

Thanks @Gian, that sent me in the right direction. (once I worked out the last line had to go after new SoapClient). I'll post the final code below, as I had to wrestle with nested XML as well and i haven't been able to find a good solution to this anywhere.

Consuming to a .NET SOAP service from PHP with authentication - Stack ...

php .net soap soap-client
Rectangle 27 0

Message Formatting:

An ebXML message has to be formatted according to the ebXML message service specification and must conform to the MIME syntax, format, and encoding rules. The definition of the XML elements are provided by an XML schema, which extends SOAP to define the ebXML message header, trace header, manifest, status, and acknowledgment.