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 commented Dec 23, 2015

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

@Jonijo

This comment has been minimized.

Copy link

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 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 commented Apr 14, 2018

@ibuxeda , Could you solve the problem?

@alanviera

This comment has been minimized.

Copy link

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
You can’t perform that action at this time.