SSL connection through proxy server - php

I'm trying to connect to the Twitter api server to make an "Application-only Autentication".
I don't care any other way to connect to Twitter. I need this specific method.
I need to go from localhost through my corporation's proxy to api.twitter.com which needs ssl
Following the instruction of this twitter developer's page https://dev.twitter.com/docs/auth/application-only-auth, i tried with:
cUrl:
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if ($this->proxy != '') {
curl_setopt($ch, CURLOPT_PROXY, $this->proxy);
curl_setopt($ch, CURLOPT_PROXYPORT, $this->port);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->userpwd);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSLVERSION, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
"));
$response = curl_exec($ch);
if (FALSE === $response) throw new Exception(curl_error($ch), curl_errno($ch));
curl_close($ch);
var_dump(json_decode($response));
}
catch(Exception $e) {
trigger_error(sprintf('Curl failed with error #%d: %s', $e->getCode(), $e->getMessage()), E_USER_ERROR);
}
Which gives me
Fatal error: Curl failed with error #35: Unknown SSL protocol error in connection to api.twitter.com
file_get_contents:
$context = stream_context_create(array(
"http" => array(
"method"=>"CONNECT",
"proxy" => $this->proxy.":".$this->port,
"request_fulluri" => true,
"header" => "
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Proxy-Authorization: Basic ".base64_encode(urlencode($this->userpwd))."
Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
",
),
));
$response = file_get_contents($url, False, $context);
var_dump(json_decode($response));
Which gives me
Warning: file_get_contents(https://api.twitter.com/oauth2/token) [function.file-get-contents]: failed to open stream: Cannot connect to HTTPS server through proxy
fsockopen:
$fp = fsockopen($this->proxy, $this->port);
fputs($fp, "
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
");
$data="";
while (!feof($fp)) $data .= fgets($fp,1024);
fclose($fp);
var_dump($data);
Which gives me
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Proxy-Connection: close
Connection: close
Content-Length: 727
I am sure that the 443 port is open and it's not a problem of the localhost (I got the same error trying on an online server).
I tried even using CONNECT method instead of POST.
I tried tunneling the proxy, but I'm neither sure I made it nor that that's the problem.
I'm running out ideas..

Try to remove this:
curl_setopt($ch, CURLOPT_SSLVERSION, 3);
You only have one value in this array, it's wrong.
curl_setopt($ch, CURLOPT_HTTPHEADER, array("
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
"));
Change the above for this:
$consumer_key = base64_encode(urlencode($consumer_key);
$consumer_secret = urlencode($consumer_secret);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Host: api.twitter.com",
"User-Agent: My Twitter App v1.0.23",
"Authorization: Basic $consumer_key:$consumer_secret",
"Content-Type: application/x-www-form-urlencoded;charset=UTF-8",
"Accept-Encoding: gzip",
"grant_type=client_credentials"
));
if you want to include the Content-Length: xx, you need to use strlen() to get string length of the post, ex;
$length = strlen($post_content);
Then add it to the CURLOPT_HTTPHEADER array:
"Content-Length: $length"

Found the problem. There's no need (maybe only in this case, i'm not sure) to base64 encode the credentials. They'll be encoded by the server.
I don't know the reason of that different error responses, but was in fact a problem of double encoding, because of which the server was not able to verify my credentials.

Related

Forbidden to Call method on Dynamics 365 AX via PHP Curl

I am trying to call methods from dynamics SOAP through WSDL via PHP curl.
I get this error from both my webapp and SOAPUI.
What could be the problem? It works fine when accessed from a .NET testing program with same credentials. Just facing problems from PHP side saying Forbidden with 1317 code. The specified account does not exist
I've been trying to call the method and faced different issues last issue I faced is this one.
I thought maybe user agent I changed it I used SOAPUI. same thing.
What I know is the user is registered in Azure AD and should have authorization for the app.
The POST is
POST /soap/services/servicemethodname?wsdl
HTTP/1.1
Host: domainname.sandbox.ax.dynamics.com
Accept: text/xml
Accept-Encoding: gzip,deflate
Connection: Keep-Alive
Content-type: text/xml
User-Agent: Apache-HttpClient
Authorization: Bearer longTokenString
Soapaction: "http://tempuri.org/webservice/method"
Content-Length: 795
The Response is
HTTP/1.1 500 Internal Server Error Cache-Control: private
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=31536000; includeSubDomains
Set-Cookie: ASP.NET_SessionId=hghtgkuhlihkjg; path=/; secure;
HttpOnly Set-Cookie:
ms-dyn-csrftoken= someTokenSTring; path=/; secure
ms-dyn-fqhn:
ms-dyn-namespace: namespace
ms-dyn-tenant: tenantidstring
ms-dyn-role:
ms-dyn-aid: aidString
X-Powered-By: ASP.NET
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
p3p: CP="No P3P policy defined. Read the Microsoft privacy statement at https://go.microsoft.com/fwlink/?LinkId=271135"
Strict-Transport-Security: max-age=31536000;
includeSubDomains Date: Thu, 01 Aug 2019 19:24:52 GMT Content-Length: 1112
a:ForbiddenForbidden1317System.ComponentModel.Win32ExceptionThe specified account does not exist0-2147467259
I need to be able to call the method without errors and get the values it sends.
My php code
$requestBody = trim('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dat="http://schemas.microsoft.com/dynamics/2013/01/datacontracts" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tem="http://tempuri.org">
<soapenv:Header>
<dat:CallContext>
<dat:Company>company</dat:Company>
<dat:Language>en-us</dat:Language>
<dat:MessageId>?</dat:MessageId>
<dat:PartitionKey>12345667</dat:PartitionKey>
</dat:CallContext>
</soapenv:Header>
<soapenv:Body>
<m:getMethod xmlns:m="http://tempuri.org/webService/getMethod">
<m:parameterName soap:mustUnderstand="1">12345</m:parameterName>
</m:getMethod>
</soapenv:Body>
</soapenv:Envelope>
');
$soapAction = 'SOAPAction: http://tempuri.org/webService/getMethod';
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER,
array( 'Accept:text/xml',
'Accept-Encoding: gzip,deflate',
'Connection: Keep-Alive',
'Content-type: text/xml; charset=utf-8',
'Cache-Control: no-cache',
'Pragma: no-cache',
'Authorization: Bearer longstringToken',
'SOAPAction: http://tempuri.org/webService/getMethod'
));
if ($postData != '') {
curl_setopt($ch, CURLOPT_POSTFIELDS,$postData);
}
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
// By default https does not work for CURL.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt ($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
// Set the option to recieve the response back as string.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$odataURL = 'https://domainname.sandbox.ax.dynamics.com/soap/services/webService';
curl_setopt($ch, CURLOPT_URL, $odataURL);
// enable string response
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);
// Mark as Post request
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
// $output contains the output string
$output = curl_exec($ch);
Ok so finally found a solution.
It helps to read documentations on the classes you use and different systems used. In my case i was trying to integrate my app with microsoft dynamics 365 ax, so i had to read up on that too.
I read a lot of documents some were related to different dynamics service but this one helped most
And since the soap service needed Authorization Header, because they were using Windows authentication, we needed to get the token from oAuth link.
https://login.windows.net/$tenantDomainName/oauth2/token
PS: the oauth2 link i knew about it from github PHPConsoleApplication
I used PHP CURL to get my authorization Token and then created a client using PHP's SoapClient Class.
Make sure you add the authorization token in the header like so:
$arrayOpt = array(
'stream_context' => stream_context_create(
array('http' =>'Authorization: Bearer tokenString')
));
$client = new SoapClient($wsdl, $arrayOpt);
$response = $client->serviceMethod($parameters);
var_dump($response);
And you will get the values of the method.

Curl php request error

I'm trying to set up an API call through php using cURL. The API documentation gives an example for a call to this API from Java:
HttpResponse<JsonNode> response = Unirest.get("https://api2445582011268.apicast.io/games/1942?fields=*")
.header("user-key", "*******")
.header("Accept", "application/json")
.asJson();
This is my attempt at converting it to a cURL call in php:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api2445582011268.apicast.io/games/1942?fields=*");
curl_setopt($ch, CURLOPT_HEADER, array(
"user-key: *******",
"Accept: application/json"
));
$output = curl_exec($ch);
echo $output;
curl_close($ch);
However my php is echoing the following output:
HTTP/1.1 403 Forbidden Content-Type: text/plain; charset=us-ascii Date: Sat, 02 Sep 2017 02:52:40 GMT Server: openresty/1.9.15.1 Content-Length: 33 Connection: keep-alive Authentication parameters missing1
Does anyone know how to solve this?
You used CURLOPT_HEADER (which is a Boolean to indicate you want the headers in the output), but you need CURLOPT_HTTPHEADER (which is used to pass an array with the headers for the request):
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"user-key: *******",
"Accept: application/json"
));

Keep getting 400 error with cURL on localhost

I've been scouring around trying to understand curl and building headers but it seems no matter what I do I get the following error :
HTTP/1.1 400 Bad Request Date: Tue, 12 Apr 2016 18:15:33 GMT Server: Apache/2.2.29 (Unix) mod_wsgi/3.5 Python/2.7.10 PHP/5.6.10 mod_ssl/2.2.29 OpenSSL/0.9.8zh DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.22.0 Content-Length: 226 Connection: close Content-Type: text/html; charset=iso-8859-1
Bad Request
Your browser sent a request that this server could not understand.
The following is the function that I am using to send post variables and fetch the contents via curl. Both the file doing the fetching and the file whose contents are fetched are being hosted locally on MAMP
$url = "./lib/otherpage.php";
$data = array("url"=>$_POST["url"],"format"=>"json");
function tryCurl($baseurl,$data)
{
$bodydata = array(json_encode($data));
$bodystr = http_build_query($bodydata);
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL,$baseurl);
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$bodystr);
curl_setopt($ch, CURLOPT_PORT,8888);
curl_setopt($ch, CURLOPT_HEADER,1);
curl_setopt($ch, CURLOPT_HTTPHEADER,array(
"POST / HTTP/1.0",
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: ".strlen($bodystr),
"Host: localhost:8888/gt_dev/",
"User-Agent: My-User-Agent 1.0",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Cache-Control: no-cache",
"Accept-Language: en;q=0.7,en-us;q=0.3",
"Connection: close",
));
// Execute
$result=curl_exec($ch);
// Printing any errors..
echo curl_error($ch);
curl_close($ch);
return $result;
}
Ultimately, the request should send two post variables ("url" and "format") to the receiving file, and expect a json string in return.
This isn't so much an answer to the original issue but turns out I was thinking about my problem the wrong way.
I wanted to use page A as a proxy to page B. And to pass the same variables page B expected from Page A.
Turns out the same effect can be achieved by simply including page B, not curling the expected parameters to it. So the answer is just
include("./lib/otherpage.php");

cURL response body missing (data not shown)

I'm working with a specific restful API on CakePHP 2.4.x, part of the API includes sending files via curl POST/PUT and we've been unable to replicate what we need in CakePHP's HttpSocket so opted for traditional curl. The attempts to use PHP's curl commands would output nothing at all (despite pauses to show they were running).
Setting up a shell_exec will output information but unfortunately we are not getting the response body which is important to save data or view specific error messages.
I'm adding everything I think is relevant to this issue (I am on OSX, local environment XAMPP). My cURL version prints:
curl 7.30.0 (x86_64-apple-darwin13.0) libcurl/7.30.0 SecureTransport zlib/1.2.5
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IPv6 Largefile NTLM NTLM_WB SSL libz
Deprecated PHP Code (This prints string(0) "" )
$ch = curl_init();
curl_setopt ($ch, CURLOPT_HTTPHEADER, Array(
"Authorization: Bearer {$authInfo->access_token}",
'Accept: application/json'
));
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
$post[$data['file']['name']] = '#' . $data['file']['location'];
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_URL, $url);
$response = curl_exec($ch);
pr($post); // print_r wrapper
pr(curl_getinfo($ch));
var_dump($response);
curl_close($ch);
Shell Exec Code
This code works fine in actually doing what we want with the API, the only issue is we're not getting the response body.
$command = Configure::read('DM.CurlBinary') . ' -sb -k -v -X POST ';
$command .= $url . ' -F "' . $data['file']['name'] . '=#' . $data['file']['location'] . '"';
$command .= ' -H "AUTHORIZATION: Bearer ' . $authInfo->access_token . '"';
$command .= ' -H "ACCEPT: application/json" -H "EXPECT: 100-continue"';
$output = shell_exec($command);
pr($output); // print_r wrapper
pr($command);
Actual CURL Command
curl -sb -k -v -X POST https://idolcamp.idol.io/api/v1/tracks/857707/records -F "record[new_file]=#/Users/someuser/Documents/Development/DittoCake/app/tmp/Idol_857707.flac" -H "AUTHORIZATION: Bearer speacialtokengoeshere" -H "ACCEPT: application/json" -H "EXPECT: 100-continue"
Response
This shows as an 422 error because the file I am uploading already exists, I'd check it by its id but we have no response in order to get the id and check if it exists next time around.
Adding handle: conn: 0x7f8e3c004000
Adding handle: send: 0
Adding handle: recv: 0
Curl_addHandleToPipeline: length: 1
- Conn 0 (0x7f8e3c004000) send_pipe: 1, recv_pipe: 0
About to connect() to idolcamp.idol.io port 443 (#0)
Trying 212.83.129.122...
Connected to idolcamp.idol.io (212.83.129.122) port 443 (#0)
TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Server certificate: *.idol.io
Server certificate: Gandi Standard SSL CA
Server certificate: UTN-USERFirst-Hardware
POST /api/v1/tracks/857707/records HTTP/1.1
User-Agent: curl/7.30.0
Host: idolcamp.idol.io
AUTHORIZATION: Bearer somespecialtoken
ACCEPT: application/json
EXPECT: 100-continue
Content-Length: 29600116
Content-Type: multipart/form-data; boundary=----------------------------3bd64d03cd9b
HTTP/1.1 100 Continue
} [data not shown]
HTTP/1.1 422 Unprocessable Entity
Server nginx is not blacklisted
Server: nginx
Date: Tue, 25 Aug 2015 15:08:00 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: keep-alive
X-Request-Id: 3803269a-18ea-4558-8623-08810a058030
X-Runtime: 1.112917
HTTP error before end of send, stop sending
Closing connection 0
API Doc: Request
API Doc: Response

cURL works via command line but not in PHP Curl

The following command works perfect in the command line:
c:\>curl -v -H "Content-Type: text/xml" -d "<?xml version='1.0' encoding='utf-8'?><methodCall><methodName>create_account</methodName><params><param><value><struct><member><name>user</name><value><string>test</string></value></member><member><name>server</name><value><string>chat3.activengage.com</string></value></member><member><name>password</name><value><string>test</string></value></member></struct></value></param></params></methodCall>" http://localhost:4561
* About to connect() to localhost port 4561 (#0)
* Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 4561 (#0)
> POST / HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost:4561
> Accept: */*
> Content-Type: text/xml
> Content-Length: 428
>
* upload completely sent off: 428 out of 428 bytes
< HTTP/1.1 200 OK
< Content-Length: 113
< Server: Erlang/Process-One
< Connection: close
<
<?xml version="1.0"?><methodResponse><params><param><value><int>0</int></value><
/param></params></methodResponse>* Closing connection #0
And in PHP using the code below:
public /*string*/ function registerUser(/*string*/$user,/*string*/$pass){
$xml = "<?xml version='1.0' encoding='utf-8'?><methodCall><methodName>create_account</methodName><params><param><value><struct><member><name>user</name><value><string>test2</string></value></member><member><name>server</name><value><string>chat3.activengage.com</string></value></member><member><name>password</name><value><string>test</string></value></member></struct></value></param></params></methodCall>";
$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, 'http://127.0.0.1:4561');
curl_setopt($handle, CURLOPT_VERBOSE, 1);
curl_setopt($handle, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($handle, CURLOPT_POST, 1);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($handle, CURLOPT_POSTFIELDS, $xml);
$content = curl_exec($handle);
echo $xml;
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
print_r($httpCode);
print_r($content);
if(curl_errno($handle))
{
echo 'error:' . curl_error($handle);
}
curl_close($handle);
}
The result is a HTTP Status code 400. Is there something I'm doing wrong?
UPDATE - The result of CURLINFO_HEADER_OUT
string(99) "POST / HTTP/1.1
Host: localhost:4561
Accept: */*
Content-Type: text/xml
Content-Length: 400
"
Running a curl request from my browser based PHP script failed after I broke my etc/resolv.conf file.
I discovered this after visiting
php5-curl error: couldn't resolve host
After fixing the resolve.conf file as follows:
(note: 192.168.1.1 is my router address)
# Generated by NetworkManager
nameserver 192.168.1.1
Curl behaved as expected.
I Hope it helps you

Categories