-
-
Save Turin86/5569152 to your computer and use it in GitHub Desktop.
<?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 <[email protected]> | |
* @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); | |
} | |
} |
Thanks a lot. I don't know why some people keeps using this outdated and inconvenient standard. They should move to RESTful Webservices >.<
Nice, but how do i use this class?
how to implement?
Please share sample code?
How to see last request? I have put __getLastRequest
in your class and return like return parent::__getLastRequest();
but it returns null
Yes, you would like to sign with an ssl certificate, how would the process be
Yes, you would like to sign with an ssl certificate, how would the process be
Call the WSSoapClient contructor (does not override the SoapClient constructor) with the appropiate parameters.
https://www.php.net/manual/en/soapclient.soapclient.php#120888
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
You will have an example of consumption and use this in the header that I get from the 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:Username########</wsse:Username>
<wsse:Password Type="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:Created>
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:Signature Id="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:Transform></ds:Transforms><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
1hI/##$$$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:Security>
</soapenv:Header>`
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#120888Tendrá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?
Hi anyone knows how to implement ws security with a certificate X509 to a soap request instead? need help . thanks
Hello, can you please help me what should it be called?
I have PHP 8.0.2
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
Thanks very much