Authorization request signing for Windows Azure Storage REST API from PowerShell

Recently, while working on one of the Windows Azure migration engagement, we were need to have a simple and portable utility scripts that manipulate on various Windows Azure Storage (WAS) services APIs like “Get all blob metadata details from selected containers”.  This is further enabled to perform various manipulations for the business.

There are various options like LINQPad queries, WAPPSCmdlets or Azure Storage Explorer + Fiddler.  However, in-terms of considering the computation post to the WAS invocation, repetitiveness of the work and considering the various type of users environment, simple PowerShell script is the option.  So, I have decided to write simple PowerShell script using WAS REST API.  This does not require any other snap-in or WAS storage client assemblies. (Re-inventing the wheel?!)

One of the main hurdle is creating Authorization header (signing the request).  It should contains the following:

  • HTTP verb
  • all standard HTTP headers, or empty line instead (canonicalized headers)
  • the URI for the storage service (canonicalized resource)

A sample string for the signing mentioned below:

[code lang="text"] <div id="LC1">GET\n /*HTTP Verb*/</div>
<div id="LC2">\n /*Content-Encoding*/</div>
<div id="LC3">\n /*Content-Language*/</div>
<div id="LC4">\n /*Content-Length*/</div>
<div id="LC5">\n /*Content-MD5*/</div>
<div id="LC6">\n /*Content-Type*/</div>
<div id="LC7">\n /*Date*/</div>
<div id="LC8">\n /*If-Modified-Since */</div>
<div id="LC9">\n /*If-Match*/</div>
<div id="LC10">\n /*If-None-Match*/</div>
<div id="LC11">\n /*If-Unmodified-Since*/</div>
<div id="LC12">\n /*Range*/</div>
<div id="LC13">x-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n /*CanonicalizedHeaders*/</div>
<div id="LC14">/udooz/photos/festival\ncomp:metadata\nrestype:container\ntimeout:20 /*CanonicalizedResource*/</div>
[/code]

Read http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx and particularly the section http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element for request signing of “Authorization” header.

I have written a simple and dirty PowerShell function for blob metadata access.

[code lang="powershell"]

function Generate-AuthString
{
param(
[string]$url
,[string]$accountName
,[string]$accountKey
,[string]$requestUtcTime
)

$uri = New-Object System.Uri -ArgumentList $url

$authString =   "GET$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)$([char]10)"
$authString += "x-ms-date:" + $requestUtcTime + "$([char]10)"
$authString += "x-ms-version:2011-08-18" + "$([char]10)"
$authString += "/" + $accountName + $uri.AbsolutePath + "$([char]10)"
$authString += "comp:list$([char]10)"
$authString += "include:snapshots,uncommittedblobs,metadata$([char]10)"
$authString += "restype:container$([char]10)"
$authString += "timeout:90"

$dataToMac = [System.Text.Encoding]::UTF8.GetBytes($authString)

$accountKeyBytes = [System.Convert]::FromBase64String($accountKey)

$hmac = new-object System.Security.Cryptography.HMACSHA256((,$accountKeyBytes))
[System.Convert]::ToBase64String($hmac.ComputeHash($dataToMac))
}

[/code]

 

Use [char] 10 for new-line, instead of “`r`n”.

Now, you need to add “Authorization” header while making the request.

[code lang="powershell"] [System.Net.HttpWebRequest] $request = [System.Net.WebRequest]::Create($url)

...

$request.Headers.Add("Authorization", "SharedKey " + $accountName + ":" + $authHeader);

[/code]

The complete script is available at my GitHub repo https://github.com/udooz/powerplay/blob/master/README.md.

The real power when accessing REST API from PowerShell is the “XML processing”.  I can simply access ListBlob() atom fields like

[code lang="powershell"]

$xml.EnumerationResults.Blobs.Blob

[/code]

Happy Coding.

Mark this!
  • Digg
  • del.icio.us
  • Facebook
  • LinkedIn
  • Add to favorites
  • RSS
  • Twitter