I'm trying to perform soap request to web-service written on C# via https. Server uses self-signed certificate.
After many failed attempts with usage of SoapClient I decided to use pure cURL to perfrom request.
My code:
<?php
header('Content-Type: text/plain; charset=utf-8');
$url = 'https://ip:8443/ServiceName';
$admin = 'login';
$password = 'haShedPassw0rdHere';
$post =
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
// Soap service params xml
</soap:Body>
</soap:Envelope>';
$headers = array(
'Content-type: text/xml;charset="utf-8"',
'Accept: text/xml',
'Cache-Control: no-cache',
'Pragma: no-cache',
'SOAPAction: https://ip:8443/ServiceName',
'Content-length: ' . strlen($post),
);
$curl = curl_init();
$options = array(
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_HTTPAUTH => CURLAUTH_ANY,
CURLOPT_USERPWD => $admin . ':' . $password,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => '',
CURLOPT_AUTOREFERER => true,
CURLOPT_CONNECTTIMEOUT => 120,
CURLOPT_TIMEOUT => 120,
CURLOPT_MAXREDIRS => 10
);
curl_setopt_array($curl, $options);
var_dump($response = curl_exec($curl));
?>
Response:
string(370) "
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
a:InvalidSecurity
</faultcode>
<faultstring xml:lang="ru-RU">
Ошибка при проверке безопасности сообщения.
</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>"
Where:
Ошибка при проверке безопасности сообщения.
Means something like:
Communication security check error.
What have I tried:
POST request with a self-signed certificate
How to consume a WCF Web Service that uses custom username validation with a PHP page?
Php SoapClient stream_context option
SOAP authentication with PHP
How can I send SOAP XML via Curl and PHP?
And more of them.
Question: What am I doing wrong?
Regards.
P.S.: Tested with PHP 5.3, PHP 5.4.14, PHP 5.5.1. Results are same.
UPDv1:
C# Source, provided by service support team:
private void Button_SetData_Click(object sender, EventArgs e)
{
eLeed.WebServiceClient client =
new eLeed.WebServiceClient();
client.ClientCredentials.UserName.UserName = "login";
client.ClientCredentials.UserName.Password = "haShedPassw0rdHere";
Stream input = null;
input = GetQuery("ServiceMethod", TextBox_Command.Text);
XmlDocument response = new XmlDocument();
response.PreserveWhitespace = true;
response.Load(client.SetDataContractor(input));
ExeResponse(response);
input.Close();
client.Close();
}
Well, this button is actually working. But how perform something like that in php with cURL ? Especially, how to pass those two lines:
client.ClientCredentials.UserName.UserName = "login";
client.ClientCredentials.UserName.Password = "haShedPassw0rdHere";
Therefore, shouldn't it return message like "invalid credentials" or something?
The error doesnt seem to be on the client side but on the server side. The server says that some security check failed. If it was a client error, you would get nothing but an error by cURL. You get an XML answer.
You should look at the server side.
Related
I have been trying to generate a Public API key for my USAePay account to use with a USAePay Client JS iFrame using PHP.
The CURL request keeps returning error code 80: Transaction type not allowed from this source.
I have tried with and without a pin and in both test mode using sandbox.usaepay. . . and in regular mode without the sandbox in the URL (changing the SourceKey in the console appropriately).
Is it possible that there is something wrong with my PHP code, or am I missing some other setting?
$seed = "abcdefghijklmnop";
$apikey = "mysourcekeyfromconsole";
$apipin = "1234";
$prehash = $apikey . $seed . $apipin;
$apihash = "s2/" . $seed . "/" . hash("sha256",$prehash);
$authKey = base64_encode($apikey . ':' . $apihash);
//print("Authorization: Basic " . $authKey);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.usaepay.com/api/v2/publickey",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET"
]);
curl_setopt($curl, CURLOPT_HTTPHEADER, [
"Content-Type: application.json",
"Authorization: Basic " . $authKey
]);
$response = curl_exec($curl);
$error = curl_error($curl);
curl_close($curl);
It seems that this does not work from the sandbox, only from "https://usaepay.com/api/v2/publickey". I don't know why it did not work initially when I tried that, unless I changed some other code or setting. Now, though, when I try to change my code to sandbox, it returns an error, and without sandbox, it returns the public key.
For user requeriments the backend must be PHP and the app client is in Ionic 2. Based on:
https://msdn.microsoft.com/en-us/library/azure/dn223265.aspx
https://github.com/Azure/azure-notificationhubs-samples/tree/master/notificationhubs-rest-php
https://github.com/webwarejp/notificationhubs-rest-php
Create Registration Notification Hub Azure PHP Important
I created this method in php API:
$uri = $this->endpoint . $this->hubPath . "/registrations".NotificationHub::API_VERSION;
/* print($uri); */
$ch = curl_init($uri);
$token = $this->generateSasToken($uri);
$headers = [
'Authorization: '. $token,
'Content-Type: '."application/atom+xml;type=entry;charset=utf-8",
'x-ms-version: 2015-01',
'Content-Length: 0'
];
$body = $this->getXmlAndroid($registrationId, $tag);
print_r($body);
curl_setopt_array($ch, array(
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $body
));
$response = curl_exec($ch);
// Check for errors
if($response === FALSE){
print_r(curl_error($ch));
throw new Exception(curl_error($ch));
}
$info = curl_getinfo($ch);
print_r($info);
curl_close($ch);
The getXmlAndroid method is simple return xml format with GCM ID
private function getXmlAndroid($registrationId){
return '<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<GcmRegistrationDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect">
<GcmRegistrationId>'.$registrationId.'</GcmRegistrationId>
</GcmRegistrationDescription>
</content>
</entry>';
}
I get the GcmRegistrationId with this function in Ionic 2 app.
import { Push, PushObject, PushOptions } from '#ionic-native/push';
....
const options: PushOptions = {
android: { senderID: 'MyIDFirebaseProject'},
ios: { alert: 'true', badge: true, sound: 'false'},
windows: {}
};
pushObject.on('registration').subscribe((registration: any) => {
console.log(registration.registrationId);
});
The problem is always request to Registration method in Notification API return
[http_code] => 400
Where 400 means the "Invalid request body. The registration could not be created because the request was malformed.". I don't understand why this happen.
Why you send Content-Length: 0 header? It may cause a problem.
I am trying coinbase api to send and get money and going to use in game,on running below code for sending money getting invalid signature error, not sure where I am wrong. I tried getting account detail, which is working fine and I am able to get account details.
<?php
$API_VERSION = '2016-02-01';
$curl = curl_init();
$timestamp = json_decode(file_get_contents("https://api.coinbase.com/v2/time"), true)["data"]["epoch"];
$req = "/v2/accounts/:account_id/transactions";
$url = "https://api.coinbase.com".$req;
$cle = "xxxxxxx";
$secret = "xxxxxxxx";
$params=['type'=>'send', 'to'=>'xxxxxxxxxx', 'amount'=>0.0001, 'currency'=>'BTC'];
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_USERAGENT, 'local server',
CURLOPT_POSTFIELDS => json_encode($params),
CURLOPT_HTTPHEADER => array(
"CB-VERSION:" . $API_VERSION,
"CB-ACCESS-SIGN:" . hash_hmac('sha256', $timestamp."GET".$req, $secret),
"CB-ACCESS-KEY:" . $cle,
"CB-ACCESS-TIMESTAMP:" . $timestamp,
'Content-Type: application/json'
),
CURLOPT_SSL_VERIFYPEER => false
));
$rep = curl_exec($curl);
curl_close($curl);
print_r($rep);
?>
In the $req URL, you need to replace :account_id with an actual account ID such as 3c04e35e-8e5a-5ff1-9155-00675db4ac02.
Most importantly, since this is a post request, the OAuth signature needs to include the payload (POST data) in the signature.
hash_hmac('sha256', $timestamp."POST".$req.json_encode($params), $secret),
When I encountered this error, it ended up being the account id, which is different for each of your currency accounts. Spent way too much time trying to figure out what was wrong with my signature... Anyways, I'd definitely try that out as GETs worked for me, but every other request type ended up with the invalid signature error.
I'm trying to create registration using REST API NotificationHub AZURE from PHP API Microsoft
¿Anyone know how it's done?
Regards and thanks!
Generally speaking, there are 3 main steps required to access Notification Hubs REST endpoints:
Parse the connection string
Generate the authorization token
Perform the HTTP call
You can refer to https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-php-backend-how-to/ for more detail.
Meanwhile, you can directly use these PHP sample provided by Azure Team in your application, which can implement your requirements easily.
# build uri
$uri = $this->endpoint . $this->hubPath . "/registrations" . NotificationHub::API_NEW_VERSION;
$ch = curl_init();
$token = $this->generateSasToken($uri);
$headers = [
'Authorization: '. $token,
'Content-Type: application/xml',
'x-ms-version: 2015-01'
];
$request_body = self::requestBodyRegistration($device_type, $tagsOrTagExpression, $device_code );
if( is_null( $request_body ) )
{
return null;
}
curl_setopt_array($ch, array(
CURLOPT_URL => $uri,
CURLOPT_POST => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $request_body
));
// Send the request
$response = curl_exec($ch);
// Check for errors
if($response === FALSE){
throw new Exception(curl_error($ch));
}
$info = curl_getinfo($ch);
curl_close($ch);
private function requestBodyRegistration($device_type, $tagsOrTagExpression, $device_code )
{
switch ($device_type) {
case 'apple':
return '<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<AppleRegistrationDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect">
<Tags>'. $tagsOrTagExpression .'</Tags>
<DeviceToken>'. $device_code .'</DeviceToken>
</AppleRegistrationDescription>
</content>
</entry>';
case 'gcm':
return '<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<GcmRegistrationDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect">
<Tags>'. $tagsOrTagExpression .'</Tags>
<GcmRegistrationId>'. $device_code .'</GcmRegistrationId>
</GcmRegistrationDescription>
</content>
</entry>';
default:
return null;
}
}
Does anyone know any PHP library for connecting remote servers that use Digest authentication method with qop=auth-int?
Or, if not, now should I build the A2 for the result? It says in RFC 2617 that I need to use an entity body, but what is this? I am just sending a GET request, it does not have any body at all.
Thanks in advance.
I was looking for the answer to your question too, for requests other than GET.
Perheps you could use something like:
$entityBody = file_get_contents('php://input');
I have not tested if it works, but looking at the answer to this question it would make sence to me that it should.
Note that this stream can only be read once [1] so if you need it again elsewhere you should reuse the $entityBody variable.
From my answer of a similar question:
I implemented the client-side Digest Authentication in PHP with cURL recently. Here's the full code:
<?php
error_reporting(E_ALL);
ini_set( 'display_errors','1');
$url = "https://api.example.com/ws.asmx/do";
$username = "username";
$password = "pwd";
$post_data = array(
'fieldname1' => 'value1',
'fieldname2' => 'value2'
);
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_VERBOSE => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false, // for https
CURLOPT_USERPWD => $username . ":" . $password,
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post_data)
);
$ch = curl_init();
curl_setopt_array( $ch, $options );
try {
$raw_response = curl_exec( $ch );
// validate CURL status
if(curl_errno($ch))
throw new Exception(curl_error($ch), 500);
// validate HTTP status code (user/password credential issues)
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status_code != 200)
throw new Exception("Response with Status Code [" . $status_code . "].", 500);
} catch(Exception $ex) {
if ($ch != null) curl_close($ch);
throw new Exception($ex);
}
if ($ch != null) curl_close($ch);
echo "raw response: " . $raw_response;
?>
If you're doing a GET request, you shouldn't need auth-int. If your service requires it, you can assume an empty entity-body (thus you can just do md5("") for this part of the A2 hash).