Estoy haciendo un desarrollo donde necesito un consumir un servicio web que implementa WS-Security.
Para garantizar la característica de Non-Repudiation (es decir, que quien envíe un mensaje no puede negar que lo ha hecho), se deben firmar digitalmente los mensajes XML a ser enviados al servicio web usando WS-Security, específicamente XML Signature.
Una persona que ya hizo pruebas de conexión al WS (con java) me envió un archivo keyStore que utilizó y le funcionó. Yo con una herramienta llamada portecle, extraje la clave privada y el certificado, y estoy usando una librería que encontré llamada soap-wsse.php (esta usa otra librería llamada xmlseclibs). Con esto ya he podido firmar el mensaje, sin embargo obtengo el siguiente mensaje:
Código:
WSDoAllReceiver: security processing failed (actions number mismatch)
Éste es el código que estoy utilizando.
Código PHP:
<?php
require_once('soap-wsse2.php');
class WSSoapClient extends SoapClient
{
//Ruta del fichero de la clave privada
public $key_file="";
//Passphrase de la clave privada
public $passphrase="";
//Ruta del fichero del certificado
public $cert_file="";
//Mensaje SOAP enviado
public $soap_sent="";
public $user = "";
public $password = "";
function __doRequest($request, $location, $saction, $version)
{
//return parent::__doRequest($request, $location, $action, $version);
//Creamos un DOMDocument
$doc = new DOMDocument('1.0');
//Cargamos el XML pasado por parámetro
$doc->loadXML($request);
//Creamos una instancia de WSSESoap con el documento, sin "mustUnderstand" ni "actor"
$objWSSE = new WSSESoap($doc,false,false);
$objWSSE->addTimestamp(300);
$objWSSE->addUserToken($this->user, $this->password);
//Creamos una instacian de XMLSecurityKey con el RSA SHA1 y de tipo privado
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1,array ('type'=>'private'));
//Pasamos el valor de passphrase
$objKey->passphrase=$this->passphrase;
//Cargamos la clave privada con la ruta del fichero, que es fichero y que no es certificado
$objKey->loadKey($this->key_file, TRUE);
//Firmamos el mensaje
$objWSSE->signSoapDoc($objKey);
//Añadimos el BinarySecurityToken, pasamos el contenido del certificado, le decimos que es formato PEM
$token = $objWSSE->addBinaryToken(file_get_contents($this->cert_file),TRUE);
//Añadimos el KeyInfo
$objWSSE->attachTokentoSig($token);
//Guardamos el XML enviado
$this->soap_sent=$objWSSE->saveXML();
echo htmlentities($this->soap_sent);
//Llamamos al método __doRequest padre
return parent::__doRequest($this->soap_sent, $location, $saction, $version);
}
}
$auth_login = 'YYYYYYYY';
$auth_password = 'ZZZZZZ';
$opciones = array(
'proxy_host' => 'proxy',
'proxy_port' => '8080',
'proxy_login' => 'user',
'proxy_password' => 'xxxxxxxxxx',
'trace' => 1,
'cache_wsdl' => WSDL_CACHE_NONE,
'login' => $auth_login,
'password' => $auth_password
);
$url = 'http://.../ConfrontaWebService?wsdl';
$pk_file = 'keys/test_pk.pem';
$cert_file = 'keys/test_cert.cer';
$pk_passphrase = 'XXXXXXXXX';
$objParametrosDTO = new stdClass();
$objParametrosDTO->secuenciaCuestionario = '10';
$objParametrosDTO->secuenciaEmpleado = '12';
$objParametrosDTO->tipoIdentificacion = '1';
$objParametrosDTO->numeroIdentificacion = '12312';
$objParametrosDTO->telefono = '1231';
$objParametrosDTO->departamento = '1';
$objParametrosDTO->ciudad = '1';
$objParametrosDTO->tipoEntidad = '1';
$objParametrosDTO->codigoEntidad = '1';
$objParametrosDTO->clave = $auth_login;
$objParametrosDTO->password = $auth_password;
$objParametrosConsulta = new stdClass();
$objParametrosConsulta->codigoInformacion = '';
$objParametrosConsulta->motivoConsulta = '';
$objParametrosConsulta->numeroIdentificacion = '';
$objParametrosConsulta->tipoIdentificacion = '';
try{
$sClient = new WSSoapClient($url, $opciones);
//Cargamos la clave, passphrase y certificado
$sClient->key_file=$pk_file;
$sClient->cert_file=$cert_file;
$sClient->passphrase=$pk_passphrase;
$sClient->user = $auth_login;
$sClient->password = $auth_password;
//$result = $sClient->consultaPlano($objParametrosConsulta);
$result = $sClient->obtenerCuestionario($objParametrosDTO);
var_dump($result);
}catch(Exception $e){
echo "<h2>Exception Error!</h2>";
echo $e->getMessage();
//echo "<h2>Last Request!</h2>";
//echo htmlentities($sClient->__getLastRequest());
}
?>
Gracias de antemano.
Saludos.
Info adicional
Utilizando un programa llamado SoapUI, envié el XML que genera mi código, la respuesta del servidor fue distinta:
Código:
Extraña cosa, cuando el mensaje es exactamente el mismo el mensaje es distinto. Espero que ésto sirva de algo. WSDoAllReceiver: security processing failed; nested exception is: org.apache.ws.security.WSSecurityException: The signature verification failed