PHP+SOAP+WSSE

24 Jun 2009

Pick any two and your life will remain nice and easy. Pick all and you will want to hurt yourself with random object in reach. PHP native class for handling SOAP calls can't do WS-Security. Here's how one can work around this problem.

class WSSESoapClient extends SoapClient {                                                                                           
	protected $wsseUser;
	protected $wssePassword;

    public function setWSSECredentials($user, $password) {
        $this->wsseUser = $user;
        $this->wssePassword = $password;
    }

    public function __doRequest($request, $location, $action, $version) {
        if (!$this->wsseUser or !$this->wssePassword) {
            return parent::__doRequest($request, $location, $action, $version);
        }

        // get SOAP message into DOM
        $dom = new DOMDocument();
        $dom->loadXML($request);
        $xp = new DOMXPath($dom);
        $xp->registerNamespace('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/');

        // search for SOAP header, create one if not found
        $header = $xp->query('/SOAP-ENV:Envelope/SOAP-ENV:Header')->item(0);
        if (!$header) {
            $header = $dom->createElementNS('http://schemas.xmlsoap.org/soap/envelope/', 'SOAP-ENV:Header');
            $envelope = $xp->query('/SOAP-ENV:Envelope')->item(0);
            $envelope->insertBefore($header, $xp->query('/SOAP-ENV:Envelope/SOAP-ENV:Body')->item(0));
        }

        // add WSSE header
        $usernameToken = $dom->createElementNS('http://schemas.xmlsoap.org/ws/2002/07/secext', 'wsse:UsernameToken');
        $username = $dom->createElementNS('http://schemas.xmlsoap.org/ws/2002/07/secext', 'wsse:Username', $this->wsseUser);
        $password = $dom->createElementNS('http://schemas.xmlsoap.org/ws/2002/07/secext', 'wsse:Password', $this->wssePassword);
        $usernameToken->appendChild($username);
        $usernameToken->appendChild($password);
        $header->appendChild($usernameToken);

        // perform SOAP call
        $request = $dom->saveXML();
        return parent::__doRequest($request, $location, $action, $version);
    }

} // class WSSESoapClient
Use method setWSSECredentials() to enclose WS-Security header in SOAP message.

Code above is a modification and extension of reply to Q#953639 on StackOverflow.com

Digg del.icio.us StumbleUpon Wykop Reddit Folksr

permalink | trackback | rss

 
 
jac

i wonder if it will works with IBM webservices in EPUAP

tom

probably yes but they prefer x.509 authentication ;)

stronger

Feel free to share your findings - good luck.

Bhargav Khatana

There is way in native PHP soap lib to add WSSE header without extending it,

I have posted this recently on PHP.net
http://php.net/manual/en/soapclient.soapclient.php'

It took me longer than a week to figure out how to implement WSSE (Web Service Security) headers in native PHP SOAP. There are no much resource available on this, so thought to add this here for community benefit.

Step1: Create two classes to create a structure for WSSE headers

<?php
class clsWSSEAuth {
private $Username;
private $Password;
function __construct($username, $password) {
$this->Username=$username;
$this->Password=$password;
}
}

class clsWSSEToken {
private $UsernameToken;
function __construct ($innerVal){
$this->UsernameToken = $innerVal;
}
}
?>

Step2: Create Soap Variables for UserName and Password

<?php
$username = 1111;
$password = 1111;

//Check with your provider which security name-space they are using.
$strWSSENS = "http://schemas.xmlsoap.org/ws/2002/07/secext";

$objSoapVarUser = new SoapVar($username, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS);
$objSoapVarPass = new SoapVar($password, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS);
?>

Step3: Create Object for Auth Class and pass in soap var

<?php
$objWSSEAuth = new clsWSSEAuth($objSoapVarUser, $objSoapVarPass);
?>

Step4: Create SoapVar out of object of Auth class

<?php
$objSoapVarWSSEAuth = new SoapVar($objWSSEAuth, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'UsernameToken', $strWSSENS);
?>

Step5: Create object for Token Class

<?php
$objWSSEToken = new clsWSSEToken($objSoapVarWSSEAuth);
?>

Step6: Create SoapVar out of object of Token class

<?php
$objSoapVarWSSEToken = new SoapVar($objWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'UsernameToken', $strWSSENS);
?>

Step7: Create SoapVar for 'Security' node

<?php
$objSoapVarHeaderVal=new SoapVar($objSoapVarWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'Security', $strWSSENS);
?>

Step8: Create header object out of security soapvar

<?php
$objSoapVarWSSEHeader = new SoapHeader($strWSSENS, 'Security', $objSoapVarHeaderVal,true, 'http://abce.com');

//Third parameter here makes 'mustUnderstand=1
//Forth parameter generates 'actor="http://abce.com"'
?>

Step9: Create object of Soap Client

<?php
$objClient = new SoapClient($WSDL, $arrOptions);
?>

Step10: Set headers for soapclient object

<?php
$objClient->__setSoapHeaders(array($objSoapVarWSSEHeader));
?>

Step 11: Final call to method

<?php
$objResponse = $objClient->__soapCall($strMethod, $requestPayloadString);
?>

stronger

Well done Bhargav!

Your turn:

nick:
and?:
www (if any):
Wpisz kod:code
 
 
PHP+SOAP+WSSE php soap ws-security wsse