I'm a little bit out of my comfort zone. I'm trying to create a SOAP request with PHP, and I'm using the famous API of KBO, here's the documentation:
So essentially everything went well, but I'm still struggling with something about the authentication, which makes me fail my entire small framework:
<?php
$endpoint = 'https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub';
$wsdl = 'https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub?wsdl';
$username = 'myusername';
$password = 'mypassword';
$timestamp = gmdate('Y-m-d\TH:i:s\Z');
$nonce = base64_encode(random_bytes(16));
$passwordDigest = base64_encode(sha1($nonce . $timestamp . $password, true));
$header = '
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>' . $username . '</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . $passwordDigest . '</wsse:Password>
<wsse:Nonce>' . $nonce . '</wsse:Nonce>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $timestamp . '</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>';
$options = array(
'soap_version' => SOAP_1_1,
'trace' => true,
'exceptions' => true,
'encoding' => 'UTF-8',
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create(array(
'http' => array(
'header' => 'Authorization: WSSE profile=' . $header,
'user_agent' => 'PHPSoapClient'
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
))
);
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
),
));
$options['stream_context'] = $context;
// $options = array(
// 'soap_version' => SOAP_1_1
// );
$client = new SoapClient($wsdl, $options);
// Set up the request parameters
$enterpriseNumber = '0810.002.854';
$request = array('EnterpriseNumber' => $enterpriseNumber);
// Call the SOAP operation with the request parameters
$response = $client->__soapCall('ReadEnterprise', array($request));
// Get the request and response XML
$requestXML = $client->__getLastRequest();
$responseXML = $client->__getLastResponse();
var_dump($response);
I also followed some suggestions from my PHP log file, where it was written to use a different version of the soap version: SOAP_1_1 instead of the SOAP_1_2.
What I find really challenging is the fact that I can't debug it in any way; I have no idea on how I can check the error message, or I can't have any hint in my error log file, it simply mentions the security check, but nothing much.
Has anyone had the same issue?
By the way, the error that I have encountered is the following:
[14-Feb-2023 17:09:24 UTC] PHP Fatal error: Uncaught SoapFault exception: [ns1:SecurityError] A security error was encountered when verifying the message in Stack trace: #0 /Users/mymac/Sites/cboxform/api-call/index.php(55): SoapClient->__soapCall('ReadEnterprise', Array) #1 {main} thrown in /Users/mymac/Sites/cboxform/api-call/index.php on line 55
TLTR:
To summarize, I would need a request that looks like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mes="http://economie.fgov.be/kbopub/webservices/v1/messages" xmlns:dat="http://economie.fgov.be/kbopub/webservices/v1/datamodel">
<soapenv:Header>
<mes:RequestContext>
<mes:Id>myid</mes:Id>
<mes:Language>fr</mes:Language>
</mes:RequestContext>
</soapenv:Header>
<soapenv:Body>
<mes:ReadEnterpriseRequest>
<dat:EnterpriseNumber>0206231995</dat:EnterpriseNumber>
</mes:ReadEnterpriseRequest>
</soapenv:Body>
</soapenv:Envelope>
with a header with a digest password, with timestamp and nonce that will expire in 300 seconds to this endpoint:
https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub?wsdl
with also a username.