Я пытался реализовать WSSESoapServer с помощью:
https://github.com/robrichards/wse-php
Который не имеет пример или руководство так же, как Проверка подписи в реализации сервера WS * указал.
Позвольте мне пройти через шаги, которые я предпринял, и где я застрял:
Сгенерирован закрытый ключ и сертификат для клиента и сервера
Private key:
openssl genrsa -aes128 -out filename.key -passout pass:password
Certificate:
openssl req -x509 -sha256 -new -key privatekey.key -passin pass:password -days 1825 -out certificate.cer
В результате: закрытый ключ клиента (pass: client_test) и закрытый ключ сервера (pass: server_test) и сертификат для обоих.
Изменены .key расширения на .pem (или возникает ошибка)
Добавлена $ objKey-> passphrase в client.php:
/* create new XMLSec Key using AES256_CBC and type is private key */
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
$objKey->passphrase = "client_test";
/* load the private key from file - last arg is bool if key in file (true) or is string (false) */
$objKey->loadKey(PRIVATE_KEY, true);
Изменен server.php:
$xmlSoap = DOMDocument::load('php://input');
в
$xmlSoap = new DOMDocument();
$xmlSoap->load('php://input');
потому что я получил устаревшую ошибку и не смог вызвать load статическим способом
Запустите клиент и получите сообщение об ошибке:
Ошибка: SOAP-ENV: серверная процедура ‘EncryptedData’ отсутствует
Вот где он застревает, и я понятия не имею, что делать.
Я новичок в SOAP, WSDL и WS-Security.
Client.php
<?php
require_once 'xmlseclibs-master/xmlseclibs.php';
require_once 'wse-php-master/src/WSSESoap.php';
ini_set("soap.wsdl_cache_ttl", 0 );
ini_set("soap.wsdl_cache_enabled", 0);
use RobRichards\WsePhp\WSSESoap;
use RobRichards\XMLSecLibs\XMLSecurityKey;
define('PRIVATE_KEY', './test_certificates/client_test_private_key.pem');
define('CERT_FILE', './test_certificates/client_test_public.cer');
define('SERVICE_CERT', './test_certificates/service_public.cer');
class MySoap extends SoapClient
{
public function __doRequest($request, $location, $saction, $version, $one_way = NULL)
{
$doc = new DOMDocument('1.0');
$doc->loadXML($request);
$objWSSE = new WSSESoap($doc);
/* add Timestamp with no expiration timestamp */
$objWSSE->addTimestamp();
/* create new XMLSec Key using AES256_CBC and type is private key */
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
$objKey->passphrase = "client_test";
/* load the private key from file - last arg is bool if key in file (true) or is string (false) */
$objKey->loadKey(PRIVATE_KEY, true);
/* Sign the message - also signs appropiate WS-Security items */
$options = array("insertBefore" => false);
$objWSSE->signSoapDoc($objKey, $options);
/* Add certificate (BinarySecurityToken) to the message */
$token = $objWSSE->addBinaryToken(file_get_contents(CERT_FILE));
/* Attach pointer to Signature */
$objWSSE->attachTokentoSig($token);
$objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC);
$objKey->generateSessionKey();
$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
$siteKey->loadKey(SERVICE_CERT, true, true);
$options = array("KeyInfo" => array("X509SubjectKeyIdentifier" => true));
$objWSSE->encryptSoapDoc($siteKey, $objKey, $options);
$retVal = parent::__doRequest($objWSSE->saveXML(), $location, $saction, $version);
$doc = new DOMDocument();
$doc->loadXML($retVal);
$options = array("keys" => array("private" => array("key" => PRIVATE_KEY, "isFile" => true, "isCert" => false)));
$objWSSE->decryptSoapDoc($doc, $options);
return $doc->saveXML();
}
}
$wsdl = 'tps.wsdl';
$sc = new MySoap($wsdl);
try {
echo($sc->sayHello("John"));
} catch (SoapFault $e) {
echo "Error: " . $e->faultcode . " " . $e->getMessage();
}
Server.php
<?php
require_once 'xmlseclibs-master/xmlseclibs.php';
require_once 'wse-php-master/src/WSSESoapServer.php';
ini_set("soap.wsdl_cache_ttl", 0 );
ini_set("soap.wsdl_cache_enabled", 0);
use RobRichards\WsePhp\WSSESoapServer;
function sayHello($name) {
return 'Hallo ' . $name;
}
try {
// get soap message
$xmlSoap = new DOMDocument();
$xmlSoap->load('php://input');
// validate signature
$validateSignature = new WSSESoapServer($xmlSoap);
if(!$validateSignature->process())
file_put_contents("log.txt", "soapserver: SIGNATURE VALIDATION ERROR - CONTINUING WITHOUT SIGNATURE\n", FILE_APPEND);
$wsdl = 'tps.wsdl';
$sServer = new SoapServer($wsdl);
$sServer->handle($validateSignature->saveXML());
} catch (Exception $fault) {
file_put_contents("log.txt", "soapserver soapfault: ".print_r($fault, true), FILE_APPEND);
}
tps.wsdl
<?xml version="1.0" encoding="utf-8" ?>
<definitions name = "TPS"targetNamespace = "http://localhost/"xmlns:tns = "http://localhost/"xmlns = "http://schemas.xmlsoap.org/wsdl/"xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"xmlns:xsd = "http://www.w3.org/2001/XMLSchema">
<message name = "SayHelloRequest">
<part name = "name" type = "xsd:string"/>
</message>
<message name = "SayHelloResponse">
<part name = "greeting" type = "xsd:string"/>
</message>
<portType name = "GetHelloResponses">
<operation name = "sayHello">
<input message = "tns:SayHelloRequest"/>
<output message = "tns:SayHelloResponse"/>
</operation>
</portType>
<binding name = "GetHelloResponsesBinding" type = "tns:GetHelloResponses">
<soap:binding style = "rpc"transport = "http://schemas.xmlsoap.org/soap/http"/>
<operation name = "sayHello">
<soap:operation soapAction = "sayHello"/>
<input>
<soap:body
encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/"namespace = "urn:tps:helloservice"use = "encoded"/>
</input>
<output>
<soap:body
encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/"namespace = "urn:tps:helloservice"use = "encoded"/>
</output>
</operation>
</binding>
<service name = "SayHelloService">
<documentation>WSDL File for HelloService</documentation>
<port binding = "tns:GetHelloResponsesBinding" name = "GetUserResponsesPort">
<soap:address
location = "http://localhost/server.php" />
</port>
</service>
</definitions>
Задача ещё не решена.
Других решений пока нет …