Hola a todos,
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());
}
?>
Agradezco cualquier ayuda que me puedan brindar,
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:
WSDoAllReceiver: security processing failed; nested exception is:
org.apache.ws.security.WSSecurityException: The signature verification failed
Extraña cosa, cuando el mensaje es exactamente el mismo el mensaje es distinto. Espero que ésto sirva de algo.