Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot create Blob Container with Azure's REST API

I'm trying to create a Blob Container using C# and the REST API (in Xamarin.Android). I'm able to upload a blob to an existing container, but I can't seem to create a container via REST. The error is (403) Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. Creating the Authorization Header works when uploading a blob, so it must be something with the way I'm constructing the container's string to be signed, but for the life of me I can't find the problem. Here's the code:

    private async Task<bool> CreateContainer(string containerName)
    {          
        String requestMethod = "PUT";
        String msVersion = "2009-09-19";
        string dt = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);

        String canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}", dt, msVersion);
        String canonicalizedResource = String.Format("/{0}/{1}\nrestype:container", AzureStorageConstants.Account, containerName);
        String stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource);

        string auth = SignThis(stringToSign);   
        string urlPath = string.Format("https://{0}.blob.core.windows.net/{1}?restype=container", AzureStorageConstants.Account, containerName);
        Uri uri = new Uri(urlPath);

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-ms-date", dt);
        client.DefaultRequestHeaders.Add("x-ms-version", "2009-09-19");
        client.DefaultRequestHeaders.Add("Authorization", auth);

        HttpContent empty = null;
        HttpResponseMessage response = await client.PutAsync(uri, empty);

        return response.IsSuccessStatusCode;
    }

    private static String SignThis(String StringToSign)
    {
        String signature = string.Empty;
        byte[] unicodeKey = Convert.FromBase64String(AzureStorageConstants.Key);
        using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
        {
            Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
            signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
        }

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

        return authorizationHeader;
    }
like image 315
David Canora Avatar asked Dec 05 '25 14:12

David Canora


1 Answers

The reason your request is failing is because you're not including the content length in your stringToSign even though it is included in the request (HttpClient is including it and setting its value to 0). This is causing signature to mismatch. To fix this, include content length in your stringToSign:

String stringToSign = String.Format("{0}\n\n\n0\n\n\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource);
like image 189
Gaurav Mantri Avatar answered Dec 07 '25 12:12

Gaurav Mantri



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!