Tcl Requires Chilkat v11.0.0+
Tcl
Xero API through an SSH Tunnel
This example demonstrates connecting through an SSH Tunnel w/ 2-legged OAuth for a Xero private application.Chilkat Tcl Downloads
load ./chilkat.dll
set success 0
# This example requires the Chilkat API to have been previously unlocked.
# See Global Unlock Sample for sample code.
set tunnel [new_CkSocket]
set sshHostname "sftp.example.com"
set sshPort 22
# Connect to an SSH server and establish the SSH tunnel:
set success [CkSocket_SshOpenTunnel $tunnel $sshHostname $sshPort]
if {$success == 0} then {
puts [CkSocket_lastErrorText $tunnel]
delete_CkSocket $tunnel
exit
}
# Authenticate with the SSH server via a login/password
# or with a public key.
# This example demonstrates SSH password authentication.
set success [CkSocket_SshAuthenticatePw $tunnel "mySshLogin" "mySshPassword"]
if {$success == 0} then {
puts [CkSocket_lastErrorText $tunnel]
delete_CkSocket $tunnel
exit
}
# 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.
set rest [new_CkRest]
set bTls 1
set port 443
set maxWaitMs 7000
# This returns a socket object that is a single channel within the SSH tunnel.
set channel [new_CkSocket]
set success [CkSocket_SshNewChannel $tunnel "api.xero.com" $port $bTls $maxWaitMs $channel]
if {$success == 0} then {
puts [CkSocket_lastErrorText $tunnel]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
exit
}
# 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.)
set success [CkRest_UseConnection $rest $channel 1]
if {$success == 0} then {
puts [CkRest_lastErrorText $rest]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
exit
}
# OK, we're connected.
# -----------------------------------------------------------------
# Now setup the OAuth1 authenticator..
set consumerKey "XERO_PRIVATE_APP_KEY"
set 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.
set pfx [new_CkPfx]
set success [CkPfx_LoadPfxFile $pfx "qa_data/certs/xero_private_app/public_privatekey.pfx" "PFX_PASSWORD"]
if {$success == 0} then {
puts [CkPfx_lastErrorText $pfx]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
delete_CkPfx $pfx
exit
}
set privKeyFromPfx [new_CkPrivateKey]
set success [CkPfx_PrivateKeyAt $pfx 0 $privKeyFromPfx]
if {$success == 0} then {
puts [CkPfx_lastErrorText $pfx]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
delete_CkPfx $pfx
delete_CkPrivateKey $privKeyFromPfx
exit
}
# Or we can load from a PEM..
set privKeyFromPem [new_CkPrivateKey]
set success [CkPrivateKey_LoadPemFile $privKeyFromPem "qa_data/certs/xero_private_app/privatekey.pem"]
if {$success == 0} then {
puts [CkPrivateKey_lastErrorText $privKeyFromPem]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
delete_CkPfx $pfx
delete_CkPrivateKey $privKeyFromPfx
delete_CkPrivateKey $privKeyFromPem
exit
}
# Note: There are many other means for loading a private key, including
# from other formats and directly from memory (i.e. not file-based).
set oauth1 [new_CkOAuth1]
CkOAuth1_put_ConsumerKey $oauth1 $consumerKey
CkOAuth1_put_ConsumerSecret $oauth1 $consumerSecret
CkOAuth1_put_Token $oauth1 $consumerKey
CkOAuth1_put_TokenSecret $oauth1 $consumerSecret
CkOAuth1_put_SignatureMethod $oauth1 "RSA-SHA1"
CkOAuth1_SetRsaKey $oauth1 $privKeyFromPfx
# Install the OAuth1 authenticator.
CkRest_SetAuthOAuth1 $rest $oauth1 0
puts "OK, the Xero OAuth1 is initialized and the REST object is ready to make REST API calls.."
# -----------------------------------------------------------------
# Make a call to verify that OAuth1 through an HTTP proxy works..
# Get the full list of contacts.
set sbXml [new_CkStringBuilder]
set success [CkRest_FullRequestNoBodySb $rest "GET" "/api.xro/2.0/Contacts" $sbXml]
if {$success == 0} then {
puts [CkRest_lastErrorText $rest]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
delete_CkPfx $pfx
delete_CkPrivateKey $privKeyFromPfx
delete_CkPrivateKey $privKeyFromPem
delete_CkOAuth1 $oauth1
delete_CkStringBuilder $sbXml
exit
}
# A 200 response is expected for actual success.
if {[CkRest_get_ResponseStatusCode $rest] != 200} then {
puts [CkStringBuilder_getAsString $sbXml]
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
delete_CkPfx $pfx
delete_CkPrivateKey $privKeyFromPfx
delete_CkPrivateKey $privKeyFromPem
delete_CkOAuth1 $oauth1
delete_CkStringBuilder $sbXml
exit
}
# Iterate over the contacts..
set bAutoTrim 0
set xml [new_CkXml]
CkXml_LoadSb $xml $sbXml $bAutoTrim
CkXml_SaveXml $xml "qa_cache/xero_contacts.xml"
# How many records exist?
set recordCount [CkXml_NumChildrenAt $xml "Contacts"]
puts "numRecords = $recordCount"
set i 0
while {$i < $recordCount} {
CkXml_put_I $xml $i
puts "ContactID: [CkXml_getChildContent $xml {Contacts|Contact[i]|ContactID}]"
set i [expr $i + 1]
}
delete_CkSocket $tunnel
delete_CkRest $rest
delete_CkSocket $channel
delete_CkPfx $pfx
delete_CkPrivateKey $privKeyFromPfx
delete_CkPrivateKey $privKeyFromPem
delete_CkOAuth1 $oauth1
delete_CkStringBuilder $sbXml
delete_CkXml $xml