Sample code for 30+ languages & platforms
C Requires Chilkat v11.0.0+

Xero API through an SSH Tunnel

This example demonstrates connecting through an SSH Tunnel w/ 2-legged OAuth for a Xero private application.

Chilkat C Downloads

C
#include <C_CkSocket.h>
#include <C_CkRest.h>
#include <C_CkPfx.h>
#include <C_CkPrivateKey.h>
#include <C_CkOAuth1.h>
#include <C_CkStringBuilder.h>
#include <C_CkXml.h>

void ChilkatSample(void)
    {
    BOOL success;
    HCkSocket tunnel;
    const char *sshHostname;
    int sshPort;
    HCkRest rest;
    BOOL bTls;
    int port;
    int maxWaitMs;
    HCkSocket channel;
    const char *consumerKey;
    const char *consumerSecret;
    HCkPfx pfx;
    HCkPrivateKey privKeyFromPfx;
    HCkPrivateKey privKeyFromPem;
    HCkOAuth1 oauth1;
    HCkStringBuilder sbXml;
    BOOL bAutoTrim;
    HCkXml xml;
    int recordCount;
    int i;

    success = FALSE;

    //  This example requires the Chilkat API to have been previously unlocked.
    //  See Global Unlock Sample for sample code.

    tunnel = CkSocket_Create();

    sshHostname = "sftp.example.com";
    sshPort = 22;

    //  Connect to an SSH server and establish the SSH tunnel:
    success = CkSocket_SshOpenTunnel(tunnel,sshHostname,sshPort);
    if (success == FALSE) {
        printf("%s\n",CkSocket_lastErrorText(tunnel));
        CkSocket_Dispose(tunnel);
        return;
    }

    //  Authenticate with the SSH server via a login/password
    //  or with a public key.
    //  This example demonstrates SSH password authentication.
    success = CkSocket_SshAuthenticatePw(tunnel,"mySshLogin","mySshPassword");
    if (success == FALSE) {
        printf("%s\n",CkSocket_lastErrorText(tunnel));
        CkSocket_Dispose(tunnel);
        return;
    }

    //   OK, the SSH tunnel is setup.  Now open a channel within the tunnel.
    //   (Any number of channels may be created from the same SSH tunnel.
    //   Multiple channels may coexist at the same time.)

    //  This sample code would typically be placed in a subroutine or function
    //  where the rest object is passed by reference.
    //  It does the OAuth1 setup and makes the initial connection.
    rest = CkRest_Create();

    bTls = TRUE;
    port = 443;
    maxWaitMs = 7000;

    //  This returns a socket object that is a single channel within the SSH tunnel.
    channel = CkSocket_Create();
    success = CkSocket_SshNewChannel(tunnel,"api.xero.com",port,bTls,maxWaitMs,channel);
    if (success == FALSE) {
        printf("%s\n",CkSocket_lastErrorText(tunnel));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        return;
    }

    //  Use the connection.  (This connection is a TLS running on an SSH channel through an SSH tunnel.
    //  In other words, TLS is wrapped within the SSH tunnel.)
    success = CkRest_UseConnection(rest,channel,TRUE);
    if (success == FALSE) {
        printf("%s\n",CkRest_lastErrorText(rest));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        return;
    }

    //  OK, we're connected.  
    //  -----------------------------------------------------------------
    //  Now setup the OAuth1 authenticator..

    consumerKey = "XERO_PRIVATE_APP_KEY";
    consumerSecret = "XERO_PRIVATE_APP_SECRET";

    //  Let's get our private key from our PFX (password protected), or the PEM (unprotected).
    //  You can decide which to use.  Either is OK, although I would recommend keeping your
    //  private keys in a PFX and not in an unprotected PEM.
    pfx = CkPfx_Create();
    success = CkPfx_LoadPfxFile(pfx,"qa_data/certs/xero_private_app/public_privatekey.pfx","PFX_PASSWORD");
    if (success == FALSE) {
        printf("%s\n",CkPfx_lastErrorText(pfx));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        CkPfx_Dispose(pfx);
        return;
    }

    privKeyFromPfx = CkPrivateKey_Create();
    success = CkPfx_PrivateKeyAt(pfx,0,privKeyFromPfx);
    if (success == FALSE) {
        printf("%s\n",CkPfx_lastErrorText(pfx));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        CkPfx_Dispose(pfx);
        CkPrivateKey_Dispose(privKeyFromPfx);
        return;
    }

    //  Or we can load from a PEM..
    privKeyFromPem = CkPrivateKey_Create();
    success = CkPrivateKey_LoadPemFile(privKeyFromPem,"qa_data/certs/xero_private_app/privatekey.pem");
    if (success == FALSE) {
        printf("%s\n",CkPrivateKey_lastErrorText(privKeyFromPem));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        CkPfx_Dispose(pfx);
        CkPrivateKey_Dispose(privKeyFromPfx);
        CkPrivateKey_Dispose(privKeyFromPem);
        return;
    }

    //  Note: There are many other means for loading a private key, including
    //  from other formats and directly from memory (i.e. not file-based).

    oauth1 = CkOAuth1_Create();
    CkOAuth1_putConsumerKey(oauth1,consumerKey);
    CkOAuth1_putConsumerSecret(oauth1,consumerSecret);
    CkOAuth1_putToken(oauth1,consumerKey);
    CkOAuth1_putTokenSecret(oauth1,consumerSecret);
    CkOAuth1_putSignatureMethod(oauth1,"RSA-SHA1");
    CkOAuth1_SetRsaKey(oauth1,privKeyFromPfx);

    //  Install the OAuth1 authenticator.
    CkRest_SetAuthOAuth1(rest,oauth1,FALSE);

    printf("OK, the Xero OAuth1 is initialized and the REST object is ready to make REST API calls..\n");

    //  -----------------------------------------------------------------
    //  Make a call to verify that OAuth1 through an HTTP proxy works..

    //  Get the full list of contacts.
    sbXml = CkStringBuilder_Create();
    success = CkRest_FullRequestNoBodySb(rest,"GET","/api.xro/2.0/Contacts",sbXml);
    if (success == FALSE) {
        printf("%s\n",CkRest_lastErrorText(rest));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        CkPfx_Dispose(pfx);
        CkPrivateKey_Dispose(privKeyFromPfx);
        CkPrivateKey_Dispose(privKeyFromPem);
        CkOAuth1_Dispose(oauth1);
        CkStringBuilder_Dispose(sbXml);
        return;
    }

    //  A 200 response is expected for actual success.
    if (CkRest_getResponseStatusCode(rest) != 200) {
        printf("%s\n",CkStringBuilder_getAsString(sbXml));
        CkSocket_Dispose(tunnel);
        CkRest_Dispose(rest);
        CkSocket_Dispose(channel);
        CkPfx_Dispose(pfx);
        CkPrivateKey_Dispose(privKeyFromPfx);
        CkPrivateKey_Dispose(privKeyFromPem);
        CkOAuth1_Dispose(oauth1);
        CkStringBuilder_Dispose(sbXml);
        return;
    }

    //  Iterate over the contacts..
    bAutoTrim = FALSE;
    xml = CkXml_Create();
    CkXml_LoadSb(xml,sbXml,bAutoTrim);
    CkXml_SaveXml(xml,"qa_cache/xero_contacts.xml");

    //  How many records exist?
    recordCount = CkXml_NumChildrenAt(xml,"Contacts");
    printf("numRecords = %d\n",recordCount);

    i = 0;
    while (i < recordCount) {
        CkXml_putI(xml,i);
        printf("ContactID: %s\n",CkXml_getChildContent(xml,"Contacts|Contact[i]|ContactID"));
        i = i + 1;
    }



    CkSocket_Dispose(tunnel);
    CkRest_Dispose(rest);
    CkSocket_Dispose(channel);
    CkPfx_Dispose(pfx);
    CkPrivateKey_Dispose(privKeyFromPfx);
    CkPrivateKey_Dispose(privKeyFromPem);
    CkOAuth1_Dispose(oauth1);
    CkStringBuilder_Dispose(sbXml);
    CkXml_Dispose(xml);

    }