6

I am currently developing a WS client that needs to sign its requests before sending them to the server. I have a private key and a certificate for this purpose but I am struggling with the security header. The expected structure of the output XML should be something like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header><wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-
1.0.xsd"><wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="CertId-45..."
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-
1.0.xsd"> ... </wsse:BinarySecurityToken><ds:Signature Id="Signature-13"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-14">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>62...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
...
</ds:SignatureValue>
<ds:KeyInfo Id="KeyId-...">
<wsse:SecurityTokenReference wsu:Id="STRId-..." xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-wssecurity-utility-1.0.xsd"><wsse:Reference URI="#CertId-..." ValueType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature></wsse:Security></soapenv:Header>
<soapenv:Body wsu:Id="id-14" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 

I tried using xmlseclibs but I can't figure out how to include all the required information since the examples are rather basic.

I suppose I could go the DIY way and manually build the headers but I would like to keep it as simple as possible.

Any clues?

Additional information

I am currently using SoapClient for this task. Thing is, I don't know how to do this exactly. The XML that I am sending requires signing its content and I have done so manually (using a c14n function and calculating its digest ..). However, in order to do the same for the whole body I'd need access to the raw XML (I suppose) so I do not think that would work.

I have not tried to create SOAP headers manually as I am trying to avoid any hacks. I am looking for something that is both easy to implement and easy to work on.

My code currently looks like this (keeping it to a minimum for improved readability):

$context = stream_context_create(array(
    'ssl' => array(
        'verify_peer' => false,
        'allow_self_signed' => true,
        'ciphers'=>'SSLv3'
    )
));

$client = new SoapClient($url, array(
    //'connection_timeout' => 100,
   /* 'passphrase' => $pass,

    'local_cert' => $keystore,*/
    'stream_context' => $context,
   // 'connection_timeout' => 1,
    'trace' => true, 
    'exceptions' => true
));

$soapBody = new \SoapVar($xml, \XSD_ANYXML);

try{
    $client->__soapCall('SOMEACTION', array($soapBody));
}
catch (SoapFault $exception) {
        echo $exception->getMessage();

    }

The xml variable contains XML code that I know is correct. It has been tested both on SoapUI (where I had to provide my keys and password) and an online testing service my provider has made available. This means that the data being sent is 100% correct.

However, my PHP code ends up with "Internal Error". I am assuming it has to do with the lack of certificates and the like. I am not sure if there is a way to get more information from the response but there is no documentation about the said error.

I have been toying with several options and keystores, private keys and certificates in several formats without getting any positive result. I think it all has to do with the fact that the correct header is not being sent.

Thanks a lot.

wtf8_decode
  • 406
  • 5
  • 18
  • You're not asking for much here. It's not clear which errors you get nor what specifically is working. So effectively your question seems way too broad. Existing material how to create and add WSSE Headers with PHP actually even exists on this website so it is specifically absolutely not clear what you're asking here for, as by the text in the title, this question has been asked before but you don't highlight what makes it different to existing material. Additionally it might be even that you don't need any headers at all because certificates are handled on the transport layer above SOAP. – hakre Dec 19 '14 at 14:25
  • I have not been able to find anything that has worked for me. Most people seem to use username and password auth. I have to send headers like those described as specified by my provider. I don't think it could be seen as 'too wide' given that the question is quite specific: generate headers like the one shown. – wtf8_decode Dec 19 '14 at 14:30
  • Are you able to create the XML Signature already? Are you able to generally create SOAP Headers already and were you able to verify that against the remote system? How does your current code look like? Which error do you get back from the remote system? What does the documentation of the remote system says about the error message or code you get back? What have you tried to trouble-shoot the problem so far? – hakre Dec 19 '14 at 14:35
  • I'm having lunch, I'll add information asap – wtf8_decode Dec 19 '14 at 14:40
  • No rush, eating slowly is more important :) – hakre Dec 19 '14 at 14:42
  • I added more information (not sure if you've seen it). – wtf8_decode Dec 22 '14 at 17:49
  • As you have 'trace' => true you could check which XML is send to the server (and which response you got). That often contains more info / hints than just the exception message like "internal error". And can you provide any technical details / reference documentation to which kind of request signing you relate to, on which layer following which (W3C/IETF) specification? – hakre Dec 22 '14 at 18:01
  • I would have to try and print the raw response but it's not getting printed on screen. If I handle the error and print its message I get just that. If I let things crash and remove the try catch block this is what I get an `Uncaught SoapFault exception`: [env:Client] Internal Error in ...`. I don't really understand your question, do you mean you want a link to the xsd ? – wtf8_decode Dec 22 '14 at 18:09
  • are you looking at the output in your browser? If so, you need to encode the raw request or response data as HTML before you display it, e.g. with [`htmlspecialchars()`](http://php.net/htmlspecialchars) or tell your browser the output is text by setting the content-type header accordingly (whichever is easier for you, see as well: [How to display XML in HTML in PHP?](http://stackoverflow.com/q/2864303/367456)) – hakre Dec 22 '14 at 18:12
  • And for WS-Security headers, the solution in http://stackoverflow.com/a/6677930/367456 seems to be accepted and working. – hakre Dec 22 '14 at 18:39
  • I am running my script via the console like `php script.php`. Thanks for the link, I will have a look at it. Some of the information posted looks very promising. Now that I read it more throughly I think OP's problem is rather different. His problem is that he can't get SoapClient to use a certain WSDL URL and needs to get that sorted out. My problem is that I can't use a certain service without passing the appropriate header. Currently no headers are being sent. I'll try and see if I can extend the SoapClient class and manually set some headers but even if it did work it's not what i'm after. – wtf8_decode Dec 22 '14 at 19:24
  • Do you mean SOAP headers or HTTP headers? For HTTP headers you can do that via the stream $context you already use for SSL options, `header` is inside the [HTTP options](http://php.net/manual/en/context.http.php). For SOAP headers that is different, see the WS-Security header related question [I gave earlier](http://stackoverflow.com/a/6677930/367456). – hakre Dec 22 '14 at 19:38

0 Answers0