6
votes

I'm working on connecting a ColdFusion 2016 application to Microsoft Azure blob storage and just don't seem to be able to get the authentication correct.

Here is the error I'm receiving:

<Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:9aed89ad-0001-00b8-6fd8-ecc48c000000 Time:2016-08-02T16:07:42.9046123Z</Message><AuthenticationErrorDetail>The Date header in the request is incorrect.</AuthenticationErrorDetail></Error>

HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. Content-Length: 419 Content-Type: application/xml Server: Microsoft-HTTPAPI/2.0 x-ms-request-id: 9aed89ad-0001-00b8-6fd8-ecc48c000000 Date: Tue, 02 Aug 2016 16:07:42 GMT Connection: close

Here is my code to list blobs in a container:

<!--- The key is copied directly from the Azure portal interface. --->
<cfset theKey = "fxIciOymaQ2OAcc1g2M...BwQRxNPtEzmwHAyx6J6pw==" />

<cfset requestMethod = "GET" />

<cfset utcDate = dateConvert("local2UTC",now()) />
<cfset xmsDate = dateFormat(utcDate,"ddd, d mmm yyyy") & " " & timeFormat(utcDate,"HH:mm:ss") & " GMT" />

<cfset xmsVersion = "2015-12-11" />

<cfset canonicalizedHeaders = "x-ms-date:#xmsDate#\nx-ms-version:#xmsVersion#\n" />
<cfset canonicalizedResource = "/coldfusion/slao\ncomp:list\ninclude:metadata,snapshots,uncommittedblobs\nrestype:container\n" />

<cfset stringToSign = "#requestMethod#\n\n\n\n\n\n\n\n\n\n\n\n#canonicalizedHeaders##canonicalizedResource#" />

<cfset x = replace(stringToSign,"\n","#chr(13)##chr(10)#","all") />
<cfset y = hmac(x,tmp,"HmacSHA256","utf-8") />
<cfset requestSignature = toBase64(binaryDecode(y,"hex")) />

<cfhttp method="#requestMethod#" url="https://coldfusion.blob.core.windows.net/slao?restype=container&comp=list&include=snapshots&include=metadata&include=uncommittedblobs" result="requestResult">
    <cfhttpparam type="header" name="Authorization" value="SharedKey coldfusion:#requestSignature#">
    <cfhttpparam type="header" name="x-ms-date" value="#xmsDate#">
    <cfhttpparam type="header" name="x-ms-version" value="#xmsVersion#">
</cfhttp>

The error suggests a bad date. As a test, I've copied in the date and time stamp shown in the error response and rerun my program - same error. I've spent quite a bit of time trying to research this on my own, but I just haven't made any progress on this. I've tried Fiddler as well but, of course, I'm getting the same error.

Does anyone see what the problem might be? Any ideas would be appreciated...

Sharon

1
(Edit) The replace() may be part of the problem. Typically, HTTP requests only use chr(10) for new lines. So unless the API specifically instructs you to use both chr(13) and chr(10), ie CR & LF, that could be causing a problem. Try using using chr(10) - only.Leigh
How are you computing tmp variable here: <cfset y = hmac(x,tmp,"HmacSHA256","utf-8") />?Gaurav Mantri
@Leigh, first, thank you for correcting the formatting on my error message! Also, I've removed the #chr(13)# and am still getting the same error.SharonG
One other thing. The hmac() function documentation is extremely poor. However, I believe it uses the "encoding" attribute on BOTH the input and key string. While that is correct for the input string, your key is obviously in base64 format, so decoding it as utf-8 will produce the wrong result. Instead, decode the key into binary, ie <cfset binaryKey = binaryDecode(theKey, "base64")>. Then use the binary key value in the hmac call, ie hmac(x, binaryKey,"HmacSHA256","utf-8")Leigh
@Leigh and @GauravMantri - adding <cfset binaryKey = binaryDecode(theKey, "base64")>, removing the extra \n, and a small tweak to the day number formatting in the date worked!SharonG

1 Answers

5
votes

I wanted to share my final, working program in ColdFusion 2016:

<!---
Copied directly from portal.azure for this storage account.
The copied value is in base64 format.
--->
<cfset theKey = "fxIciOymaQ2OAcc1g2M...BwQRxNPtEzmwHAyx6J6pw==" />

<!---
Explicitly decode the base64 key into binary, so that hmac() 
does not use the supplied "encoding", ie utf-8 to decode it
(because that produces the wrong result). 
--->
<cfset binaryKey = binaryDecode(theKey, "base64")>

<cfset requestMethod = "GET" />

<cfset utcDate = dateConvert("local2UTC",now()) />
<cfset xmsDate = dateFormat(utcDate,"ddd, dd mmm yyyy") & " " & timeFormat(utcDate,"HH:mm:ss") & " GMT" />

<cfset xmsVersion = "2015-12-11" />

<cfset canonicalizedHeaders = "x-ms-date:#xmsDate#\nx-ms-version:#xmsVersion#\n" />
<cfset canonicalizedResource = "/coldfusion/slao\ncomp:list\ninclude:metadata,snapshots,uncommittedblobs\nrestype:container" />

<cfset stringToSign = "#requestMethod#\n\n\n\n\n\n\n\n\n\n\n\n#canonicalizedHeaders##canonicalizedResource#" />

<cfset x = replace(stringToSign,"\n","#chr(10)#","all") />
<cfset y = hmac(x,binaryKey,"HmacSHA256","utf-8") />
<cfset requestSignature = toBase64(binaryDecode(y,"hex")) />

<cfhttp method="#requestMethod#" url="https://coldfusion.blob.core.windows.net/slao?restype=container&comp=list&include=snapshots&include=metadata&include=uncommittedblobs" result="requestResult">
    <cfhttpparam type="header" name="Authorization" value="SharedKey coldfusion:#requestSignature#">
    <cfhttpparam type="header" name="x-ms-date" value="#xmsDate#">
    <cfhttpparam type="header" name="x-ms-version" value="#xmsVersion#">
</cfhttp>

<cfdump var="#requestResult#" expand="yes" />

Many thanks! Sharon