BLOB REST authentication examples
-
2010年1月25日 17:47Searched net for examples and have basic framework, but still getting 403 errors.Does anyone have a working BLOB REST authentication example?Thanks in advance.
- 已移动 Brian AurichMicrosoft Employee, Moderator 2010年9月28日 19:01 migration (From:Windows Azure)
全部回复
-
2010年1月25日 18:21Hi,
Will you be able to post some code so that we can take a look?
Thanks
Gaurav Mantri
Cerebrata Software
http://www.cerebrata.com -
2010年1月25日 18:30Thanks Gaurav, definitely, be back asap to post what I do have...
-
2010年1月25日 18:40答复者
Here is an example of using the REST API to retrieve a list of containers:
private void GetBlobs() { string requestMethod = "GET"; String urlPath = "comp=list"; String urlPathResource = "comp:list"; String msVersion = "2009-09-19"; String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); String canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}", dateInRfc1123Format, msVersion); String canonicalizedResource = String.Format("/{0}/\n{1}", AzureStorageConstants.Account, urlPathResource); String stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource); String authorizationHeader = CreateAuthorizationHeader(stringToSign); Uri uri = new Uri(AzureStorageConstants.BlobEndPoint + "?" + urlPath); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Method = requestMethod; request.Headers.Add("x-ms-date", dateInRfc1123Format); request.Headers.Add("x-ms-version", msVersion); request.Headers.Add("Authorization", authorizationHeader); request.Headers.Add("Accept-Charset", "UTF-8"); request.Accept = "application/atom+xml,application/xml"; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { Stream dataStream = response.GetResponseStream(); using (StreamReader reader = new StreamReader(dataStream)) { String responseFromServer = reader.ReadToEnd(); } } } private String CreateAuthorizationHeader(String canonicalizedString) { if (String.IsNullOrEmpty(canonicalizedString)) { throw new ArgumentNullException("canonicalizedString"); } String signature = CreateHmacSignature(canonicalizedString, AzureStorageConstants.Key); String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", AzureStorageConstants.SharedKeyAuthorizationScheme, AzureStorageConstants.Account, signature); return authorizationHeader; } private String CreateHmacSignature(String unsignedString, Byte[] key) { if (String.IsNullOrEmpty(unsignedString)) { throw new ArgumentNullException("unsignedString"); } if (key == null) { throw new ArgumentNullException("key"); } Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(unsignedString); using (HMACSHA256 hmacSha256 = new HMACSHA256(key)) { return Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac)); } }
Note the unfortunate usage where urlPath uses comp=list while urlPathResource uses comp:list. AzureStorageConstants is a trivial class exposing the Azure account details and endpoints.
I just tried this out so I know it works.- 已编辑 Neil MackenzieMVP, Editor 2010年7月7日 23:34 Corrected this to list of containers not blobs
-
2010年1月25日 20:13Thank you Neil,I used your code with my account/endpoint info but still get 403.Can you tell if the values I'm using "look" right please? I'm wondering if its simply the account value?var BlobEndPoint = "http://expressionsoft.blob.core.windows.net/";var Account = "expressionsoft";var SharedKeyAuthorizationScheme = "SharedKey";byte[] Key = Encoding.UTF8.GetBytes("Base 64 Secondary Access Key");One thing I should mentions is that I expect the GET to return a null or empty list since I haven't submitted any PUT requests yet.
-
2010年1月25日 20:44答复者
jmarquez -
If you haven't created a container and some blobs I suggest you download Gaurav Mantri's Cloud Storage Studio and use that to create a container and upload some files. Doing this has the advantage that using a third-party tool to access Azure Storage Services demonstrates that there are no problems accessing Azure Storage from your machine - and that you are using the right account and key. You should also use Fiddler to verify precisely what you are sending across the wire. The response visible in Fiddler typically provides additional detail as what the Azure Storage Service discovered to be wrong with your request.
You should verify that the data is in the correct RFC1123 format - and that it is correct. Azure gives you a 15 minute leeway on the time but if your system is too far off authentication will fail. You should verify that your account key is correct - a good clue that you copied it correctly is that base 64 keys often end with either one or two = symbols.
I did forget to provide one piece of code and that was used to convert the Base 64 key into an array of Bytes. AzureStorageConstants.Key uses the following to return the key as a Byte array
Convert.FromBase64String(cloudKey)
- 已编辑 Neil MackenzieMVP, Editor 2010年1月25日 20:59
- 已标记为答案 Yi-Lun LuoModerator 2010年2月1日 9:36
-
2010年1月25日 20:51Will do, and will post notes here. Thanks again Neil.
-
2010年4月19日 0:53
Hi,
Excellent post, really helped me get my head around the string signing. Using your code as a template I was trying to do PUTs but am gettting the "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature." I'm not sure what i'm doing wrong here, any help would be much appreciated.
string requestMethod = "PUT"; String msVersion = "2009-09-19"; String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); String canonicalizedHeaders = String.Format("x-ms-blob-type:{2}\nx-ms-date:{0}\nx-ms-version:{1}", dateInRfc1123Format, msVersion, "BlockBlob"); String canonicalizedResource = String.Format("/{0}/{1}/{2}", account, container, xmlBlobNew); String stringToSign = String.Format("{0}\n\n\n{4}\n\n{3}\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource, "Content-Type:text/plain", "Content-Length:11"); String authorizationHeader = CreateAuthorizationHeader(stringToSign); Uri uri = new Uri(blobEndPoint + container + @"/" + xmlBlobNew ); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Method = requestMethod; request.Headers.Add("x-ms-blob-type", "BlockBlob"); request.Headers.Add("x-ms-date", dateInRfc1123Format); request.Headers.Add("x-ms-version", msVersion); request.Headers.Add("Authorization", authorizationHeader); request.Headers.Add("Accept-Charset", "UTF-8"); request.ContentType = "text/plain"; request.ContentLength = 11; request.Accept = "application/atom+xml,application/xml, text/plain"; ...
-
2010年4月19日 3:02答复者
JimmieBond -
The following works:
private void PutBlob(String containerName, String blobName) { String requestMethod = "PUT"; String content = "The Name of This Band is Talking Heads"; UTF8Encoding utf8Encoding = new UTF8Encoding(); Byte[] blobContent = utf8Encoding.GetBytes(content); Int32 blobLength = blobContent.Length; const String blobType = "BlockBlob"; String urlPath = String.Format("{0}/{1}", containerName, blobName); String msVersion = "2009-09-19"; String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); String canonicalizedHeaders = String.Format("x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}", blobType, dateInRfc1123Format, msVersion); String canonicalizedResource = String.Format("/{0}/{1}", AzureStorageConstants.Account, urlPath); String stringToSign = String.Format("{0}\n\n\n{1}\n\n\n\n\n\n\n\n\n{2}\n{3}", requestMethod, blobLength, canonicalizedHeaders, canonicalizedResource); String authorizationHeader = CreateAuthorizationHeader(stringToSign); Uri uri = new Uri(AzureStorageConstants.BlobEndPoint + urlPath); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Method = requestMethod; request.Headers.Add("x-ms-blob-type", blobType); request.Headers.Add("x-ms-date", dateInRfc1123Format); request.Headers.Add("x-ms-version", msVersion); request.Headers.Add("Authorization", authorizationHeader); request.ContentLength = blobLength; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(blobContent, 0, blobLength); } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { String ETag = response.Headers["ETag"]; } }- 已建议为答案 Jimmiebond 2010年4月19日 9:58
-
2010年4月19日 9:58Thanks very much.
-
2010年9月27日 16:55
Hi, I am trying your code for write in my blob, but method GetResponse() gives me the error 'Forbbiden (403)'. I think that the cause is a bad Authorization but I can't find how to fix that issue.
I'm using local storage:
String AzureStorageConstantsBlobEndPoint = "http://127.0.0.1:10000/"; String AzureStorageConstantsAccount = "devstoreaccount1";
private static String CreateAuthorizationHeader(String canonicalizedString) { String AzureStorageConstantsKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="; String AzureStorageConstantsAccount = "devstoreaccount1"; String AzureStorageConstantsSharedKeyAuthorizationScheme = "SharedKey"; String signature = string.Empty; using (HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(AzureStorageConstantsKey))) { Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString); signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac)); } String authorizationHeader = String.Format( CultureInfo.InvariantCulture, "{0} {1}:{2}", AzureStorageConstantsSharedKeyAuthorizationScheme, AzureStorageConstantsAccount, signature); return authorizationHeader; }
I just changed this line of code:
Uri uri = new Uri(AzureStorageConstantsBlobEndPoint + AzureStorageConstantsAccount + "/" + urlPath);
because if I don't put account in the uri, I get a 404 error.
Did I miss anything?? I'm a little stuck...
Thanks in advance!!
-
2010年9月27日 18:25答复者
Carlimir -
The issue is that the authorization string is slightly different in development storage - and requires the account to be specified twice. When trying out things with the REST interface I prefer to go directly against cloud storage because of these differences and because the Fiddler experience is better. (You should be using Fiddler.)
In the REST examples I post I tend to focus on code against cloud storage to simplify the code (i.e. I don't give the alternatives.) In this particular case, the solution is to change the declaration of canonicalizedResource to the following (for development storage):
String canonicalizedResource = String.Format("/{0}/{0}/{1}", AzureStorageConstants.Account, urlPath); -
2010年9月28日 7:59Thanks for your response Neil, I solved my issue completely.I just download Fiddler and I find it very interesting. I'll take a look when I can.
Regards

