john
john

Reputation: 641

Invalid signature error in Amazon AWS API "itemsearch" call using ColdFusion

I am stuck on a error that is the invalid signature. I am calling the itemsearch API, but before that my signature (version 4) is not working.

This is the cfc file "amazonsig.cfc" that I got from http://amazonsig.riaforge.org/index.cfm?event=action.download:

<cfcomponent hint="Amazon Product Advertising API Signature Generator">

    <cffunction name="signRequest" returntype="string" output="false"
        hint="Sign a request">

        <cfargument name="request" required="yes" type="string">
        <cfargument name="secretKey" required="yes" type="string">

        <!--- "Local" variable scope --->
        <cfset var lc = structnew()>

        <!--- Extract the URL part of the request and strip the protocol --->
        <cfset lc.requesturl = listfirst(arguments.request, "?")>
        <cfset lc.requesturl = replacenocase(lc.requesturl, "http://", "")>

        <!--- Split into host and path --->
        <cfset lc.host = listfirst(lc.requesturl, "/")>
        <cfset lc.path = right(lc.requesturl, len(lc.requesturl) - len(lc.host))>

        <!--- Process the query string parameters into a structure --->
        <cfset lc.querystring = listlast(arguments.request, "?")>
        <cfset lc.strParams = structnew()>
        <cfloop list="#lc.querystring#" index="i" delimiters="&">
            <cfset lc.strParams[listfirst(i, "=")] = urldecode(listlast(i, "="))>
        </cfloop>

        <!--- Add the timestamp --->
        <cfif not StructKeyExists(lc.strParams, "Timestamp")>
            <cfset lc.utcdate = dateconvert("local2Utc", now())>
            <cfset lc.timestamp = dateformat(lc.utcdate, 'yyyy-mm-dd') & "T" & timeformat(lc.utcdate, 'HH:mm:ss') & "Z">
            <cfset lc.strParams["Timestamp"] = lc.timestamp>
        </cfif>

        <!--- Sort the parameters --->
        <cfset lc.keys = listsort(structkeylist(lc.strParams), "text")>

        <!--- Generate a new query string including timestamp, with parameters in the correct order, encoding as we go --->
        <cfset lc.qs = "">
        <cfloop list="#lc.keys#" index="i">
            <cfset lc.qs = lc.qs & rfc3986EncodedFormat(i) & "=" & rfc3986EncodedFormat(lc.strParams[i]) & "&">
        </cfloop>

        <!--- Strip off the last & --->
        <cfset lc.qs = left(lc.qs, len(lc.qs)-1)>

        <!--- Build the string to sign --->
        <cfset lc.stringToSign = "GET" & chr(10)>
        <cfset lc.stringToSign = lc.stringToSign & lc.host & chr(10)>
        <cfset lc.stringToSign = lc.stringToSign & lc.path & chr(10)>
        <cfset lc.stringToSign = lc.stringToSign & lc.qs>

        <!--- Create the signature --->
        <cfset lc.binaryMsg = JavaCast("string",lc.stringToSign).getBytes("iso-8859-1")>
        <cfset lc.binaryKey = JavaCast("string",arguments.secretKey).getBytes("iso-8859-1")>
        <cfset lc.key = createObject("java","javax.crypto.spec.SecretKeySpec")>
        <cfset lc.key.init(lc.binaryKey,"HmacSHA256")>
        <cfset lc.hmac = createObject("java","javax.crypto.Mac")>
        <cfset lc.hmac = lc.hmac.getInstance("HmacSHA256")>
        <cfset lc.hmac.init(lc.key)>
        <cfset lc.hmac.update(lc.binaryMsg)>
        <cfset lc.signature = lc.hmac.doFinal()>

        <!--- Return the new request URL --->
        <cfreturn "http://" & lc.host & lc.path & "?" & lc.qs & "&Signature=" & urlencodedformat(tobase64(lc.signature))>

    </cffunction>

    <cffunction name="rfc3986EncodedFormat" returntype="string" output="false"
        hint="Perform some character encoding">
        <cfargument name="text" required="yes" type="string">
        <!--- "Local" variable scope --->
        <cfset var lc = structnew()>
        <cfset lc.objNet = createObject("java","java.net.URLEncoder")>
        <cfset lc.encodedText = lc.objNet.encode(arguments.text, 'utf-8').replace("+", "%20").replace("*", "%2A").replace("%7E", "~")>
        <cfreturn lc.encodedText>
    </cffunction>
</cfcomponent>

This is my cfm file "amazonsig.cfm"

<cfset requrl = "http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&Operation=ItemSearch&AWSAccessKeyId=aaaa&AssociateTag=aaaaa&SearchIndex=Books&Keywords=Harry&ResponseGroup=Images,ItemAttributes,Offers">

<cfset amazonsig = createObject("component", "amazonsig")>
<cfset abc = amazonsig.signrequest(requrl,"aaa")>


<cfhttp url="#abc#" method="GET" result="response"  resolveurl="yes">
<cfhttpparam type="header" name="Content-Type" value="application/json" >
<cfhttpparam type="header" name="Accept" value="application/json" >

</cfhttp>
<cfdump var="#response#">

Note: the signature URL is correct because I hit directly in the browser and the response return correctly, but in <cfhttp> it is giving error.

Enter image description here

Upvotes: 0

Views: 466

Answers (2)

john
john

Reputation: 641

I have solved it I was using coldfusion 11 with jdk 1.7 but when i run the code on coldfusion 10 with jdk 1.8 it successfully run.

Upvotes: 0

CFMLBread
CFMLBread

Reputation: 754

Make sure you're running ColdFusion with the latest version of Java. Many CF installs are using older JVMs which do not support the updated security features being used by many web services.

Here is a blog post with instructions for updating Java for ColdFusion.

Upvotes: 1

Related Questions