3

Has anyone tried creating a table inside a storage account using REST API? I can do it without an issue if I use SharedKeyLite authorization. However, when using SharedKey authorization, the authentication keeps on failing.

My guess is it's got to do something with the "Content-MD5" value in the Authorization signature. The documentation is a little vague on Content-MD5 value and I can't find a recommended way to generate Content-MD5 in the documentation.

I can't find an example using C#. The only example I found was using Powershell and that is using an empty string for Content-MD5. However, that doesn't work for my case.

Here is my code:

public static void CreateTable(string storageAccount, string storageKey, string tableName)
        {
            var client = new HttpClient();

            string date = DateTime.UtcNow.ToString("R", System.Globalization.CultureInfo.InvariantCulture);
            client.DefaultRequestHeaders.Add("x-ms-date", date);
            string msVersion = "2018-03-28";
            client.DefaultRequestHeaders.Add("x-ms-version", msVersion);
            client.DefaultRequestHeaders.Add("MaxDataServiceVersion", "3.0;NetFx");
            client.DefaultRequestHeaders.Add("DataServiceVersion", "3.0;NetFx");
            client.DefaultRequestHeaders.Add("Accept", "application/json;odata=nometadata");
            string payload = "{ \"TableName\":\""+ tableName +"\" }";
            int contentLength = GetContentLength(payload);
            string authH = "SharedKey " + storageAccount + ":" + CreateTableSignature("POST", payload, "application/json", date, storageAccount + "/Tables", storageKey, new List<string>() { });
            client.DefaultRequestHeaders.Add("Authorization", authH);
            string requestUri = $"https://{storageAccount}.table.core.windows.net/Tables";

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
            request.Content = new StringContent(payload,
                                                Encoding.UTF8,
                                                "application/json");
            request.Content.Headers.ContentLength = contentLength;
            client.SendAsync(request)
                  .ContinueWith(responseTask =>
                  {
                      Console.WriteLine("Response: {0}", responseTask.Result);
                  });
        }
public static string CreateTableSignature(string verb, string content, string contentType,  string date, string resource, string key, List<string> canonicalizedResourceParms)
        {
            string msgSignature = verb + "\n" +
               CreateMD5(content) + "\n" +
               contentType + "\n" +
               date + "\n";

            msgSignature += "/" + resource;
            foreach (string parm in canonicalizedResourceParms)
                msgSignature += "\n" + parm;
            byte[] SignatureBytes = Encoding.UTF8.GetBytes(msgSignature);

            // Create the HMACSHA256 version of the storage key.
            HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(key));

            // Compute the hash of the SignatureBytes and convert it to a base64 string.
            return Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));

        }
public static string CreateMD5(string input)
        {
            // Use input string to calculate MD5 hash
            using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
            {
                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);
                return Convert.ToBase64String(hashBytes);
            }
        }
2
  • I've tried the solution here for creating the authorization header, but the same error for me as well.As per here this should be occur in 2 cases, 1) your account key is incorrect correct and 2) Clock on your computer is incorrect. These are the two reasons which could result in this error. Commented Sep 23, 2018 at 12:24
  • I don't think my account key is incorrect or the clock is off because SharedKeyLite authorization works. Also, I was able to do some Blob service operations like create a storage account. Even though the Bob service operations have a different signatures, they do use the date and key fields. Commented Sep 24, 2018 at 13:25

1 Answer 1

1

Two points to fix.

  1. Content-Type

    request.Content = new StringContent(payload,
                                        Encoding.UTF8,
                                        "application/json");
    

    In this method, SDK actually sets application/json; charset=utf-8 when we sending the request. This means the signature needs application/json; charset=utf-8 as well.

    Or I recommend you to remove that misleading content type setting and use

    request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    
  2. Content-MD5

    It's not required in signature, you can leave it empty. Otherwise If you want to put it in the signature, you need to add corresponding request header first.

    request.Content.Headers.ContentMD5 = Convert.FromBase64String(CreateMD5(payload));
    

    Besides, in method CreateMD5(), Encoding should be UTF8

    System.Text.Encoding.UTF8.GetBytes(input);
    
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.