Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
<?php
/**
* This class can add WSSecurity authentication support to SOAP clients
* implemented with the PHP 5 SOAP extension.
*
* It extends the PHP 5 SOAP client support to add the necessary XML tags to
* the SOAP client requests in order to authenticate on behalf of a given
* user with a given password.
*
* This class was tested with Axis and WSS4J servers.
*
* @author Roger Veciana - http://www.phpclasses.org/browse/author/233806.html
* @author John Kary <johnkary@gmail.com>
* @author Alberto Martínez - https://github.com/Turin86
* @see http://stackoverflow.com/questions/2987907/how-to-implement-ws-security-1-1-in-php5
*/
class WSSoapClient extends SoapClient
{
private $OASIS = 'http://docs.oasis-open.org/wss/2004/01';
/**
* WS-Security Username
* @var string
*/
private $username;
/**
* WS-Security Password
* @var string
*/
private $password;
/**
* WS-Security PasswordType
* @var string
*/
private $passwordType;
/**
* Set WS-Security credentials
*
* @param string $username
* @param string $password
* @param string $passwordType
*/
public function __setUsernameToken($username, $password, $passwordType)
{
$this->username = $username;
$this->password = $password;
$this->passwordType = $passwordType;
}
/**
* Overwrites the original method adding the security header.
* As you can see, if you want to add more headers, the method needs to be modified.
*/
public function __call($function_name, $arguments)
{
$this->__setSoapHeaders($this->generateWSSecurityHeader());
return parent::__call($function_name, $arguments);
}
/**
* Generate password digest.
*
* Using the password directly may work also, but it's not secure to transmit it without encryption.
* And anyway, at least with axis+wss4j, the nonce and timestamp are mandatory anyway.
*
* @return string base64 encoded password digest
*/
private function generatePasswordDigest()
{
$this->nonce = mt_rand();
$this->timestamp = gmdate('Y-m-d\TH:i:s\Z');
$packedNonce = pack('H*', $this->nonce);
$packedTimestamp = pack('a*', $this->timestamp);
$packedPassword = pack('a*', $this->password);
$hash = sha1($packedNonce . $packedTimestamp . $packedPassword);
$packedHash = pack('H*', $hash);
return base64_encode($packedHash);
}
/**
* Generates WS-Security headers
*
* @return SoapHeader
*/
private function generateWSSecurityHeader()
{
if ($this->passwordType === 'PasswordDigest')
{
$password = $this->generatePasswordDigest();
$nonce = sha1($this->nonce);
}
elseif ($this->passwordType === 'PasswordText')
{
$password = $this->password;
$nonce = sha1(mt_rand());
}
else
{
return '';
}
$xml = '
<wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:wsse="' . $this->OASIS . '/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>' . $this->username . '</wsse:Username>
<wsse:Password Type="' . $this->OASIS . '/oasis-200401-wss-username-token-profile-1.0#' . $this->passwordType . '">' . $password . '</wsse:Password>
<wsse:Nonce EncodingType="' . $this->OASIS . '/oasis-200401-wss-soap-message-security-1.0#Base64Binary">' . $nonce . '</wsse:Nonce>';
if ($this->passwordType === 'PasswordDigest')
{
$xml .= "\n\t" . '<wsu:Created xmlns:wsu="' . $this->OASIS . '/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $this->timestamp . '</wsu:Created>';
}
$xml .= '
</wsse:UsernameToken>
</wsse:Security>';
return new SoapHeader(
$this->OASIS . '/oasis-200401-wss-wssecurity-secext-1.0.xsd',
'Security',
new SoapVar($xml, XSD_ANYXML),
true);
}
}
?>
@AntonioCS

This comment has been minimized.

Copy link

@AntonioCS AntonioCS commented Dec 23, 2015

Finally!!!! Something that works!! Thanks!!!

@Jonijo

This comment has been minimized.

Copy link

@Jonijo Jonijo commented May 13, 2016

In case youre wondering how to implement.

$stub = new WSSoapClient('https://my-wsdl-location?wsdl', array(
'trace' => 1,
'encoding' => 'UTF-8',
));

$functions = $stub->__getFunctions();
var_dump($functions);

$stub->__setUsernameToken('username', 'password', 'PasswordText');

try {

    $config= array("Value"=>"somedata");

    $var = $stub->queryValue($config);

    var_dump($var);


} catch(SoapFault $fault) {
    print("Fault string: " . $fault . "\n");
}
@ibuxeda

This comment has been minimized.

Copy link

@ibuxeda ibuxeda commented Oct 23, 2017

Hi, this code is very usefull, but, I'm having some troubles to make him work in my project, my scenario is the next one, I need to consume a web service from an financial entity with a lot of security parameters. I test the web service with SOAPUI app an its working fine. The security is at IP level (IP fixed), SOAP header with ws-security (like this code) and they give me an certificate to installl on the server computer. I was testing the code with others web services and its working fine. When i try to connect to web service i have the next error message:

Fault string: SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://linkpagosservices.redlink.com.ar/linkpagosservices/AltaDeudasServices?wsdl' : failed to load external entity "https://linkpagosservices.redlink.com.ar/linkpagosservices/AltaDeudasServices?wsdl" in C:\inetpub\wwwroot\wsLinkPHP\index.php:39 Stack trace: #0 C:\inetpub\wwwroot\wsLinkPHP\index.php(39): SoapClient->SoapClient('https://linkpag...', Array) #1 {main}

The code i'm using

'; $options = array( 'soap_version'=>SOAP_1_1, 'cache_wsdl'=>WSDL_CACHE_NONE, 'connection_timeout'=>15, 'trace'=>1, 'encoding'=>'UTF-8', 'exceptions'=>true, 'keep_alive' => true, 'location' => 'https://linkpagosservices.redlink.com.ar:443/linkpagosservices/AltaDeudasServices'); //endpoint taked from SOAPUI try { echo '
object
'; //$webservice = new WSSoapClient('https://linkpagosservices.redlink.com.ar/linkpagosservices/AltaDeudasServices?wsdl', array('trace' => 1, 'encoding' => 'UTF-8',)); $webservice = new WSSoapClient('https://linkpagosservices.redlink.com.ar/linkpagosservices/AltaDeudasServices?wsdl', $options); echo '
HEADER
'; $webservice->__setUsernameToken('USER', 'PASS', 'PasswordText'); // echo '
object created
'; $functions = $webservice->__getFunctions(); echo '
DUMP
'; var_dump($functions); echo 'The end'; } catch(SoapFault $fault) { print("Fault string: " . $fault . "\n"); } ?>

If anyone can help me please, I'll be very greatful.

Regards

@pablopassoni

This comment has been minimized.

Copy link

@pablopassoni pablopassoni commented Apr 14, 2018

@ibuxeda , Could you solve the problem?

@alanviera

This comment has been minimized.

Copy link

@alanviera alanviera commented Dec 6, 2018

Hola, tengo el mismo problema, lo pudieron resolver? Saludos.

Hello, I have the same problem, could you fix it? Regards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment