Skip to content

Instantly share code, notes, and snippets.

@Turin86
Forked from johnkary/WSSoapClient.php
Last active April 24, 2023 19:37
Show Gist options
  • Star 39 You must be signed in to star a gist
  • Fork 20 You must be signed in to fork a gist
  • Save Turin86/5569152 to your computer and use it in GitHub Desktop.
Save Turin86/5569152 to your computer and use it in GitHub Desktop.
WS-Security for PHP SoapClient
<?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, WSS4J servers and CXF.
*
* @author Roger Veciana - http://www.phpclasses.org/browse/author/233806.html
* @author John Kary <johnkary@gmail.com>
* @author Alberto Martínez - https://gist.github.com/Turin86/5569152
* @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);
}
}
@andymorenoing
Copy link

Sí, le gustaría firmar con un certificado ssl, ¿cómo sería el proceso?

Llame al constructor WSSoapClient (no anula el constructor SoapClient) con los parámetros apropiados.
https://www.php.net/manual/en/soapclient.soapclient.php#120888

Tendrás un ejemplo de consumo y lo usarás en el encabezado que obtengo de la SOAPUI

`soapenv: Header
<wsse: Security xmlns: wsse =" http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd "xmlns: wsu =" http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd ">
<wsse: UsernameToken wsu: Id =" UsernameToken-B89D7F960777898D89160631426090014 ">
wsse: Nombre de usuario ######## </ wsse: Nombre de usuario>
<wsse: Tipo de contraseña = " http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile -1.0 # PasswordText "> ##### </ wsse: Password>
<wsse: Nonce EncodingType =" http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap- message-security-1.0 # Base64Binary "> sBRMmGjIObO6tX0KjOScFA == </ wsse: Nonce>
wsu: Created2020-11-25T16: 24: 20.900Z </ wsu: Created>
</ wsse: UsernameToken>
<wsu: Timestamp wsu: Id = "TS-B89D7F960777898D89160631426090013">
wsu: Created2020-11-25T16: 24: 20.899Z </ wsu: Creado>
wsu: Expires2020-11-25T16: 25: 20.899Z </ wsu: Expires>
</ wsu: Timestamp>
<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 # X509PKIPathv1 "wsu: Id =" X509-B89D7F960777898D8916063142608618 "> ######## CERTIFICA ###################### / s
</ wsse: BinarySecurityToken>
<ds:ID de firma = "SIG-B89D7F960777898D89160631426089212" xmlns: ds = "http://www.w3.org/2000/09/xmldsig# ">
ds: SignedInfo <ds: CanonicalizationMethod Algorithm =" http://www.w3.org/2001/10/xml-exc-c14n# ">
<ec: InclusiveNamespaces PrefixList = "soapenv v1" xmlns: ec = " http://www.w3.org/2001/10/xml-exc-c14n#" />
</ ds: CanonicalizationMethod> <ds: SignatureMethod Algorithm = " http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds: Reference URI = "# id-B89D7F960777898D89160631426086111">
ds: Transforms <ds: Transform Algorithm = " http: // www.w3.org/2001/10/xml-exc-c14n # ">
<ec: InclusiveNamespaces PrefixList =" v1 "xmlns: ec =" http://www.w3.org/2001/10/xml-exc- c14n # "/>
</ ds:Transformar> </ ds: Transformaciones> <ds: DigestMethod Algorithm = " http://www.w3.org/2000/09/xmldsig#sha1" />
DS: DigestValueURDCHKG444RS # / SHsbPH + oRVOS53qjc = </ ds: DigestValue>
</ ds: Reference>
</ ds: SignedInfo>
ds: SignatureValueybjaTDbfjaxY8lCePbN43aIlJ4AINQeGomIkHSbCoYxH + + JUQxeIhUSwo 3VbYG9BCQAX / U6bgyup
00KSASncniw3qWWSAE9z1d / 73zwgAz88ykIuMSxVEC70qc5FoxLXPvQZad15SQjOkyjfDFG83ZTu
YrNLX11bBQfYjhHhfMQFn + #### AAAdlJ2fcRpzPBsSo5VzZtKiNrkbV
1ALT / ## $ $$ fFSASASq8tK6RJxSgzCZmmcDz
3JZA652vHyyT4Sws / ChtSaY1oOS3v0a6LkQJ1w ==
</ ds: SignatureValue>
<ds: KeyInfo Id = "KI-B89D7F960777898D8916063142608619">
<wsse: SecurityTokenReference wsse11: TokenType =" http://docs.oasis-open.org/wss/2004 /01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1 "wsu: Id ="STR-B89D7F960777898D89160631426086110 "xmlns: wsse11 ="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd ">
<wsse: Reference URI =" # X509-B89D7F960777898D8916063142608618 "ValueType =" http: //docs.oasis- open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1 "/>
</ wsse: SecurityTokenReference>
</ ds: KeyInfo>
</ ds: Signature>
</ wsse: Seguridad>

</ soapenv: Encabezado> `

you got an example with the certificate too?

@nbgithub123
Copy link

Hi anyone knows how to implement ws security with a certificate X509 to a soap request instead? need help . thanks

@jgarciafinanciat
Copy link

Hello, can you please help me what should it be called?
I have PHP 8.0.2

@jgarciafinanciat
Copy link

Man this saved the day, I tried the original and it wasn't working for my needs but your fork saved me. Thanks.

Hello, can you please help me what should it be called?
I have PHP 8.0.2

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