How to connect to API using PHP with a PFX file and password?
Asked Answered
P

3

7

I need to connect to a company API using a PFX file and password using oauth2.

I'm not very familiar with using PFX files and not sure how to connect to an API using a PFX file and password. I looked here at SO but didn't find much to help me get started. I searched google, but found a few documents and sample code, none of which worked. I found the following code, but it isn't working for me. Can someone please help me get this working?

Code I've found and am currently trying to use is as follows:

<?php

$url = "https://myaccounts.domain.com/auth/oauth/v2/token";
$cert_file = 'my_auth.pfx';
$cert_password = '1234567890';

$ch = curl_init();

$options = array( 
    CURLOPT_RETURNTRANSFER => true,

    //CURLOPT_HEADER         => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_SSL_VERIFYPEER => false,

    CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)',

    //CURLOPT_VERBOSE        => true,
    CURLOPT_URL => $url ,
    CURLOPT_SSLCERT => $cert_file ,
    CURLOPT_SSLCERTPASSWD => $cert_password ,
);

curl_setopt_array($ch , $options);

$output = curl_exec($ch);

if(!$output)
{
    echo "Curl Error : " . curl_error($ch);
}
else
{
    echo htmlentities($output);
}
?>

The above code gives me the following error:

Curl Error: could not load PEM client certificate, OpenSSL error error:02001002:system library:fopen:No such file or directory, (no key found, wrong pass phrase, or wrong file format?) 

The key is in the same directory, so I'm not sure why it isn't finding it. Perhaps I'm approaching the use of a PFX file wrong.

Pforzheim answered 2/2, 2017 at 15:26 Comment(0)
P
8

I was approaching this all wrong. From what I've read and the information I've gathered, it's best to convert the PFX file to a PEM file. I did this using cygwin with all the necessary packages and openssl. Once the PFX file was converted to PEM, I then used a curl command with necessary credentials to connect to the API I need to pull data from. The command I ran from a bash shell is the following:

curl -i -XPOST -u username:password -k https://myaccounts.domain.com/auth/oauth/v2/token -v --cert my_auth.pem

I received the following response:

* timeout on name lookup is not supported
*   Trying 123.123.123.123...
* TCP_NODELAY set
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to myaccounts.domain.com (123.123.123.123) port 111 (#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: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [87 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [3880 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [333 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [903 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [1291 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [70 bytes data]
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
} [264 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
{ [1 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=My Location; L=ThankYou; O=Automatic Data Processing, Inc.; OU=Testing Labs; CN=myaccounts.domain.com
*  start date: Aug  4 00:00:00 2001 GMT
*  expire date: Oct 23 01:01:01 2017 GMT
*  issuer: C=US; O=My Corporation; OU=My Trust Network; CN=My Class 3 Secure Server CA - G4
*  SSL certificate verify ok.
* Server auth using Basic with user '123456'
} [5 bytes data]
> POST /auth/oauth/v2/token HTTP/1.1
> Host: myaccounts.domain.com
> Authorization: Basic veryveryveryveryverylongstringthatwillgoherebecauseitisveryverylong==
> User-Agent: curl/6.12.0
> Accept: */*
>
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0{ [5 bytes data]
< HTTP/1.1 200 OK
< MY-CorrelationID: 123456789-adda-1234-a123-1a12345abcde
< Pragma: no-cache
< Cache-Control: no-store, no-cache, private
< Content-Type: application/json;charset=UTF-8
< Content-Length: 127
< Date: Thu, 02 Feb 2017 23:05:46 GMT
< Server: My Accounts
<
{ [127 bytes data]
100   127  100   127    0     0     75      0  0:00:01  0:00:01 --:--:--    77* Curl_http_done: called premature == 0
100   127  100   127    0     0     75      0  0:00:01  0:00:01 --:--:--    77HTTP/1.1 200 OK
MY-CorrelationID: 123456789-adda-1234-a123-1a12345abcde
Pragma: no-cache
Cache-Control: no-store, no-cache, private
Content-Type: application/json;charset=UTF-8
Content-Length: 127
Date: Thu, 02 Feb 2017 23:05:46 GMT
Server: My Accounts

{
  "access_token":"123456789-1234-1234-1234-12345678901234",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"api"
}
* Connection #0 to host myaccounts.domain.com left intact

I was also able to verify this connection using postman, and I get the same response consistently.

I further development the solution for my needs based on research I've done. The PHP solution using cURL is below. Below are two functions and an if condition. The if condition fires the appropriate function based on if the access token has already been added to the session or not. If not added to the session, it will fetch it based on the credentials that needs to be added. If already added to the session, then proceed with getting the data needed.

I used the php curl documentation for expanding on my OP: http://php.net/manual/en/book.curl.php

<?php

session_start();

function getAccessCode(){

    $curl = curl_init();

    // Variables
    $apiGrantType = 'client_credentials';
    $apiScopes = array('scope1','scope2','scope3');             // Currently not used
    $apiUrl = "myaccounts.domain.com/auth/oauth/v2/token?grant_type=" . $apiGrantType;
    $authPath = '/var/www/html/domain.com/clients/test/';
    $cliendId = 'username';                                     // Client ID
    $clientSecret = 'password';                                 // Client Secret
    $certUserPwd = $cliendId . ":" . $clientSecret;             // Client ID:Client Secret
    $certFile = $authPath . 'my_auth.pem';                      // Private Cert
    $certPassword = 'cert-password';                            // Cert Password

    $apiPost = array(
        "grant_type"    => $apiGrantType,
        "client_id"     => $cliendId,
        "client_secret" => $clientSecret
    );
    $apiPostQuery = http_build_query($apiPost);

    $apiHeader = array();

    // $header Content Length
    $apiHeader[] = 'Content-length: 0';

    // $header Content Type
    $apiHeader[] = 'Content-type: application/json';

    // $header 'Client ID:Client Secret' Base64 Encoded
    $apiHeader[] = "Authorization: Basic " . base64_encode($cliendId . ":" . $clientSecret); // OAuth,Basic

    // cURL Options
    $options = array(

        CURLOPT_URL                 => $apiUrl,

        CURLOPT_RETURNTRANSFER      => true,

        CURLOPT_HEADER              => false, // true to show header information
        CURLINFO_HEADER_OUT         => true,
        CURLOPT_HTTPGET             => false,
        CURLOPT_POST                => true,
        CURLOPT_FOLLOWLOCATION      => false,
        CURLOPT_VERBOSE             => true,
        CURLOPT_FOLLOWLOCATION      => true,

        CURLOPT_SSL_VERIFYHOST      => false, // true in production
        CURLOPT_SSL_VERIFYPEER      => false, // true in production

        CURLOPT_TIMEOUT             => 30,
        CURLOPT_MAXREDIRS           => 2,

        CURLOPT_HTTPHEADER          => $apiHeader,
        CURLOPT_USERAGENT           => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)',

        CURLOPT_HTTPAUTH            => CURLAUTH_ANYSAFE, // CURLAUTH_BASIC
        CURLOPT_POSTFIELDS          => $apiPostQuery,

        CURLOPT_USERPWD             => $certUserPwd,
        CURLOPT_SSLCERTTYPE         => 'PEM',
        CURLOPT_SSLCERT             => $certFile,
        CURLOPT_SSLCERTPASSWD       => $certPassword
    );

    curl_setopt_array($curl , $options);
    $output = curl_exec($curl);
    $json = json_decode($output);

    return $json->access_token;
}


function getJobApps($access_token) {

    echo '<pre>' . print_r($_SESSION, TRUE) . '</pre>';

    /**
     * Get Job Applications Data from DOMAIN
     */
    $curl = curl_init();

    $apiUrl = "https://myaccounts.domain.com/aaaaa/bbbbb";

    // $header Authorization
    $apiHeader = array('Authorization', 'Bearer ' . $access_token);

    $options = array(
        CURLOPT_URL             => $apiUrl,
        CURLOPT_HTTPHEADER      => $apiHeader,
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_POST            => true
    );

    curl_setopt_array($curl , $options);
    $output = curl_exec($curl);
    $json = json_decode($output);

    echo '<pre>';
    print_r($json);
    echo '</pre>';
}


// Init Loop
if(isset($_SESSION['access_token'])) {

    // Job Applications
    $apiData = getJobApps($_SESSION['access_token']);

    echo $apiData;

} else {
    $access_token = getAccessCode();
    $_SESSION['access_token'] = $access_token;

    echo '<pre>' . print_r($_SESSION, TRUE) . '</pre>';

    header(sprintf("Location: %s", 'http://mywebsite.com/clients/test/test.php'));
    die();
}

?>
Pforzheim answered 2/2, 2017 at 23:21 Comment(0)
H
2

just add the following curl Option in your option array:

$options = array(
 /* 
  * other options
  */ 
   CURLOPT_SSLCERTTYPE => 'P12',
)

or this way

$ch = curl_init();
//other curl_options..
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12');
//....
$response = curl_exec($ch);
curl_close($ch);

This works for me.

Horbal answered 17/11, 2023 at 21:8 Comment(1)
Nice answer, it avoids to play with the openssl application to convert pfx to different files. But IMHO you should add in your answer some lines which appeared on the question like CURLOPT_SSLCERT => /path/cert.pfx, CURLOPT_SSLCERTPASSWD => 'cert_password'Glucosuria
F
0

Actually I had a .pfx file I converted it to pem using

openssl pkcs12 -in cert_file.pfx -out cert_file.pem

Then I found the exact path by using pwd command in linux. The path become something like /home/user/cert_file.pem

But the problem I was facing because of no file permission. So just for testing I gave 777 permission to the file. You can ofcourse give a proper permission. Then my response started working.

I have used this curl setting

    CURLOPT_URL => 'url here',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_VERBOSE => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_SSLCERTTYPE => 'PEM',
    CURLOPT_SSLCERT => '/home/user/cert_file.pem',
    CURLOPT_SSLCERTPASSWD => 'password',
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => 'fields here'

Password I set during converting to pem with the above command, so I gave that passowrd

Now everthing is working and I am getting response.

For Curl I have used below setting

  1. Open terminal ctrl+alt+t

  2. cd /etc/ssl/certs/

  3. sudo wget http://curl.haxx.se/ca/cacert.pem

  4. Check if .curlrc file is available in your home folder or not.

  5. nano ~/.curlrc

  6. Now paste the below lines in the open file

    capath=/etc/ssl/certs/
    cacert=/etc/ssl/certs/ca-certificates.crt
    
  7. Now save the file and do your things using curl command.

  8. Restart apache server

Fraenum answered 1/5, 2021 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.