C Requires Chilkat v11.0.0+
C
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
#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);
}