Question

I'm attempting to set CORS properties on my Windows Azure blob storage account. I'm using an ASP.NET server to send the PUT request.

The server is sending back a Forbidden response, saying "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."

So it must be something in my authentication header. Here are the two functions I use to get the header.

public string GetWindowsAzureAuthenticationHeader(string verb)
{
    string stringToSign = String.Format("{0}\n"
                                        + "\n" // content encoding
                                        + "\n" // content language
                                        + "\n" // content length
                                        + "\n" // content md5
                                        + "\n" // content type
                                        + "\n" // date
                                        + "\n" // if modified since
                                        + "\n" // if match
                                        + "\n" // if none match
                                        + "\n" // if unmodified since
                                        + "\n" // range
                                        + "x-ms-date:" + DateTime.UtcNow.ToString("R") + "\nx-ms-version:2013-08-15\n" // headers
                                        + "/{1}\ncomp:properties\nrestype:service", verb, CloudConfig.StorageAccountName);

    return SignThis(stringToSign, CloudConfig.StorageAccountKey, CloudConfig.StorageAccountName);
}

private string SignThis(string stringToSign, string key, string account)
{
    string signature;
    var unicodeKey = Convert.FromBase64String(key);
    using (var hmacSha256 = new HMACSHA256(unicodeKey))
    {
        var dataToHmac = Encoding.UTF8.GetBytes(stringToSign);
        signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
    }

    String authorizationHeader = String.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}:{2}",
        "SharedKey",
        account,
        signature);

    return authorizationHeader;
}

This is the controller action that sends the request. The _mediaFactory.GetWindowsAzureCors method returns the contents of an XML file with my CORS request.

var content = Encoding.UTF8.GetBytes(_mediaFactory.GetWindowsAzureCors(ControllerContext.HttpContext.Server));
var request = (HttpWebRequest)WebRequest.Create(CloudConfig.StorageAccountUri);

request.Method = "PUT";
request.Headers.Add("x-ms-date", DateTime.UtcNow.ToString("R"));
request.Headers.Add("x-ms-version", "2013-08-15");
request.ContentType = "text/plain; charset=UTF-8";
request.Host = string.Format("{0}.blob.core.windows.net", CloudConfig.StorageAccountName);
request.Headers.Add("Authorization", _mediaFactory.GetWindowsAzureAuthenticationHeader(request.Method));

request.GetRequestStream().Write(content, 0, content.Length);
using (var response = (HttpWebResponse) request.GetResponse())
{
    model.StatusCode = response.StatusCode;
    model.Response = response.StatusDescription;
}

What am I doing wrong?

Was it helpful?

Solution

It's actually pretty simple.

First, add reference to Azure Storage Client library in your project. If you're using Nuget, the package you would want to install is WindowsAzure.Storage.

After that, the function which sets the CORS settings is SetServiceProperties. Here's the sample code to do so:

            CloudStorageAccount storageAccount = new CloudStorageAccount(new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(accountName, accountKey), true);
            var blobClient = storageAccount.CreateCloudBlobClient();
            ServiceProperties blobServiceProperties = new ServiceProperties();
            blobServiceProperties.Cors.CorsRules.Add(new CorsRule(){
                AllowedHeaders = new List<string>() {"*"},
                ExposedHeaders = new List<string>() {"*"},
                AllowedMethods = CorsHttpMethods.Post | CorsHttpMethods.Put | ... Other Allowed Methods,
                AllowedOrigins = new List<string>() {"http://yourdomain.com", "https://yourdomain.com", "blah", "blah", "blah"},
                MaxAgeInSeconds = 3600,
            });
            blobClient.SetServiceProperties(blobServiceProperties);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top