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
- 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!







