getting 403 forbidden webexception : azure blob put request.
-
6. ledna 2011 7:50I am using this code to upload some text directly to azure blob using rest api. I am getting an webexception 403 forbidden. Can someone please tell me where am i going wrong in my code.
private void PutBlob(String containerName, String blobName , CloudBlob blob)
{
String requestMethod = "PUT";
String urlPath = String.Format("{0}", blobName);
String storageServiceVersion = "2009-10-01";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
// if (uploadPST.HasFile)
// {
string content = "Sample file";
// Stream content = uploadPST.FileBytes;
UTF8Encoding utf8Encoding = new UTF8Encoding();
Byte[] blobContent = utf8Encoding.GetBytes(content);
Int32 blobLength = blobContent.Length;
const String blobType = "BlockBlob";
/* String canonicalizedHeaders = String.Format(
"x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
blobType,
dateInRfc1123Format,
storageServiceVersion);*/
String canonicalizedHeaders = String.Format(
"x-ms-date:{0}\nx-ms-meta-m1:{1}\nx-ms-meta-m1:{2}",
dateInRfc1123Format,
"v1",
"v2");
String canonicalizedResource = String.Format("/{0}/{1}", myaccount, urlPath);
String stringToSign = String.Format(
"{0}\n\n{1}\n\n{2}\n{3}",
requestMethod,
"text/plain; charset=UTF-8",
canonicalizedHeaders,
canonicalizedResource);
String authorizationHeader = CreateAuthorizationHeader(stringToSign, blob);
Uri uri = new Uri(CloudStorageAccount.FromConfigurationSetting("DataConnectionString").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", storageServiceVersion);
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"];
}
// }
}
Rau- Upravený elipsis.rau 6. ledna 2011 9:03
Všechny reakce
-
6. ledna 2011 7:39
I am using this code to upload some text directly to azure blob using rest api. I am getting an webexception 403 forbidden. Can someone please tell me where am i going wrong in my code.
private void PutBlob(String containerName, String blobName , CloudBlob blob)
{
String requestMethod = "PUT";
String urlPath = String.Format("{0}", blobName);
String storageServiceVersion = "2009-10-01";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
// if (uploadPST.HasFile)
// {
string content = "Sample file";
// Stream content = uploadPST.FileBytes;
UTF8Encoding utf8Encoding = new UTF8Encoding();
Byte[] blobContent = utf8Encoding.GetBytes(content);
Int32 blobLength = blobContent.Length;
const String blobType = "BlockBlob";
/* String canonicalizedHeaders = String.Format(
"x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
blobType,
dateInRfc1123Format,
storageServiceVersion);*/
String canonicalizedHeaders = String.Format(
"x-ms-date:{0}\nx-ms-meta-m1:{1}\nx-ms-meta-m1:{2}",
dateInRfc1123Format,
"v1",
"v2");
String canonicalizedResource = String.Format("/{0}/{1}", myaccount, urlPath);
String stringToSign = String.Format(
"{0}\n\n{1}\n\n{2}\n{3}",
requestMethod,
"text/plain; charset=UTF-8",
canonicalizedHeaders,
canonicalizedResource);
String authorizationHeader = CreateAuthorizationHeader(stringToSign, blob);
Uri uri = new Uri(CloudStorageAccount.FromConfigurationSetting("DataConnectionString").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", storageServiceVersion);
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"];
}
// }
}
- Sloučený Steve Marx 6. ledna 2011 9:35 appears to be duplicate
-
6. ledna 2011 8:55PřispěvatelI have a post showing an example of the Put Blob operation in the Azure Storage Services REST API. The first thing I would correct here is the storage service version which appears to be an invalid value. The latest version is 2009-09-19. The value quoted here, 2009-10-01, is the version for the Azure Service Management API not the Storage Services REST API.
-
6. ledna 2011 9:05Thanks for the reply. I have another question. Do we need to pass the certificate also?
Rau -
6. ledna 2011 9:08
Hi,
There are a few things that I noticed in your code above which could cause this 403 error (based on http://msdn.microsoft.com/en-us/library/dd179451.aspx):
1. You're not passing "x-ms-version" request header.
2. You're not passing "x-ms-blob-type" request header.
3. Even though you're using metadata headers in creating "canonicalizedHeaders" however these headers are missing from your request header collection. Also I noticed that you're passing same metadata header "x-ms-meta-m1" when creating ""canonicalizedHeaders".
You may also find this blog post from Neil helpful: http://convective.wordpress.com/2010/08/18/examples-of-the-windows-azure-storage-services-rest-api/
Hope this helps.
Thanks
Gaurav Mantri
Cerebrata Software
-
6. ledna 2011 9:30
Now I have followed the steps as in given in the post . This is my code. I am still getting the same exception "Remote server returned an error : 403 frobidden".
What does AzureStorageConstants.SharedKeyAuthorizationScheme mean exactly? As per my understanding it can be sharedKey or sharedKetLite . Is That correct?
private String CreateAuthorizationHeader(String canonicalizedString, CloudBlob blob)
{
String signature = string.Empty;
using (HMACSHA256 hmacSha256 = new HMACSHA256())
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKeyLite", myAccountNAme, signature);
return authorizationHeader;
}
private void PutBlob(String containerName, String blobName , CloudBlob blob)
{
String requestMethod = "PUT";
String urlPath = String.Format("{0}", blobName);
String storageServiceVersion = "2009-09-19";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
string content = "Sample file";
// Stream content = uploadPST.FileBytes;
UTF8Encoding utf8Encoding = new UTF8Encoding();
Byte[] blobContent = utf8Encoding.GetBytes(content);
Int32 blobLength = blobContent.Length;
const String blobType = "BlockBlob";
String canonicalizedHeaders = String.Format(
"x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
blobType,
dateInRfc1123Format,
storageServiceVersion);
String canonicalizedResource = String.Format("/{0}/{1}", myAccountName, 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, blob);
Uri uri = new Uri(CloudStorageAccount.FromConfigurationSetting("DataConnectionString").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", storageServiceVersion);
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"];
}
}
Rau -
6. ledna 2011 10:10
Hi,
Are you trying to upload data in development storage or cloud storage? Please take a look at this link (http://msdn.microsoft.com/en-us/library/dd179428.aspx) to understand about SharedKey and SharedKeyLite authentication schemes. It seems that you're using the format defined for "SharedKey":
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);However you are specifying "SharedKeyLite" to sign:
String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKeyLite", myAccountNAme, signature);Hope this helps.
Thanks
Gaurav
-
6. ledna 2011 10:27Ya. Thanks. I realized that i had used a wrong authentication scheme. I changed it to sharedKey. But I am still getting the exception. And I am uploading data to cloud storage.
Rau -
6. ledna 2011 10:59
Hi,
I noticed one more thing. Does your blobName variable includes blob container name as well? Reason I am asking this is because when you are creating "canonicalizedResource", you're only passing account name and urlPath (which is set to the name of the blob).
String canonicalizedResource = String.Format("/{0}/{1}", myAccountName, urlPath);
It should have been:
String urlPath = String.Format(“{0}/{1}”, containerName, blobName);
String canonicalizedResource = String.Format("/{0}/{1}", myAccountName, urlPath);
Hope this helps.Thanks
Gaurav
-
6. ledna 2011 11:06
Ya. The blobname contains the container name as well. Thats the reason i have not used the containername.
Rau -
6. ledna 2011 11:30
Hi,
Everything else looks OK. Did you check the error details for this 403 error. You can use the code below to see more details about this 403 error. Put this code in the catch block:
WebException webEx = exception as WebException; if (webEx != null) { WebResponse resp = webEx.Response; if (resp != null) { using (StreamReader sr = new StreamReader(resp.GetResponseStream(), true)) { string responseText = sr.ReadToEnd();//This is where details about this 403 message can be found } } }Please share the contents of responseText here.
Hope this helps.
Thanks
Gaurav
-
6. ledna 2011 11:54
This is the response that i have got .
<?xml version="1.0" encoding="utf-8"?><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:64d7af60-2d91-4d92-b801-a973138d8d82
Time:2011-01-06T11:52:21.8216796Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'n6TD+n6j865aRom+U/sk5KKKvt6N+k0wNXdBsqac0eA=' is not the same as any computed signature. Server used following string to sign: 'PUT
11
x-ms-blob-type:BlockBlob
x-ms-date:Thu, 06 Jan 2011 11:51:47 GMT
x-ms-version:2009-09-19
/myAccount/tempstorage/pst/ZDGGP634299114975250520/temp.txt'.</AuthenticationErrorDetail></Error>Thank you.
Rau -
6. ledna 2011 12:18
Thanks a lot for your help Gaurav.
I am sharing the link to my project. You will have to insert your account details to run it.
I have not deployed the project. I am running the project locally.
http://demos.dreamwarestech.com/azure/RestUpload.zip
Thank you.
Rau -
6. ledna 2011 12:34
Hi Rau,
Thanks for sharing the project. Let me try it out and get back to you.
Regards
Gaurav
-
6. ledna 2011 13:32
Hi Rau,
Finally!!! I should have seen this earlier but there is an issue with your CreateAuthorizationHeader() function especially with the following line:
byte[] storageKey = utf8Encoding.GetBytes(key);
It should be:
byte[] storageKey = Convert.FromBase64String(key);
Once you make this change, the 403 error should go away but you'll have to ensure that the blob container in question exists otherwise you'll get a 404 error.
Hope this helps.
Thanks
Gaurav
- Označen jako odpověď Allen Chen - MSFTMicrosoft Employee, Moderator 7. ledna 2011 2:44
-
6. ledna 2011 14:28Thanks a lot Gaurav. The code is working fine now.
Rau -
7. ledna 2011 5:33Thanks a lot Gaurav. I have one more question . Can i upload large files using this approach. I tried uploading 23MB file and i got request timeout error.
Rau -
7. ledna 2011 5:46
Hi Rau,
You're welcome. I don't think you can upload a 23 MB file using this approach as the maximum sized blob which can be uploaded without breaking it into blocks is 4 MB. Anything over that would need to be split into blocks. You may want to read about Put Block (http://msdn.microsoft.com/en-us/library/dd135726.aspx) and Commit Block List (http://msdn.microsoft.com/en-us/library/dd179467.aspx) operations. I do have a question for you: Is there any particular reason why you want to go this route i.e. implementing REST API on your own instead of using Storage Client library provided by Microsoft (http://msdn.microsoft.com/en-us/library/wl_svchosting_mref_reference_home.aspx)? I'm just curious.
Thanks
Gaurav
-
7. ledna 2011 7:23
Hi Gaurav,
Thanks for your reply, i read about 'Put Block' and 'Put Block List' operations of REST API, and i decided that insted of using Blok Blob if i use PageBlob i dont need to split the file in to small chunks, now i am modifying my program to use PageBlob.(Give me a comment if i am wrong with this approch).
And thanks for your curiousity also, if you really want to know more about that, please have a look to following link;
http://social.msdn.microsoft.com/Forums/en-US/windowsazuremanagement/thread/6a8c1072-975d-4af9-845b-0fd743ee470d
Basically in my application i want to upload a large file to webrole, need to process that file on webserver, and after processing that file, i want to upload it to BlobStorage.
Actually i am using StorageClient library to upload that processed file to blob and its working fine but it is part of webrole means i am uploading that file from webserver to BlobStorage, and problem is I need to upload that Big file first to webserver and then process it.
All problems now starts here. That's why i am using REST API to Upload a file directly to blob. Please reply if i am going wrong with this approch, or i need to change my approch. Any way please reply and have look on the link that i have provided.
Thanks
Rau -
7. ledna 2011 8:15
Hi Rau,
There are few things to consider:
1. Page blob v/s Block blob: The criteria for choosing between a page blob and a block blob should be solely based on how you want to use the blob. Block blobs are suitable for streaming purposes (e.g. images, documents, videos etc.) where you need to send the blob back to a client in some shape or form. Page blobs on the other hand are suitable when there are random read/writes involved. For example, you could upload a VHD as page blob mount it as an azure drive and start reading/writing into that. I'm not sure I am able to understand the usage of this blob from your description above.
2. Network speed: Even though page blobs do not have a restriction of block size, still you would need to consider the network speed between your application and Azure data center. For example, I am here in India and the network connectivity is comparatively poorer as compared to say US. For me, if I try to upload even a 1 MB blob without splitting it, I will certainly get a timeout error. Thus it is much advisable to split a blob into blocks (in case of blob blocks) and into pages (in case of page blobs) and upload these chunks. The difference would come when you are uploading pages, they get committed immediately while for blocks to commit you would need to call "Commit Block List".
3. Also I have seen your project (from the source code link). Essentially you're not directly uploading the blob into blob storage because first you will be using some kind of file uploader control (either ASP.Net or SWFUploader) and both of them would upload the file on web server first and then your server side code will execute which will push this data into blob storage. It would be direct if you had a separate utility (like our Cloud Storage Studio product which talks to blob storage directly) which is doing the upload. Then you would have some code in your web role which would read this blob and process it.
I think what would work best in your case is if you are able to break this large blob into smaller chunks on the client side and start uploading these chunks to your webrole. As these chunks become available to your webrole you can either:
Wait for all the chunks to arrive, reassemble that blob and then upload that blob in blob storage.
OR
Start moving these chunks into blob storage. If you're uploading them as block blob then you would need to commit the block list.
Hope this helps.
Thanks
Gaurav
-
7. ledna 2011 11:43
Hi Gaurav,
Thanks a lot for your advice. But I want my files to be directly uploaded to blob using swfuploader. So I have opted for page blob now. Now I am again getting 403 exception. As per the documentation this is a two step process. 1. To create a page blob without any content uploaded with put blob. 2. Add content with put page request.
My first step is failing. I am noit able to create a page blob. It gives 403 exception. Can you help me with this?
private String CreateAuthorizationHeader(String canonicalizedString)
{
String signature = string.Empty;
string key = "storageKey";
// UTF8Encoding utf8Encoding = new UTF8Encoding();
byte[] storageKey = Convert.FromBase64String(key);
using (HMACSHA256 hmacSha256 = new HMACSHA256(storageKey))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKey", "accountName", signature);
return authorizationHeader;
}
private void PutBlob(String blobName)
{
String requestMethod = "PUT";
String urlPath = String.Format("{0}", blobName);
String storageServiceVersion = "2009-09-19";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
UTF8Encoding utf8Encoding = new UTF8Encoding();
Byte[] blobContent = uploadPST.FileBytes;
Int32 blobLength = blobContent.Length;
const String blobType = "PageBlob";
String canonicalizedHeaders = String.Format(
"x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
blobType,
dateInRfc1123Format,
storageServiceVersion);
String canonicalizedResource = String.Format("/{0}/{1}", "accountName", 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("myHost" + "/" + 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-blob-content-length", blobLength.ToString());
request.Headers.Add("x-ms-version", storageServiceVersion);
request.Headers.Add("Authorization", authorizationHeader);
request.ContentLength = 0;
try
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
String ETag = response.Headers["ETag"];
}
}
catch (Exception exception)
{
// Response resp = exception.Response;
string responseText = exception.Message ;//This is where details about this 403 message can be found
}
}
Rau -
7. ledna 2011 13:22
Hi Rau,
Looking at your code above, you would need to include "x-ms-blob-content-length" when constructing "canonicalizedHeaders".
Hope this helps.
Thanks
Gaurav
-
7. ledna 2011 14:34Thanks Gaurav. I added the header. But it still failed. Gave the same exception.
Rau -
7. ledna 2011 14:39
May be it's time to upload the project one more time :)
Gaurav
-
8. ledna 2011 4:58
http://demos.dreamwarestech.com/azure/RestUpload.zip
I have uploded the project. Its the same one as before with some changes in headers.
Rau -
9. ledna 2011 15:21
Hi Rau,
Based on the documentation (http://msdn.microsoft.com/en-us/library/dd179428.aspx), your canonicalizedHeader string should have the request headers starting with x-ms- sorted alphabetically. So the code below:
String canonicalizedHeaders = String.Format( "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}\nx-ms-blob-content-length:{3}", blobType, dateInRfc1123Format, storageServiceVersion, blobLength.ToString());should be changed to something like:
String canonicalizedHeaders = String.Format( "x-mx-blob-content-length:{3}\nx-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}", blobType, dateInRfc1123Format, storageServiceVersion, blobLength.ToString());Please try it out and hopefully that should solve your problem.
Hope this helps.
Thanks
Gaurav
-
10. ledna 2011 5:25
Hi Gaurav,
I found a link http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/ce26dec6-d8a8-4036-a805-cb319e556a7d/ . This is the same approach as you had mnetioned in your earlier post. This approach is working for large files also. So I decided to go with it. But thanks for all the help. You gave me a lot of hints that has helped me understand blob storage better.
Rau -
29. dubna 2012 17:43
Can someone help. Am facing same problem.. but using simple code to do things. Can someone help please. Am able to upload the same data using StorageClient dll. But with Http, am facing issues. On desktop it says (403) Forbidden Error.
public bool StartGPSDataUpload(Guid raceId) { bool bResult = false; try { string URL = ""; URL = "http://xxxx.blob.core.windows.net/videos/"+ Uri.EscapeDataString("6a3c2acd-8a2f-41ee-9203-137d7ba7ecd5-GPS-test.txt") +"?timeout=90"; WebReq = (HttpWebRequest)HttpWebRequest.Create(URL); WebReq.Method = "PUT"; WebReq.KeepAlive = false; WebReq.Headers["x-ms-version"] = "2011-08-18"; WebReq.UserAgent = "myapp"; WebReq.Headers["x-ms-blob-type"] = "BlockBlob"; WebReq.Headers["x-ms-date"] = DateTime.UtcNow.ToString("R"); WebReq.Headers["Authorization"] = "SharedKey xxxx:ioOqYh7CnftgX8c1DxX5OiRWL1v9TfIJMmTl8m4ogrY="; gpsdataInByte = ReadGPSFile(raceId); WebReq.ContentLength = gpsdataInByte.Length; using (HttpWebResponse response = (HttpWebResponse)WebReq.GetResponse()) { String ETag = response.Headers["ETag"]; System.Windows.Forms.MessageBox.Show(ETag); } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show("error - " + ex.ToString()); } return bResult; } -
30. dubna 2012 14:50
I was able to get things working. Thanks for the details in this blob. A few things to note,
- In addition to the above, this article was helful http://convective.wordpress.com/2010/08/18/examples-of-the-windows-azure-storage-services-rest-api/
- In the above, without content length it worked
String canonicalizedHeaders = String.Format(
"x-mx-blob-content-length:{3}\nx-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}",
blobType,
dateInRfc1123Format,
storageServiceVersion,
blobLength.ToString());Here is the sample code for others. Usage will be (new AzureStorageHelper()).PutBlob("yourcontainername", "yourblobfilename");
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.Globalization; using System.Net; using System.IO; namespace TestBlobUpload { class AzureStorageConstants { public static string Key="xxxx"; public static string SharedKeyAuthorizationScheme = "SharedKey"; public static string Account="xxxx"; public static string BlobEndPoint="http://xxxxx.blob.core.windows.net/"; } class AzureStorageHelper { public String CreateAuthorizationHeader(String canonicalizedString) { String signature = string.Empty; //UTF8Encoding utf8Encoding = new UTF8Encoding(); //byte[] storageKey = utf8Encoding.GetBytes(AzureStorageConstants.Key); byte[] storageKey = Convert.FromBase64String(AzureStorageConstants.Key); using (HMACSHA256 hmacSha256 = new HMACSHA256(storageKey)) { Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString); signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac)); } String authorizationHeader = String.Format( CultureInfo.InvariantCulture, "{0} {1}:{2}", AzureStorageConstants.SharedKeyAuthorizationScheme, AzureStorageConstants.Account, signature); return authorizationHeader; } public void PutBlob(String containerName, String blobName) { String requestMethod = "PUT"; String urlPath = String.Format("{0}/{1}", containerName, blobName); String storageServiceVersion = "2011-08-18"; // "2009-09-19"; String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); 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 canonicalizedHeaders = String.Format( "x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}", blobType, dateInRfc1123Format, storageServiceVersion); /* String canonicalizedHeaders = String.Format( "x-mx-blob-content-length:{3}\nx-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}", blobType, dateInRfc1123Format, storageServiceVersion, blobLength.ToString()); */ 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", storageServiceVersion); request.Headers.Add("Authorization", authorizationHeader); request.ContentLength = blobLength; try { using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(blobContent, 0, blobLength); } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { String ETag = response.Headers["ETag"]; } System.Windows.Forms.MessageBox.Show("Success"); } catch (WebException webEx) { if (webEx != null) { WebResponse resp = webEx.Response; if (resp != null) { using (StreamReader sr = new StreamReader(resp.GetResponseStream(), true)) { string responseText = sr.ReadToEnd();//This is where details about this 403 message can be found System.Windows.Forms.MessageBox.Show("error - " + responseText); } } } } } } }