PHP access to webservice with .cer and .p7b certificates - php

I'm trying to access a webservice from the prefecture that consolidate commercial invoices, the website provides those 2 certificates .cer and .p7b, I've tried both curl and soap clients with several different options in the params array, but still only get 403 or error on loading key.
Can someone explain me which of the certificates I should use, or if both, which goes in which option and others params needed?
Using curl I at least get a 403 answer (which is something expected without the certificate), but on soap client it only gives SOAP-ERROR: Parsing WSDL even it's the very same URL.
Trying loading the keys leads to:
.CER: "unable to set private key file ... type PEM"
.P7B: "could not load PEM client certificate, OpenSSL error:02001002:system library:fopen:No such file or directory, (no key found, wrong pass phrase, or wrong file format?)"
though the path seems to be correct.
Get same errors using cmd line curl with --cert options (though I tried each cert file individually, is there a way to use both simultaneously?)

Related

Any way to force PHP SOAP to call HTTPS instead of HTTP?

I have a VERY simple PHP code:
<?php
$soap = new SoapClient('https://rev-int.api.us.fleetmatics.com/Vehicle/SageQuest/VehicleService.svc?wsdl', array());
var_dump($soap);
When I copy that URL into my browser it loads just fine, with no redirects or anything:
$soap = new SoapClient('https://rev-int.api.us.fleetmatics.com/Vehicle/SageQuest/VehicleService.svc?wsdl
But when I execute that PHP script I get the following error after a PHP timeout:
Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://rev-int.api.us.fleetmatics.com/Vehicle/SageQuest/VehicleService.svc?wsdl=wsdl0' : failed to load external entity "http://rev-int.api.us.fleetmatics.com/Vehicle/SageQuest/VehicleService.svc?wsdl=wsdl0"
Notice the response URL is http://rev-int.api.us.fleetmatics.com/Vehicle/SageQuest/VehicleService.svc?wsdl=wsdl0 which is very similar but not quite accurate. If I search the working WSDL for that given URL I find it at the top:
That said, every URI points to HTTP instead of HTTPS, but if we simply change this in our browser the page loads just fine.
So the question becomes: when we create a PHP SoapClient, can we force all URIs to follow HTTPS regardless of the protocol specified in the WSDL?
The WSDL can stand by itself and contain everything inside, or it can use imports to bring in content from other locations (it usually happens with XSD schemas).
If it imports things, those imports need to be resolved by the client. If they can't be resolved, either because the location is wrong, or the protocol is wrong, or whatever, then the client bails out, because it needs a complete WSDL to understand the service's contract and how to call it, not just the parts it could load.
So you have two options:
Contact the provider of the service and ask them to fix it so all imports can be resolved.
If you can download the WSDL and all the resources it tries to import, by opening in browser and changing the protocol to https, you can save them all locally on disk in the same folder. Assuming you end up with a file named VehicleService.wsdl for the WSDL itself, and VehicleService.xml for the file you got from http://rev-int.api.us.fleetmatics.com/Vehicle/SageQuest/VehicleService.svc?wsdl=wsdl0 somehow, you can then change the WSDL to import this local file with <wsdl:import .... location="VehicleService.xml" /> instead of what it does right now. Then you can feed this local WSDL to your client, and because now everything is in the same folder, it should work.

Missing API key for Google Cloud

I'm attempting to use Google's Natural Language API for PHP, and having followed the instructions, I'm getting an error in the application I've written:
Fatal error: Uncaught Google\Cloud\Core\Exception\ServiceException: {
"error": { "code": 403, "message": "The request is missing a valid API
key.", "status": "PERMISSION_DENIED" } }
I've downloaded the account key file, run the export, but I get the 403 error.
I've created a symbolic link to the file in the project folder, run the export, but I get the 403 error.
I placed the export in the ".bash_profile" file, exited the terminal session, but I get the 403 error.
Provide authentication credentials to your application code by setting
the environment variable GOOGLE_APPLICATION_CREDENTIALS. Replace
[PATH] with the file path of the JSON file that contains your service
account key, and [FILE_NAME] with the filename. This variable only
applies to your current shell session, so if you open a new session,
set the variable again.
When I ran: echo $GOOGLE_APPLICATION_CREDENTIALS the export isn't there, so I ran it again, but I get the 403 error.
I followed the documentation to the letter, and I've gone through it three times, and each time I get the same 403 error.
I see no instructions asking me to store a string value for the API key in the application, but I've found a number of people recommending that, but not provide an example of how or where.
So, some advice would be welcome!
simply do not use an export; while your ~/.bashrc is not apache's .bashrc.
but add the path to the file directly into the PHP code; eg. into a config.php.
or use putenv('GOOGLE_APPLICATION_CREDENTIALS=/var/www/[FILE_NAME].json');
while preventing HTTP access to that file with .htaccess.
or one can even setup with .htaccess, alike
SetEnv GOOGLE_APPLICATION_CREDENTIALS "/var/www/[FILE_NAME].json"

Magento 1.9.1.0 : Unable to load WSDL using soap cleint

I have tried all the answers given in the following threads.
[1] Magento SOAP API - PHP Exception thrown for login method call: "looks like we got no XML document"
[2] Magento SOAP API - PHP Exception error “looks like we got no XML document”
I am able to load the WSDL in the browser and the WSDL URL is in this format
http://www.foo.com/api/v2_soap/?wsdl
This is the error am getting in the console:
looks like we got no XML document .
This error is usually related to Magento setting up a SoapServer, and not to your SoapClient call, which in turn means that it's usually a problem of your server not being able to fetch the WSDL. Connect toyour server via ssh and issue the following command (with your URL)
$ curl -i 'http://www.foo.com/api/v2_soap/?wsdl'
This will output the HTTP headers, and the response. My guess is the response isn't valid XML (includes debugging, or whitespace), curl couldn't connect to the server (because your host's networking is wrong) or your WSDL points to other WSDLs that can't be connected to.
Solve that problem, and you'll be good to go.

How to check if SSL bundle and domain certificates are made from existing private key

If I have pkey, csr (generated from pkey), bundle certificate and domain certificate files. How can I validate if both certificates are made for pkey?
Also is that the right way to validate ssl certificates. Any suggestions?
I would like to avoid using openssl cli tool and use php openssl library or any third party php library.
#HannoBinder was close but it was a bit trickier. Apparently in PHP openssl one must get resource variables from certificate (tested also on certificate bundle file containing domain certificate for nginx) and private key file.
You can get certificate resource with openssl_pkey_get_public. But for private key you must get it with openssl_pkey_get_private. Its not to clearly written in documentation since probably these functions are quite universal.
Also i could not at first understand how to get public key from those resources. Apparently openssl_pkey_get_details can do that.
So in the end I resolved it this way.
$certPubKeyResource = openssl_pkey_get_public(file_get_contents($cert));
$publicKey1 = trim(openssl_pkey_get_details($certPubKeyResource)['key']);
$private_key = openssl_pkey_get_private(file_get_contents($pkey));
$publicKey2 = trim(openssl_pkey_get_details($private_key)['key']);
echo (!strcmp($publicKey1, $publicKey2) ? 'OK' : 'FAIL') . PHP_EOL;
I hope someone will have use for this since I could not find this particular case.
Also If someone will give more in depth answer with maybe some references to useful materials about SSL in PHP I could mark it as a correct answer instead of mine since im quite interested into getting full picture of this topic.

Soap Client Call to SSL

I am trying to get the content of WSDL from HTTPS Server
<?php
echo file_get_contents("https://zendsoap.lan/Zend_Soap_Server.php?wsdl");
?>
It Return:
Warning: file_get_contents() [function.file-get-contents]: SSL operation failed with code 1. OpenSSL Error messages: error:1408E0F4:SSL routines:func(142):reason(244) in /Applications/AMPPS/www/zendSoap.lan/Zend_Soap_Client.php on line 4
Warning: file_get_contents() [function.file-get-contents]: Failed to enable crypto in /Applications/AMPPS/www/zendSoap.lan/Zend_Soap_Client.php on line 4
Warning: file_get_contents(https://zendsoap.lan/Zend_Soap_Server.php?wsdl) [function.file-get-contents]: failed to open stream: operation failed in /Applications/AMPPS/www/zendSoap.lan/Zend_Soap_Client.php on line 4
AND when I can goto the WSDL Location (https://zendsoap.lan/Zend_Soap_Server.php?wsdl): Everything looks fine.
P.S: Can anybody tell me how can I share the WSDL file
I agree with RockyFord regarding it being an SSL issue (I'm pretty sure you will have a self signed certificate in place and due to using SSL there are a few steps you will need to take in order to minimise security concerns). Regarding the immediate issue you could try fixing it with code similar to this:
$url = 'https://zendsoap.lan/Zend_Soap_Server.php?wsdl';
$contextOptions = array(
'ssl' => array(
'verify_peer' => true,
'CN_match' => 'zendsoap.lan' // assuming zendsoap.lan is the CN used in the certificate
)
);
$sslContext = stream_context_create($contextOptions);
$wsdlContent = file_get_contents($url, NULL, $sslContext);
(UPDATE: It might seem like an easy solution to change the code above to
'verify_peer' => false
while it may be ok for basic development it's not really a good idea and definitely shouldn't be used in a production environment as it introduces serious security concerns - see this excellent article on How to properly secure remote API calls over SSL from PHP code by Artur Ejsmont for more on this subject as well as the Transport Layer Security Cheat Sheet and Securing Web Services by OWASP)
To pick up on your point regarding sharing a WSDL from within a Zend Framework application you could do something like this to get started:
// go to application/configs/application.ini
// if your APPLICATION_ENV is development then add the following line in the development section:
phpSettings.soap.wsdl_cache_enabled = 0
The line above will prevent your wsdl being cached during development. Next you might want to create a SoapController and add this action like this:
public function serverAction()
{
$baseUrl = 'http://zendsoap.lan/soap/server';
if( isset( $_GET['wdsl'] ) ) {
$strategy = new Zend_Soap_Wsdl_Strategy_AnyType();
$server = new Zend_Soap_AutoDiscover($strategy);
$server->setUri($baseUrl);
$server->setClass('Application_Model_Web_Service');
$server->handle();
} else {
$server = new Zend_Soap_Server($baseUrl . '?wsdl');
$server->setClass('Application_Model_Web_Service');
$server->handle();
}
}
The nice thing about the approach above is the WSDL will be generated for you on the fly. You will have noticed the setClass() method is going to be called with 'Application_Model_Web_Service' passed as the only parameter. To test your configuration I recommend you create that class and insert the method below. Testing your configuration with a simple service containing a single method will help you with troubleshooting before you make the service more complex. Here is the example method:
// Note: you should definitely comment your methods correctly in the class so
// the WSDL will be generated correctly - by that I mean use #param and #return
// so the correct input and output types can be determined and added to the WSDL
// when the the ZF component generates it for you
/**
* #return string
*/
public function getMessage()
{
return 'ok';
}
(UPDATE: Also in response to the question you asked regarding using Zend_Soap_Client to access the web service, since it looks like you're intending to make it a secure service I'd suggest you raise a separate question regarding setting up secure soap services with php. If you explain more about what you're trying to do in that question you may get some good input from a range of experts on best practices :-)
)
I know you're new to SO so if you're happy with the answer you can accept it, also generally it's best to just reply to an answer rather than add another answer to reply. Easy when you know how of course and even easier when someone tells you ;-)
I tried your way of defining The Soap Server, only thing was I used my custom class instead of using Application_Model_Web_Service. I am using single files for Client & Server. When I run https://zendsoap.lan/Zend_Soap_Server.php without ?wsdl it result in this:
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>WSDL</faultcode>
<faultstring>SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://zendsoap.lan/Zend_Soap_Server.php?wsdl' : failed to load external entity "https://zendsoap.lan/Zend_Soap_Server.php?wsdl"
</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And When I try file_get_contents() the way you told, I get this:
Warning: file_get_contents() [function.file-get-contents]: SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:func(144):reason(134) in /Applications/AMPPS/www/zendSoap.lan/https_soap_test.php on line 16
Warning: file_get_contents() [function.file-get-contents]: Failed to enable crypto in /Applications/AMPPS/www/zendSoap.lan/https_soap_test.php on line 16
Warning: file_get_contents(https://zendsoap.lan/Zend_Soap_Server.php?wsdl) [function.file-get-contents]: failed to open stream: operation failed in /Applications/AMPPS/www/zendSoap.lan/https_soap_test.php on line 16
Here is link to screenshot of My Certificate:
http://i.stack.imgur.com/bKoVD.png
Loads of thanks for your help.
Problem solved By changing 'verify_peer' => false
Can you (#dkcwd) please tell me what should be the code if I use Zend_Soap_Client without file_get_contents(). I mean is there any option which i can't find on internet to do something similar to 'verify_peer' => false.
Loads of Thanks to #dkcwd
UPDATE: Let me summarise what exactly I am doing, I am trying to create a basic SOAP Server over SSL. Before making Web Services available on my Production website, I have to test it on Development system with has got Self Signed Certificate (Whose authentication is a problem right now).
Following are the problems I am facing in that regard:
When I try to call https://zendsoap.lan/Zend_Soap_server.php?wsdl its works fine I can view the wsdl.
But when I try https://zendsoap.lan/Zend_Soap_server.php, I get this:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://zendsoap.lan/Zend_Soap_Server.php?wsdl' : failed to load external entity "https://zendsoap.lan/Zend_Soap_Server.php?wsdl"
Is that something I should be
The reason I made verify_peer=>false as I am running it on dev server so no need to verify my own created certificate, but obviously on production I want the Certificate to be verified.
This thing work fine with NuSoap but most of the stuff in NuSoap is deprecated for our server which is running PHP 5.4.6, So the most reliable solution for me using PHP's SOAP extension. And the reason for me using Zend is we're in process of moving our system from some third party framework to Zend Framework and everyday I get requests from client to add this & that new components, I assumed if I develop every new request from Client using Zend libraries then it will be easy for me in later stages to move to Zend Framework.
I hope I made some sense there.
Many Thanks in advance...

Categories