PHPSample OAuth connect QBO 401 - php

I am trying to connect to Quickbooks online. I have tried several packages including the PHPSample, the sample code within the v3 SDK, and the java example for time accounting. I end up with a similar problem in each.
I am able to connect to Quickbooks, and retrieve the realmId, oauth token and oauth secret.
In this state, I am able to successfully disconnect.
When I subsequently connect and try to query for data (for example, all accounts) I get a 401 error.
here is the return info (with my keys removed)
ERROR: Invalid auth/bad request (got a 401, expected HTTP/1.1 20X or a redirect)
Response: 401 - message=ApplicationAuthenticationFailed;
errorCode=003200;
statusCode=401
SignatureBaseString: POST
&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F<REALM_ID>%2Fquery&minorversion%3D3%26oauth_consumer_key%3D<CONSUMER_KEY%26oauth_nonce%3D2172856b0bd6c51a491.36540409%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1454423404%26oauth_token%3D<OAUTH_TOKEN>%26oauth_version%3D1.0
array(6) {
["sbs"]=> string(369) "POST&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F<REALM_ID>%2Fquery&minorversion%3D3%26oauth_consumer_key%3DI360v9TvxGoU7UoBYesJFUiRAkVQ8OQfV4Cbl2oN%26oauth_nonce%3D2172856b0bd6c51a491.36540409%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1454423404%26oauth_token%3DqyprdWBRfbyvECJdjDA98qR6G9oPvReu65EuFtFomxS5UPXP%26oauth_version%3D1.0"
["headers_sent"]=> string(532) "POST /v3/company/<REALM_ID>/query?minorversion=3 HTTP/1.1 host: sandbox-quickbooks.api.intuit.com user-agent: V3PHPSDK2.2.0 accept: */* connection: close content-type: application/text Authorization: OAuth oauth_consumer_key="<CONSUMER_KEY>",oauth_signature_method="HMAC-SHA1",oauth_nonce="2172856b0bd6c51a491.36540409",oauth_timestamp="1454423404",oauth_version="1.0",oauth_token="<OAUTH_TOKEN>",oauth_signature="<ALPHA_NUM_STRING>" Content-Length: 53"
["headers_recv"]=> string(147) "HTTP/1.1 401 Unauthorized Server: nginx/1.8.0 Date: Tue, 02 Feb 2016 14:29:35 GMT Content-Type: text/xml Content-Length: 797 Connection: close"
["body_sent"]=> string(53) "select * from Account startPosition 1 maxResults 1000"
["body_recv"]=> string(797) " message=ApplicationAuthenticationFailed; errorCode=003200; statusCode=401 SignatureBaseString: POST&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F<REALM_ID>%2Fquery&minorversion%3D3%26oauth_consumer_key%3D<CONSUMER_KEY>%26oauth_nonce%3D2172856b0bd6c51a491.36540409%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1454423404%26oauth_token%3D<OAUTH_TOKEN>%26oauth_version%3D1.0 "
["info"]=> string(1280) "Adding handle: conn: 0x3a3c70 Adding handle: send: 0 Adding handle: recv: 0 Curl_addHandleToPipeline: length: 1 - Conn 5 (0x3a3c70) send_pipe: 1, recv_pipe: 0 About to connect() to sandbox-quickbooks.api.intuit.com port 443 (#5) Trying 12.149.173.155... Connected to sandbox-quickbooks.api.intuit.com (12.149.173.155) port 443 (#5) SSLv3, TLS handshake, Client hello (1): SSLv3, TLS handshake, Server hello (2): SSLv3, TLS handshake, CERT (11): SSLv3, TLS handshake, Server finished (14): SSLv3, TLS handshake, Client key exchange (16): SSLv3, TLS change cipher, Client hello (1): SSLv3, TLS handshake, Finished (20): SSLv3, TLS change cipher, Client hello (1): SSLv3, TLS handshake, Finished (20): SSL connection using AES256-SHA256 Server certificate: subject: C=US; ST=California; L=San Diego; O=INTUIT INC.; OU=Tech Ops; CN=*.api.intuit.com start date: 2015-11-23 00:00:00 GMT expire date: 2016-11-23 23:59:59 GMT issuer: C=US; O=Symantec Corporation; OU=Symantec Trust Network; CN=Symantec Class 3 Secure Server CA - G4 SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway. upload completely sent off: 53 out of 53 bytes Server nginx/1.8.0 is not blacklisted Closing connection 5 SSLv3, TLS alert, Client hello (1): " }
ERROR MESSAGE: message=ApplicationAuthenticationFailed; errorCode=003200; statusCode=401 SignatureBaseString: POST&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F<REALM_ID>%2Fquery&minorversion%3D3%26oauth_consumer_key%3D<CONSUMER_KEY>%26oauth_nonce%3D2172856b0bd6c51a491.36540409%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1454423404%26oauth_token%3D<OAUTH_TOKEN>%26oauth_version%3D1.0
Note that
<CONSUMER_KEY> matches what is listed in the App page on intuit under OAuth Consumer Key
<OAUTH_TOKEN> matches what is returned from connect to quickbooks as the oauth token
<REALM_ID> matches what is returned from connect to quickbooks as the realm id
<ALPHA_NUM_STRING> is a string of alpha numeric characters (which look like a key string) that I do not recognize as coming from somewhere else.
I am sure I am doing something simple wrongly, but I cannot see it.
Any advice would be greatly appreciated.
Thanks in advance.

Please see the sandbox keys and base url you need to use here-
Please refer-
https://developer.intuit.com/v2/blog/2014/10/20/changes-to-ipp-app-tokens
https://developer.intuit.com/blog/2014/10/24/intuit-developer-now-offers-quickbooks-sandboxes
EDIT:
So if you have used dev app keys/tokens and sandbox url then your oauth should work fine. 401 is tokens expired/invalidated error and can occur in following cases-401 errors occur when users other than the master admin try to login for the realm or wrong email id is used to login.
They can also happen when some other user or the master admin tries to use Connect to Quickbooks button again for the same realm using same tokens if the master admin is deleted in QBO company.
Another reason is when the admin disconnects realm/company manually which invalidates tokens.
401 can also occur when there are outages at our end.
The most obvious reason is 180 days expiry of tokens.
Apart from that service issues at our end can also disconnect tokens/invalidate tokens and give 401 errors at your end.
To regenerate tokens-
If 180 days are not over and days left for token expiry>30 days/180 days over, then email them to Disconnect and Reconnect using Connect to Quickbooks button.
If 180 days are going to be over and days left for token expiry is within 30 days, then your system needs to use Reconnect apis to renew existing tokens.
https://developer.intuit.com/v2/docs/0050_quickbooks_api/0020_authentication_and_authorization/oauth_management_api

Related

issue with Authorize.net api call started returning null

A very strange thing happened. Our app stopped connecting to auth.net. We had made no code changes. At some point last night the transactions stopped. We have been trying to figure out why. THis is what we have.
The API call is supposed to always return something liken en error but it is returning NULL. We have run a ton of test and still have issues
$ch = curl_init('https://apitest.authorize.net/xml/v1/request.api');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
$data = curl_exec($ch);
curl_close($ch);
this returns the following
Trying 198.241.207.86...
TCP_NODELAY set
Connected to apitest.authorize.net (198.241.207.86) port 443 (#0)
ALPN, offering http/1.1
successfully set certificate verify locations:
CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs
SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
ALPN, server accepted to use http/1.1
Server certificate:
subject: C=US; ST=Georgia; L=Suwanee; O=MIS Solutions, Inc.; OU=Cloud; CN=*.greenlightcloud.net
start date: Jun 8 00:00:00 2020 GMT
expire date: Jul 8 12:00:00 2022 GMT
subjectAltName does not match apitest.authorize.net
SSL: no alternative certificate subject name matches target host name 'apitest.authorize.net'
stopped the pause stream!
Closing connection 0
We reinstalled the sdk via composer. We also updated the SSL cert manually from git and no change.
We tried the sample code from git and we get the "Charge Credit Card Null response returned" which means the call is returning null.
Any help would be great.
Check your firewall. We found that the IP for Authorize.net went from a server in US to Singapore overnight and is now blocked on our firewall.

PHP CURL "NSS: client certificate not found (nickname not specified)" Issue

Request to a single specific https endpoint fails on one of my servers with "NSS: client certificate not found (nickname not specified)" error from PHP CURL.
When I ran the same query from the command line with verbose option I got the same error, but after that I also got a valid response (after the error in the same CURL request).
Then I've enabled verbose option for my PHP CURL request and displayed it for testing like this:
$error = curl_error($curl);
if ($error) {
echo "cURL Error #:" . $error;
rewind($verbose);
$verboseLog = htmlspecialchars(stream_get_contents($verbose));
echo "<pre>";
print_r($verboseLog);
} else {
echo $response;
}
And got this as output:
cURL Error #:NSS: client certificate not found (nickname not specified)
* About to connect() to <address> port 8001 (#0)
* Trying <ip>... * connected
* Connected to <address> (<ip>) port 8001 (#0)
* skipping SSL peer certificate verification
* NSS: client certificate not found (nickname not specified)
* SSL connection using TLS_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=*.<address>m,O=XXX A.S.,OU=IT,L=Umraniye,ST=Istanbul,C=TR
* start date: Jun 11 12:52:03 2015 GMT
* expire date: Jun 09 14:16:13 2018 GMT
* common name: *.<address>
* issuer: CN=GlobalSign Organization Validation CA - SHA256 - G2,O=GlobalSign nv-sa,C=BE
> POST /<url_part> HTTP/1.1
Host: <address>:8001
Accept: */*
Accept-Encoding: deflate, gzip
authorization: Basic UlBlahBlahnJrcjEyMzQ1Ng==
cache-control: no-cache
content-type: application/json
postman-token: eeefe018-7cac-1706-7b6d-847800a7ad0f
Content-Length: 333
< HTTP/1.1 200 OK
< set-cookie: sap-usercontext=sap-client=100; path=/
< set-cookie: SAP_SESSIONID_CFP_100=ohZvfO5ZOwq_LTE76Zgz9L-C0NdhlRHngM0AF6R3IFY%3d; path=/
< content-type: application/json; charset=utf-8
< content-length: 1150
< cache-control: max-age=0
< sap-cache-control: +180
< sap-isc-uagent: 0
<
* Connection #0 to host <address> left intact
* Closing connection #0
So, CURL request finished with the error, but in verbose log we see that after the error valid response was also fetched.
Here's my questions:
Is there any way to overcome this NSS issue as long as other different https endpoints work completely fine? Is it connected with endpoint's server configuration and can be resolved there?
If the first item fails, is it possible not to throw CURL NSS error, but get the response instead? CURLOPT_FAILONERROR option does not help.
CURL was built with NSS:
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz
Update:
The second item can be closed, because this error is really strange: curl_error returns the error, but curl_exec returns valid response at the same time.
Try giving a absolute path to the certificate and add a "./" prefix. For example "./path-to-your-cert"

Connect to site with unknown scheme via Guzzle

I have a list of URL without scheme specified, ex.:
github.com (works only with https);
what.ever (works only with http);
google.com (supports both schemes).
I need to get contents of its' root path (/) using Guzzle (v6), but I do not know their scheme: http or https.
Can I solve my task without making 2 requests?
Guzzle will follow redirects by default, so unless you have an explicit list of URL's that are https then I would prepend http if missing and allow the website to redirect if it only accepts https requests (which is what they should do).
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$response = (new Client)->get('http://github.com/', ['debug' => true]);
Response:
> GET / HTTP/1.1
Host: github.com
User-Agent: GuzzleHttp/6.2.1 curl/7.51.0 PHP/5.6.30
< HTTP/1.1 301 Moved Permanently
< Content-length: 0
< Location: https://github.com/
< Connection: close
<
* Curl_http_done: called premature == 0
* Closing connection 0
* Trying 192.30.253.112...
* TCP_NODELAY set
* Connected to github.com (192.30.253.112) port 443 (#1)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: github.com
* Server certificate: DigiCert SHA2 Extended Validation Server CA
* Server certificate: DigiCert High Assurance EV Root CA
> GET / HTTP/1.1
Host: github.com
User-Agent: GuzzleHttp/6.2.1 curl/7.51.0 PHP/5.6.30
< HTTP/1.1 200 OK
< Server: GitHub.com
< Date: Wed, 31 May 2017 15:46:59 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Status: 200 OK
Generally — no, you cannot solve the problem without two requests (because one there might be no redirect).
You can do 2 async requests with Guzzle, then you will spend probably the same time, but with a proper general solution.
Just create two requests and wait for both:
$httpResponsePromise = $client->getAsync('http://' . $url);
$httpsResponsePromise = $client->getAsync('https://' . $url);
list($httpResponse, $httpsResponse) = \GuzzleHttp\Promise\all(
[$httpResponsePromise, $httpsResponsePromise]
);
That's all, now you have two responses (for each protocol) and you make them in parallel.

"Invalid API request" when using CURL_EXEC

i have the following php code that calls an API:
$forcetest = 1;
$url = "https://www.website.com/api/pointTotal.php?userId=" . $userId;
if ($forcetest || (isset($_SERVER['ON_TEST_SERVER']) && ($_SERVER['ON_TEST_SERVER']))){
$url = "https://wwwtest.website.com/api/pointTotal.php?userId=" . $userId;
}
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url
));
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'sharedSecret: abc123',
));
//curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //tested to see if this would work, didn't seem to matter
// Only do this if on dev/test
if ($forcetest || (isset($_SERVER['ON_TEST_SERVER']) && ($_SERVER['ON_TEST_SERVER']))) {
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
}
$response = curl_exec($curl);
print($response);
if(!$response){
die('Error: "' . curl_error($curl) . '" - Code: ' . curl_errno($curl));
}
my problem is when going to production (i.e. $forcetest = 0;) it works just fine, calling the prod api and using the prod database. if i switch it, and it goes to the wwwtest subdomain to call the test api, i get the error returned
{"success":false,"errors":["Invalid API request"]}
"invalid api request" isn't something in the api's code, so it seems to me that its something curl_exec is doing/erroring on but i can't figure out what. if i go to the api's directly, they both return the correct information in my browser, so i know it's up and working. is it maybe a cert issue or some sort of xss setting on that subdomain/server that's causing it to error? i'm kind of at a loss.
Thanks in advance.
edit: CLI curl command and header output:
[josh#mac] $ curl -H 'sharedSecret: abc123' 'https://wwwtest.website.com/api/pointTotal.php?userId=1472&rewardsType=f' -vvv
* About to connect() to wwwtest.website.com port 443
* Trying xxx.xx.xx.xx... connected
* Connected to wwwtest.website.com (xxx.xx.xx.xx) port 443
* successfully set certificate verify locations:
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSLv2, Client hello (1):
SSLv3, TLS handshake, Server hello (2):
SSLv3, TLS handshake, CERT (11):
SSLv3, TLS handshake, Server finished (14):
SSLv3, TLS handshake, Client key exchange (16):
SSLv3, TLS change cipher, Client hello (1):
SSLv3, TLS handshake, Finished (20):
SSLv3, TLS change cipher, Client hello (1):
SSLv3, TLS handshake, Finished (20):
SSL connection using RC4-SHA
* Server certificate:
* subject: /C=US/ST=New Mexico/L=Albuquerque/O=removed/CN=*.website.com
* start date: 2013-07-29 00:00:00 GMT
* expire date: 2016-10-05 12:00:00 GMT
* subjectAltName: wwwtest.website.com matched
* issuer: /C=US/O=DigiCert Inc/CN=DigiCert Secure Server CA
* SSL certificate verify ok.
> GET /api/pointTotal.php?userId=1472&rewardsType=f HTTP/1.1
> User-Agent: curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
> Host: wwwtest.website.com
> Accept: */*
> sharedSecret: abc123
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Jun 2016 18:27:25 GMT
< Server: Apache/2.2.3 (CentOS) DAV/2 mod_ssl/2.2.3 OpenSSL/0.9.8e-fips-rhel5
< Access-Control-Request-Headers: accept, auth-key
< Access-Control-Allow-Origin: https://customeraccess.website.com
< Access-Control-Allow-Headers: sharedSecret
< Content-Length: 36
< Content-Type: text/html
Connection #0 to host wwwtest.website.com left intact
* Closing connection #0
* SSLv3, TLS alert, Client hello (1):
{"userId":"1472","pointTotal":50600}
also added this to the php code making the call
curl_getinfo($curl, CURLINFO_HEADER_OUT) and it prints out a 404 which is what seems to be the problem but going to the url it's curl'ing immediatley returns the correct result so i'm not sure what's causing the 404
Sorry, just now saw this question was still open. The problem turned out to be bad internal DNS. the code and the curl we're all correct, i had to rely on the sys admin's to resolve it.

New APNS Provider API and PHP

I started creating some code based upon this for sending push notifications from PHP.
However now that I have understood there is a new API which utilizes HTTP/2 and provides feedback in the response, I am trying to figure out what I need to do to get that feedback.
I haven't been able to find any tutorials or sample code to give me direction (I guess because it is so new).
Is it possible to use the stream_socket_client() method of connecting to APNS with the new provider API? How do I get the feedback? All I get back from fwrite($fp, $msg, strlen($msg)) right now is a number. For all intents and purposes, you can consider my code the same as the code from the SO question I based my code on
Thanks!
With the new HTTP/2 APNS provider API, you can use curl to send push notifications.
EDIT
Before proceeding (as noted by #Madox), openssl >= 1.0.2e of should be installed (from package preferably). Verify with the command
openssl version
a) Your version of PHP should be >= 5.5.24 so that the constant CURL_HTTP_VERSION_2_0 is defined.
b) Make sure that you have curl version 7.46+ installed in your system with
curl --version
c) Curl should have http/2 support enabled. In the output when typing the previous command, you should see a line like this one:
Features: IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets
if HTTP2 doesn't show up, you can follow this excellent tutorial to install http/2 for curl https://serversforhackers.com/video/curl-with-http2-support
Verify that curl detected openssl >= 1.0.2e, doing curl --version should output something like this:
curl 7.47.1 (x86_64-pc-linux-gnu) libcurl/7.47.1 OpenSSL/1.0.2f zlib/1.2.8 libidn/1.28 nghttp2/1.8.0-DEV librtmp/2.3
e) Once you everything installed, you can test it in the command line:
curl -d '{"aps":{"alert":"hi","sound":"default"}}' \
--cert <your-certificate.pem>:<certificate-password> \
-H "apns-topic: <your-app-bundle-id>" \
--http2 \
https://api.development.push.apple.com/3/device/<device-token>
f) Here is a sample code in PHP that I have successfully tried:
if(defined('CURL_HTTP_VERSION_2_0')){
$device_token = '...';
$pem_file = 'path to your pem file';
$pem_secret = 'your pem secret';
$apns_topic = 'your apns topic. Can be your app bundle ID';
$sample_alert = '{"aps":{"alert":"hi","sound":"default"}}';
$url = "https://api.development.push.apple.com/3/device/$device_token";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $sample_alert);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apns-topic: $apns_topic"));
curl_setopt($ch, CURLOPT_SSLCERT, $pem_file);
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $pem_secret);
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//On successful response you should get true in the response and a status code of 200
//A list of responses and status codes is available at
//https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW1
var_dump($response);
var_dump($httpcode);
}
I want to add some information to tiempor3al answer.
1) curl must be compiled with openssl version >=1.0.2 to fully support http/2. I receive "?##?HTTP/2 client preface string missing or corrupt..." error when I compiled it with CentOS stock openssl-1.0.1e.
2) if your version of php module mod_curl.so compiled without CURL_HTTP_VERSION_2_0 constant, you could replace it with integer number 3:
curl_setopt($ch, CURLOPT_HTTP_VERSION, 3);
I could successfully send push via HTTP2 using php CURL and read the feedback directly in the response body (here I wrote a short tutorial on how to do this: Sending Push Notification with HTTP2 (and PHP)).
I think that you can check the response body reading from the socket (I don't remember exactly the php function, perhaps "fgets").
I'm using CentOS 6 and the way to solve was to install from source cURL and OpenSSL.
It may look very simple but it took me 3 days to figure out the right configuration for the packages so I think I can help someone by posting what I did here.
It proved a little tricky for me since I'm not used to install packages from source, but I now can connect to APNs using HTTPS over HTTP/2.
The details of what I did is here:
Download and uncompress cURL and OpenSSL:
wget https://curl.haxx.se/download/curl-7.47.1.tar.gz
wget https://www.openssl.org/source/openssl-1.0.2h.tar.gz
Configure OpenSSL with the following flags (I'm not sure what they do, but is what worked for me):
export CXXFLAGS="$CXXFLAGS -fPIC"
./config zlib enable-ssl3 enable-shared
make and install OpenSSL
Configure cURL with the following flag:
./configure --with-ssl=/usr/local/ssl/
Make and install cURL
set LD_LIBRARY_PATH to /usr/local/ssl/lib/
export LD_LIBRARY_PATH=/usr/local/ssl/lib/
Test
/usr/local/bin/curl -v -d '{"aps":{"alert":"hi","sound":"default"}}' --cert cert.crt --key cert.key -H "apns-topic: topics" --http2 https://api.development.push.apple.com:443/3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
The result:
* Trying 17.172.238.203...
* Connected to api.development.push.apple.com (17.172.238.203) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=api.development.push.apple.com; OU=management:idms.group.533599; O=Apple Inc.; ST=California; C=US
* start date: Jun 19 01:49:43 2015 GMT
* expire date: Jul 18 01:49:43 2017 GMT
* subjectAltName: host "api.development.push.apple.com" matched cert's "api.development.push.apple.com"
* issuer: CN=Apple IST CA 2 - G1; OU=Certification Authority; O=Apple Inc.; C=US
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* TCP_NODELAY set
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x1091110)
> POST /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0 HTTP/1.1
> Host: api.development.push.apple.com
> User-Agent: curl/7.48.0
> Accept: */*
> apns-topic: topics
> Content-Length: 40
> Content-Type: application/x-www-form-urlencoded
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* We are completely uploaded and fine
< HTTP/2.0 400
<
* Connection #0 to host api.development.push.apple.com left intact
{"reason":"BadDeviceToken"}
As you can see, I got rid of the ugly
▒##▒HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 504f5354202f332f6465766963652f746573742048545450
Follow this guide [http://cloudfields.net/blog/ios-push-notifications-encryption/][1] to generate and merge your certificate and private key.
Once you merge and your sslcert and pkey as described in the guide with same file names, just try the curl command below.
curl -X POST -H 'apns-topic: com.mycompany.ios.BadassApp' -d '{"aps":{"content-available":1,"alert":"hi","sound":"default"}}' --cert apns_cert.pem:yourCertPassword --http2 'https://api.development.push.apple.com:443/3/device/b8de1sf067effefc398d792205146fc67dn0e96b0ff21ds81cabe384bbe71353'
To resolve HTTP/2 client preface string missing or corrupt errors in PHP 5.6 I created an Apache and CLI PHP Docker image that you might want to rely on or just look up what I did in the Dockerfile to build your own. Same can probably apply to PHP 7.0 although I haven't tried.
yes, it's possible:
$errno=0;$errstr="";
$sock = stream_socket_client(
"api.push.apple.com:443",
$errno,
$errstr,
4,
STREAM_CLIENT_CONNECT,
stream_context_create(["ssl" => ["local_cert" => "/path/to/cert.pem","verify_peer"=>false,"verify_peer_name"=>false]])
);
stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);

Categories