php SOAP not sending certificate.pem - php

I can load in the wsdl, pull out the functions and data types just fine but when I try to call a function on the server I get a connection error. When I look at the soap data passed in the $request it doesn't contain any of the security certificate and no errors are generated.
My code looks like this:
// setup the transaction array
$header = array('local_cert' => "certificate.pem",
'logonUser' => "user_name",
'style' => SOAP_DOCUMENT,
'use' => SOAP_LITERAL,
'exceptions' => true,
'trace' => true);
// create the soap client, this will log us in
$client = new SoapClient($wsdl, $header);
try
{
$response = $client->getMessage($parameters);
}
catch (Exception $e)
{
dumpVars($client->__getLastRequest());
echo 'Caught exception: ', $e->getMessage(), "\n";
}
?>
So my question is this, what do I have to do to get the security certificate to be passed?
Thanks,
Pete

The purpose of local_cert in $header is not sending it in the SOAP call itself. It's only being used as an SSL client certificate. Also, according to this comment on php.net you need to read the file contents of the certificate in order to use it.

2 (small) things :
'logonUser' does not seem to be a valid option for the SoapClient constructor. If it is a required header for this service, consider using soapClient::setSoapHeaders. If it is a standard HTTP login param, use the 'login' key.
try to use the full path of the pem certificate, and make sure it is readable by php

Related

PHP SoapClient Doesn't Retrieve WSDL with Client Certificate

Other similar questions have not helped me resolve this.
I have to retrieve a WSDL file using a client certificate + private key combination from my webserver calling another external SOAP API.
$wsdl = 'https://www.example.com?wsdl';
$endpoint = 'https://www.example.com';
$sslContext = stream_context_create($contextOptions);
$options = [
'local_cert' => '/var/www/combo.pem',
'passphrase' => 'Pass1',
'cache_wsdl' => WSDL_CACHE_MEMORY,
'trace' => 1,
'stream_context' => stream_context_create([
'ssl' => [
'ciphers' => 'RC4-SHA',
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
]
])
];
try{
$soapClient = new SoapClient($wsdl, $options);
}
catch(Exception $e)
{
var_dump($e);
}
The error I'm getting is:
SOAP-ERROR: Parsing WSDL: Couldn't load from '..domain..' : failed to load external entity "..domain..?wsdl"
I tried numerous settings and none of them made any difference to this response. I tried no settings, empty array.
What has worked:
Establishing a raw connection via CURL, so the certificate file is fine
Retrieving WSDL information from SoapUI, so the WSDL destination is correct and the certificate file was okay
phpinfo() returns SoapClient is enabled, OpenSSL is enabled. What else could I try or check?
SOAP error could come from invalid character encoding or maybe some HTTP header missing like 'User-Agent' when you query the remote server.
Try to adding User-Agent to options like the sample below.
$options = array(
'http' => array(
'user_agent' => 'PHP_Embedded_Soap_Client'
)
);
PS: I would not recommend to strict ciphers to: RC4-SHA
I wanted to comment this but based on others' suggestions of using file_get_contents and your reply mentioning that it returned false, I'm now kind of sure it's more of a connection problem. Please check followings:
It's obvious that your actual $wsdl value is different than what is posted but please make sure that .com?wsdl is not happening in your code. it should be .com/?wsdl.
Check your DNS settings. A lookup through dnslookup can help identify problem.
Make sure date & time setting of server is correct. It can lead to SSL errors.
If none of above helped. You might consider downloading WSDL content with other tools (such as cURL) and on different machines to identify the cause of problem.

WS-Security, and how to Authenticate

Documentation of the service, says I need to use WS-Security.
From they support, i got a p12 file, which I should be using.
What I did so far
I ran up SoapUI application, configured it, added wsdl etc, and got message
<faultstring>These policy alternatives can not be satisfied: (...)</faultstring>
So I found I need to add basic Auth to the request. And i got my proper answer.
What I need now
I need to use this to SOAP requests, on my PHP application.
First, i changed p12 file into pem, and tried :
$soapClient = new SoapClient('https://int.pz.gov.pl/pz-services/tpSigning?wsdl',
array('location' => 'https://int.pz.gov.pl/pz-services/tpSigning?wsdl',
'trace' => 1,"exceptions" => 1,
'local_cert'=>'path/cert_file.pem',
'passphrase'=>'cert_password'
));
But I am still getting same fail message about policies not being satisfied:
These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}AsymmetricBinding: Received Timestamp does not match the requirements
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}X509Token: The received token does not match the token inclusion requirement
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}SignedParts: Soap Body is not SIGNED in (...)
Help?
Is it even possible with just PHP? I tried several solutions, found some class extending SoapClient (using user/password, not p12/pem file), found even solution in c# (which I am too ready to use if that's what I need to do - sending xml to c# with WebSocket, and sending it back to browser), but non of those worked.
Changing the cert into pem format is the right way. The native PHP soap client class can not handle p12 certs. Have you tried the following?
try {
$oClient = new SoapClient(
'https://int.pz.gov.pl/pz-services/tpSigning?wsdl',
[
'authentication' => SOAP_AUTHENTICATION_DIGEST,
'exceptions' => true,
'local_cert' => dirname(__FILE__) . 'mycert.pem',
'passphrase' => 'my_passphrase',
'trace' => true,
]
);
} catch (SoapFault $oSoapFault) {
echo "<pre>";
var_dump($oSoapFault);
echo "</pre>";
}
The PHP soap client class uses SOAP_AUTHENTICATION_BASIC by default. Perhaps the DIGEST auth is the right way? Normally the cert includes all the data.
You don 't need the location option. The location option is just required, when using non-wsdl conversation with target namespace as uri option without a direct wsdl file.
And always keep in mind: What works with SoapUI isn 't supposed to run with the native PHP client. ;)

PHP SoapClient with BasicAuth

I have a PHP script trying to connect to a WSDL.
I need to allow self signed AND give basic auth details.
Using SOAP UI, when I connect to the WSDL I am prompted for username / password.
I got this working.
I also found out that each request also requires basic auth (so on the request screen, I have to select Auth, then basic, enter same credentials as I used on the prompt).
How to I do this auth in PHP
As I said, I can connect, not a problem, I seem to kill the service or timeout if I try to make a request
<?php
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
$data = array(
'columnA' => 'dataA',
'columnB' => 'dataB',
'columnC' => 'dataC');
$url = 'https://111.111.111.111:1234/dir/file';
$login = 'username';
$pwd = 'password';
$client = new soapClient(null, array(
'location' => $url,
'uri' => '',
'login' => $login,
'password' => $pwd,
'stream_context' => $context
));
echo "\n\r---connected---\n\r";
$result = $client ->requestName($data);
print_r($result);
?>
My output is
---connected---
Then it seems to hang.
I have tried wrapping it round a try catch and I had the same result.
Any suggestions??
From the Manual soapclient support the http basic auth.
For HTTP authentication, the login and password options can be used to
supply credentials. For making an HTTP connection through a proxy
server, the options proxy_host, proxy_port, proxy_login and
proxy_password are also available. For HTTPS client certificate
authentication use local_cert and passphrase options. An
authentication may be supplied in the authentication option. The
authentication method may be either SOAP_AUTHENTICATION_BASIC
(default) or SOAP_AUTHENTICATION_DIGEST.
$wsdl = "http://example/services/Service?wsdl";
$option = array(
"trace"=>1,
"login"=>"admin",
"password"=>"admin",
);
$client = new SoapClient($wsdl,$option);
But when I initiate the soapclient, it will throw this error
Exception: Unauthorized
I also have tried to put the auth in the url, like
$wsdl = "http://admin:admin#example/services/Service?wsdl";
But it also doesn't works.
Finally I solved it by add authentication to the option. The manual says the authentication default value is the basic auth, but only when I explicitly set it, it can work.
$option = array(
"trace"=>1,
"login"=>"admin",
"password"=>"admin",
"authentication"=>SOAP_AUTHENTICATION_BASIC
);
Try url encoding your username and password inside the url that you are using:
$url = 'http://'.urlencode('yourLogin').':'.urlencode('yourPassword').'#111.111.111.111:1234/dir/file';
Also I don't see you make use of the wsdl in your code example. You can always download a copy of the wsdl locally and then reference that local copy. You can download the wsdl anyway you want (with php, curl, manually).

PHP non blocking soap request

After a user signs up on my website i need to send a soap request in a method that is not blocking to the user. If the soap server is running slow I don't want the end user to have to wait on it. Is there a way I can send the request and let my main PHP application continue to run without waiting from a response from the soap server? If not, is there a way to set a max timeout on the soap request, and handle functionality if the request is greater than a max timeout?
Edit:
I would ideally like to handle this with a max timeout for the request. I have the following:
//ini_set('default_socket_timeout', 1);
$streamOptions = array(
'http'=>array(
'timeout'=>0.01
)
);
$streamContext = stream_context_create($streamOptions);
$wsdl = 'file://' . dirname(__FILE__) . '/Service.wsdl';
try{
if ( file_get_contents( $wsdl ) ) {
$this->_soapClient = new SoapClient($wsdl,
array(
'soap_version' => SOAP_1_2,
'trace' => true,
'stream_context' => $streamContext
)
);
$auth = array('UserName' => $this->_username, 'Password' => $this->_password);
$header = new SoapHeader(self::WEB_SERVICE_URL, "WSUser", $auth);
$this->_soapClient->__setSoapHeaders(array($header));
}//if
}
catch(Exception $e){
echo "we couldnt connect". $e;
}
$this->_soapClient->GetUser();
I set the timeout to 0.01 to try and force the connection to timeout, but the request still seems to fire off. What am I doing wrong here?
I have had the same issues and have implemented solution !
I have implemented
SoapClient::__doRequest();
To allow multiple soap calls using
curl_multi_exec();
Have a look at this asynchronous-soap
Four solutions:
Use AJAX to do the SOAP -> Simplest SOAP example
Use AJAX to call a second PHP file on your server which does the SOAP (best solution imo)
Put the SOAP request to the end of your PHP file(s) (not the deluxe solution)
Use pcntl_fork() and do everything in a second process (I deprecate that, it might not work with every server configuration)
Depending on the way you implement this, PHP has plenty of timeout configurations,
for example socket_set_timeout(), or stream_set_timeout() (http://php.net/manual/en/function.stream-set-timeout.php)

Soap 1.2 not working with stamps.com

I am feebly trying to implement a stamps.com api interface into my platform. This is my first time using SOAP, I event had to recompile PHP to enable the libraries.
I'm moving along but now I'm having a problem. They support soap 1.1 and soap 1.2 requests, and when I run the following code:
$client = new SOAPClient(
'./SWSIM.wsdl',
array(
'trace' => 1
)
);
I get back a successful response from my request that comes after this.
However if I add the option to use soap 1.2 like this:
$client = new SOAPClient(
'./SWSIM.wsdl',
array(
'trace' => 1,
'soap_version' => SOAP_1_2
)
);
I get the following error:
There was an exception running the extensions specified in the config file. ---> Value cannot be null. Parameter name: input
This line is not actually throwing the exception. Its the following command that throws it, but removing the soap_version is what "fixes it". I would like to use soap 1.2 so naturally this is bugging me.
FTR The command I'm running is this:
$authData = array(
"Credentials" => array(
"IntegrationID" => "MYUID",
"Username" => "MYUSERNAME",
"Password" => "MYPASSWORD"
)
);
try {
$objectresult = $client->AuthenticateUser($authData);
} catch (Exception $e) {
echo "EXCEPTION: " . $e->getMessage();
print_r($e);
exit;
}
The WSDL file can be viewed here:
https://swsim.stamps.com/swsim/swsimv22.asmx?wsdl
I have also checked in with their developer support and they said:
"The message you are currently receiving is returned from whichever program you are designing your integration with. This has been commonly noted happening within Visual Basic where is creates a wrapper class that needs certain variables for the response. This could be similar to the behavior that you are experiencing. Please verify how your program language consumes a WSDL."
I also noticed that the __soapCall method excepts an "input headers" argument. I'm not entirely sure I should be / can even use that method in my code. I suppose I should just try and play with it.
Check your WSDL file. I was using the wrong one, and it appears you may be as well. Try this one: http://developer.stamps.com/developer/downloads/files/Stamps.com_SWSIM.wsdl
NOTE: The above is out of date. Contact stamps.com for the current wsdl!
I know this is an old thread, but here is an example class that should get anyone started with the stamps.com api in php https://github.com/aaronjsmith/stamps.com-php
The WSDL looks fine and it's the same input structure for both Soap versions. The problem is a bug somewhere at their end, you'll have to contact them to resolve.
I would also test it via a .NET app just to see if it behaves the same.

Categories