11-27-2018 11:59 AM
Hello,
Is there a way to call an AWS API using the SnapLogic REST Get or Post snaps?
There’s no option to create an AWS Signature account for REST:
Hopefully I’m just missing something. I did all my testing using Postman and now I’m blocked in SnapLogic.
In SnapLogic Expression Language I see there’s Digest sha256 but AWS requires HMAC so I can’t find a workaround.
Alternatively is HMAC available in the Script snap or do I need to develop my own Snap for this this?
Thanks!
11-30-2018 08:37 AM
I was able to implement this using a Script Snap. Code for the Script Snap is below in case this can help someone else. Please note this is only for a GET request, and also note the HTTP Headers in the REST Get Snap.
/*
Purpose of this script is to derive a signing key and signature for AWS Signature Version 4 to enable calling an AWS based API GET method
https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html
https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
*/
try { load("nashorn:mozilla_compat.js"); } catch(e) { }
importPackage(com.snaplogic.scripting.language);
importPackage(java.util);
importClass(javax.crypto.Mac);
importClass(javax.crypto.spec.SecretKeySpec);
importClass(org.apache.commons.codec.binary.Base64);
importClass(org.apache.commons.codec.digest.DigestUtils);
importClass(javax.xml.bind.DatatypeConverter);
var impl = {
input : input
, output : output
, error : error
, log : log
,execute : function ()
{
//----------------------------------------------------------
// Enter your variables here
//----------------------------------------------------------
var secretKey = ''; // Your Secret Key
var accessKey = ''; // Your Access Key
var regionName = ''; //e.g.: us-east-1
var serviceName = ''; //e.g.: execute-api
var endpoint = ''; //e.g.: https://subdomain.domain.com/resource/id
var host = ''; //e.g.: subdomain.domain.com
var canonical_uri = ''; //e.g.: /resource/id
var canonical_querystring = ''; //e.g.: Param1=value&Param2=value
//----------------------------------------------------------
var method = 'GET';
var dateStamp = impl.getDateStamp();
var amzdate = impl.getDateTimeStamp();
var canonical_headers = 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n';
var signed_headers = 'host;x-amz-date';
var payload_hash = DigestUtils.sha256Hex('');
var canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash;
var algorithm = 'AWS4-HMAC-SHA256';
var credential_scope = dateStamp + '/' + regionName + '/' + serviceName + '/' + 'aws4_request';
var string_to_sign = algorithm + '\n' + amzdate + '\n' + credential_scope + '\n' + DigestUtils.sha256Hex(canonical_request);
var signing_key = impl.getSignature(secretKey, dateStamp, regionName, serviceName);
var signature = impl.base64toHEX(impl.HmacSHA256( string_to_sign, signing_key ));
var authorization_header = algorithm + ' ' + 'Credential=' + accessKey + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature;
var wrapper = new java.util.HashMap();
wrapper.put("authorization", authorization_header );
wrapper.put("url", endpoint );
wrapper.put("host", host );
wrapper.put("amzdate", amzdate );
this.output.write(wrapper);
}
, getSignature : function ( secretKey, dateStamp, regionName, serviceName )
{
regionName = regionName || '';
serviceName = serviceName || '';
dateStamp = dateStamp || '';
var kSecret = (new java.lang.String( "AWS4" + secretKey )).getBytes("UTF8");
var kDate = impl.HmacSHA256(dateStamp, kSecret);
var kRegion = impl.HmacSHA256(regionName, kDate);
var kService = impl.HmacSHA256(serviceName, kRegion);
var kSigning = impl.HmacSHA256("aws4_request", kService);
return kSigning;
}
, HmacSHA256 : function ( data, secretKey )
{
var algorithm = "HmacSHA256";
var mac = Mac.getInstance( algorithm );
mac.init(new SecretKeySpec( secretKey, algorithm ) );
return mac.doFinal( data.getBytes("UTF8") );
}
, getDateStamp : function ()
{
// Must be YYYYMMDD format
var d = new Date();
var dateStamp = d.getFullYear();
dateStamp += ('0' + (d.getMonth()+1)).slice(-2);
dateStamp += ('0' + d.getDate()).slice(-2);
return dateStamp;
}
, getDateTimeStamp : function ()
{
// Must be YYYYMMDDTHHMMSSZ format
var d = new Date();
var dateTimeStamp = impl.getDateStamp();
dateTimeStamp += 'T';
dateTimeStamp += ('0' + d.getHours()).slice(-2);
dateTimeStamp += ('0' + d.getMinutes()).slice(-2);
dateTimeStamp += ('0' + d.getSeconds()).slice(-2);
dateTimeStamp += 'Z';
return dateTimeStamp;
}
, base64toHEX : function( guid )
{
return DatatypeConverter.printHexBinary( guid ).toLowerCase();
}
};
var hook = new com.snaplogic.scripting.language.ScriptHook(impl);
01-04-2019 02:35 AM
Hi Ish,
Can you confirm from which Snaplex are you trying to connect?
Also can you please mention the snap pack version.
We too are facing the same issue and despite using the above mentioned script, we receive Signature Not matched error.
Regards
Harikrishnan
10-29-2020 07:33 AM
I am also getting authentication error- signature mismatch.
@Ish ,@Harikrish any solution you have pls do share.
10-29-2020 11:37 AM
Hi @Siva_Venna,
The advice I can offer is to check the values of the variables you input to the script are correct. For example if the endpoint is something like:
https://subdomain.domain.com/v1/resource?token=abcd123
Then the values would be:
var endpoint = 'https://subdomain.domain.com/v1/resource?token=' + encodeURIComponent('abcd123');
var host = 'subdomain.domain.com';
var canonical_uri = '/v1/resource';
var canonical_querystring = 'token=' + encodeURIComponent('abcd123');