Amazon AWS API URL Signature creation with ColdFusion
<cffunction name="awsurl" returntype="string" access="public" output="No"> | |
<cfargument name="Query" type="string" required="true" /> | |
<cfargument name="AWSAccessKeyId" type="string" required="true" /> | |
<cfargument name="SecretKey" type="string" required="true" /> | |
<cfargument name="Host" type="string" default="ec2.amazonaws.com" /> | |
<cfargument name="Methord" type="string" default="GET" /> | |
<cfargument name="URI" type="string" default="/" /> | |
<cfargument name="SignatureVersion" type="string" default="2" /> | |
<cfargument name="Version" type="date" default="2012-04-01" /> | |
<cfargument name="http" type="string" default="https" hint="https|http" /> | |
<!--- add common values ---> | |
<cfset local.Time = dateConvert("local2Utc",now())> | |
<cfset local.Time = "#DateFormat(local.Time,'yyyy-mm-dd')#T#TimeFormat(local.Time,'HH:mm:ss')#"> | |
<cfset arguments.Query = "#arguments.Query#&Timestamp=#local.Time#&SignatureVersion=#arguments.SignatureVersion#&Version=#arguments.Version#&SignatureMethod=HmacSHA256"> | |
<!--- sort QueryString ---> | |
<cfset arguments.Query = ListToArray(arguments.Query,'&')> | |
<cfset ArraySort(arguments.Query,'text')> | |
<!--- prepend AccessKeyID ---> | |
<cfset ArrayPrepend(arguments.Query, "AWSAccessKeyId=#arguments.AWSAccessKeyId#")> | |
<!--- url encode each values ---> | |
<cfset local.SortedString = ArrayNew(1)> | |
<cfloop from="1" to="#ArrayLen(arguments.Query)#" index="local.i"> | |
<cfset local.value = arguments.Query[local.i]> | |
<cfif listlen(local.value,'=') gt 1> | |
<cfset ArrayAppend(local.SortedString,"#listfirst(local.value,'=')#=#reservedEncod(listlast(local.value,'='))#")> | |
<cfelse> | |
<cfset ArrayAppend(local.SortedString,"#local.value#")> | |
</cfif> | |
</cfloop> | |
<!--- create signature string ---> | |
<cfset local.toEncode = "#arguments.Methord##chr(10)##arguments.Host##chr(10)##arguments.URI##chr(10)##ArrayToList(local.SortedString,'&')#"> | |
<cfoutput><pre>#local.toEncode#</pre></cfoutput> | |
<!--- encode Signature String ---> | |
<cfset local.Signature = URLEncodedFormat(ToBase64(HMAC_SHA256(local.toEncode,arguments.SecretKey)))> | |
<cfset arguments.Query = ArrayToList(arguments.Query,'&')> | |
<cfset arguments.Query = "#arguments.http#://#arguments.Host##arguments.URI#?#arguments.Query#&Signature=#local.Signature#"> | |
<cfreturn arguments.Query> | |
</cffunction> | |
<cffunction name="reservedEncod" returntype="string" access="public" output="no"> | |
<cfargument name="string" type="string" required="true" /> | |
<cfset local.reserved = "!|##|$|&|'|(|)|*|+|,|/|:|;|=|?|@|[|]| "> | |
<cfloop list="#local.reserved#" index="local.i" delimiters="|"> | |
<cfif find(local.i,arguments.string)> | |
<cfset arguments.string = replace(arguments.string,local.i, "%#ucase(FormatBaseN(Asc(local.i),'16'))#", 'all')> | |
</cfif> | |
</cfloop> | |
<cfreturn arguments.string> | |
</cffunction> | |
<cffunction name="HMAC_SHA256" returntype="binary" access="public" output="no"> | |
<cfargument name="signMessage" type="string" required="true" /> | |
<cfargument name="signKey" type="string" required="true" /> | |
<cfset local.jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1") /> | |
<cfset local.jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1") /> | |
<cfset local.key = createObject("java","javax.crypto.spec.SecretKeySpec") /> | |
<cfset local.mac = createObject("java","javax.crypto.Mac") /> | |
<cfset local.key = local.key.init(local.jKey,"HmacSHA256") /> | |
<cfset local.mac = local.mac.getInstance(local.key.getAlgorithm()) /> | |
<cfset local.mac.init(local.key) /> | |
<cfset local.mac.update(local.jMsg) /> | |
<cfreturn local.mac.doFinal() /> | |
</cffunction> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
surgiie commentedJan 30, 2017
I cant seem to get HMAC_SHA256 function to generate the proper signature according to the response from amazon. Do you have an updated solution?