cancel
Showing results for 
Search instead for 
Did you mean: 

AWS Signature for REST Get & Post

Ish
New Contributor III

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:

image

Hopefully I’m just missing something. I did all my testing using Postman and now I’m blocked in SnapLogic.

image

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!

9 REPLIES 9

Ish
New Contributor III

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.

image

/*
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);

Harikrish
New Contributor

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

Siva_Venna
Contributor

I am also getting authentication error- signature mismatch.
image

@Ish ,@Harikrish any solution you have pls do share.

Ish
New Contributor III

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');