6

I need to add the following complex header with different namespace and types to my SoapClient Header.

<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <wsse:Security soapenv:mustUnderstand="1" 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">
        <wsse:UsernameToken>
            <wsse:Username>****</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>
    <wsa:Action>/IntS5/S5WS</wsa:Action>
</soapenv:Header>

As proposed in other answers I tried the following approach in my php project.Since I need WSA Addressing, I set the wsa:Action with security header together.

    $header_part = '<wsse:Security soapenv:mustUnderstand="1" 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">'
         . '<wsse:UsernameToken><wsse:Username>****</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>'
         . '</wsse:UsernameToken></wsse:Security><wsa:Action>/IntS5/S5WS</wsa:Action>';

    $soap_var_header = new SoapVar($header_part, XSD_ANYXML, null, null, null);
    $soap_header = new SOAPHeader('http://www.w3.org/2005/08/addressing', 'wsa', $soap_var_header);
    $client->__setSoapHeaders($soap_header);

Some how __soapCall returns me the following error.

SoapFault exception: [Client] DTD are not supported by SOAP.I am not sure if it's related to header or the parameters of the putCall. Anybody can help me ?

EDIT: The problem is probably related with the namespace of the HEADER/Envelope.

The request which is sent to server looks like this. UPDATED

<?xml version="1.0" encoding="UTF-8"?>
                    <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://ws.s5.mediasat.de/" xmlns:ns2="http://www.w3.org/2005/08/addressing">
                        <env:Header>
                            <wsse:Security env:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                                <wsse:UsernameToken>
                                    <wsse:Username>****</wsse:Username>
                                    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">*****</wsse:Password>
                                </wsse:UsernameToken>
                            </wsse:Security>
                            <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">/IntS5/S5WS</wsa:Action>
                        </env:Header>
                        <env:Body>
                            <ns1:putCall>
                                <transaction>createIncident</transaction>
                                <transactionSender>Request</transactionSender>
                                <caseDataModel>
                                    <senderId>7</senderId>
                                    <ticketTypeId>102</ticketTypeId>
                                    <title>test</title>
                                    <priorityId>101</priorityId>
                                    <categoryId>128</categoryId>
                                    <description>Description</description>
                                    <ticketNumberSender>INCC00000743809</ticketNumberSender>
                                    <createTypeId>701</createTypeId>
                                    <serviceId>B001APP05K</serviceId>
                                    <categoryId>128</categoryId>
                                    <serviceRecipientId>77888</serviceRecipientId>
                                    <serviceLocationSAPCode>V135</serviceLocationSAPCode>
                                </caseDataModel>
                            </ns1:putCall>
                        </env:Body>
                    </env:Envelope>

The request that works on SOAP UI

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.s5.mediasat.de/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security soapenv:mustUnderstand="1" 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">
            <wsse:UsernameToken>
                <wsse:Username>***</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">***</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        <wsa:Action>/IntS5/S5WS</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ws:putCall>
            <transaction>createIncident</transaction>
            <transactionSender>Request</transactionSender>
            <caseDataModel>
                <senderId>7</senderId>
                <ticketTypeId>102</ticketTypeId>
                <title>test</title>
                <priorityId>101</priorityId>
                <categoryId>128</categoryId>
                <description>Description</description>
                <ticketNumberSender>INCC00000743809</ticketNumberSender>
                <createTypeId>701</createTypeId>
                <serviceId>B001APP05K</serviceId>
                <categoryId>128</categoryId>
                <serviceRecipientId>77888</serviceRecipientId>
                <serviceLocationSAPCode>V135</serviceLocationSAPCode>
            </caseDataModel>
        </ws:putCall>
    </soapenv:Body>
</soapenv:Envelope>

Is there anyway to set/override the namespace for the header?

Ilker Baltaci
  • 11,644
  • 6
  • 63
  • 79

2 Answers2

3

You should generate the header procedurally instead of using the string.

Example:

<?php

$client = new SoapClient(null, array(
    'location' => "http://localhost/soap/",
    'uri' => "http://ws.s5.mediasat.de/",
    'soap_version'   => SOAP_1_2
));

$username = '***';
$password = '***';
$sec_namespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
$wsa_namespace = 'http://www.w3.org/2005/08/addressing';

// prepare security token
$node1 = new \SoapVar($username, XSD_STRING, null, null, 'Username', $sec_namespace);

$xml = new XMLWriter(); // this is a little hacky, but no other way to set the type as far as I know
$xml->openMemory();
$xml->startElementNS('wsse', 'Password',$sec_namespace);
$xml->writeAttribute('Type', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText');
$xml->Text($password);
$xml->endElement();
$node2 = new \SoapVar($xml->outputMemory(), XSD_ANYXML);

$token = new \SoapVar(array($node1, $node2), SOAP_ENC_OBJECT, null, null, 'UsernameToken', $sec_namespace);
$security = new \SoapVar(array($token), SOAP_ENC_OBJECT, null, null, 'Security', $sec_namespace);
$soap_header_sec = new \SOAPHeader($sec_namespace, 'Security', $security, true);

// prepare action token
$action = new \SoapVar('/IntS5/S5WS', XSD_STRING, null, null, 'Action', $wsa_namespace);
$soap_header_action = new \SOAPHeader($wsa_namespace, 'Action', $action, false);

// set prepared headers
$client->__setSoapHeaders(
    [$soap_header_sec,$soap_header_action]
 );

$client->putCall();

This will produce the valid envelope with all namespaces set:

<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://ws.s5.mediasat.de/" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns3="http://www.w3.org/2005/08/addressing" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
  <env:Header>
    <ns2:Security env:mustUnderstand="true">
      <ns2:UsernameToken>
        <ns2:Username>***</ns2:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">***</wsse:Password>
      </ns2:UsernameToken>
    </ns2:Security>
    <ns3:Action>/IntS5/S5WS</ns3:Action>
  </env:Header>
  <env:Body>
    <ns1:putCall env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" />
  </env:Body>
</env:Envelope>
luki
  • 194
  • 1
  • 11
  • BTW it should be $xml->startElementNS('ns2', 'Password',$sec_namespace); – Ilker Baltaci Jul 03 '17 at 08:55
  • the problem is xmlns:env="http://www.w3.org/2003/05/soap-envelope" if i could change it to "http://schemas.xmlsoap.org/soap/envelope/" the new generated request works.is it possible somehow? – Ilker Baltaci Jul 03 '17 at 09:00
  • @IlkerBaltaci think that\`s the SOAP 1.1, just change in `'soap_version' => SOAP_1_2` to SOAP_1_1 – luki Jul 03 '17 at 12:18
  • @IlkerBaltaci about the `$xml->startElementNS('ns2', 'Password',$sec_namespace);`, it\`s better to not reuse the same alias because it might change is you add more namespaces – luki Jul 03 '17 at 12:23
  • if I set 'soap_version' => SOAP_1_1 I get Wrong version error. – Ilker Baltaci Jul 03 '17 at 13:43
  • I implemented a class that extends SoapClient and replaced http://www.w3.org/2003/05/soap-envelope with http://schemas.xmlsoap.org/soap/envelope/.Now the request returns me looks like we got no XML document.If i copy paste the __last_request of the soapclient it seems to be ok.Where could be the problem. – Ilker Baltaci Jul 03 '17 at 13:50
  • @IlkerBaltaci it`s really hard to say, can you provide some simplified code to show how you did it? Maybe try to use the SoapClient in your class instead of extending it. – luki Jul 03 '17 at 15:57
  • WSDL of the service would also come in handy. – luki Jul 03 '17 at 16:04
0
  1. The name space "http://www.w3.org/2005/08/addressing" is not bound to the prefix "wsa".

  2. The "mustUnderstand" attribute must use the prefix "env" not "soapenv".

You can declare the missing namespace locally. You just have to fix you header_part to look like this:

header_part = '<wsse:Security env:mustUnderstand="1" 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">'
     . '<wsse:UsernameToken><wsse:Username>****</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>'
     . '</wsse:UsernameToken></wsse:Security><wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">/IntS5/S5WS</wsa:Action>';

Note: Maybe it is obvious but it is kind of dangerous to assume that the prefix for the "http://www.w3.org/2003/05/soap-envelope" will always be "env". The framework can change this at any time. If you want to be on the really safe side you might prefer to bind the namespace locally to a new prefix:

<wsse:Security soapenv:mustUnderstand="1" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" ...

But having one namespace bound to two different prefixes will make things even harder to read and understand so I would say it is a question of taste.

fhossfel
  • 2,041
  • 16
  • 24
  • The question is how to add xmlns:wsa="http://www.w3.org/2005/08/addressing" to Header in soapclient – Ilker Baltaci Jun 30 '17 at 14:57
  • i changed the header as you proposed but server sends me "looks like we got no XML document".I copied to whole request body and pasted to SOAP UI. It returns me "Policy enforcement failed to authenticate the request." since the security header is not recognized. – Ilker Baltaci Jun 30 '17 at 21:50
  • Can you post the complete request that is generated. – fhossfel Jun 30 '17 at 22:18
  • Can you try to add the wsu namespace declaration? That is the only difference I see... – fhossfel Jul 01 '17 at 01:40