Search code examples
azureazure-storageazure-blob-storageazure-sas

Azure Storage Account generate SAS Token, not an SAS URI


I'm using the Azure.Storage.Blob library to generate a SasToken, but I get instead a Sas Uri. I looked for examples online and in the docs.

I tried to generate a token myself but I didn't succeed in doing so. I even tried creating a SharedKeyLite but that didn't work aswell.

My code for SharedKeyLite:

      var stringToSign = $"{DateTimeOffset.UtcNow.ToString("R", CultureInfo.InvariantCulture)}\n${canonicalizedResource}";
      var hmac = new HMACSHA256(Convert.FromBase64String(storageAccountKey));
      var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
      return Convert.ToBase64String(hash);

My request:

URI: https://<myAccount>.blob.core.windows.net/<pathToFile>

# Headers
Authorization: SharedKeyLite <myAccount>:<keyFromAbove>
x-ms-date: date
x-ms-version: 2014-02-14

Error:

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

Why doesn't Azure.Storage.Blob generate a SAS Token?


Solution

  • Use the Azure CLI to get the SAS token from the Storage Account.

     az storage blob generate-sas \ --account-name {Storage Account name} \
    --container-name {container name} \--name {blob name} \--permissions 
     {permissions to grant} \--expiry {datetime to expire the SAS token} \
    --services {storage services the SAS allows} \--resource-types {resource types the SAS allows}
    

    Example:

    CONNECTION_STRING=<connection-string> az storage blob generate-sas \
        --account-name MyStorageAccount \ --container-name MyContainer \
       --name MyBlob \ --permissions racdw \ --expiry 2020-06-15
    

    For more details refer this link

    Another method to generate SAS Token

        private static string GetSharedAccessSignature(
               string accountName,
               string accountkey,
               string blobContainer,
               string blobName,
               DateTimeOffset sharedAccessStartTime,
               DateTimeOffset sharedAccessExpiryTime)
        {
            var canonicalNameFormat = $"/blob/{accountName}/{blobContainer}/{blobName}";
            var st = sharedAccessStartTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
            var se = sharedAccessExpiryTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
            var sasVersion = "2016-05-31";
        
            string stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}", new object[]
            {
                "r",
                st,
                se,
                canonicalNameFormat,
                string.Empty,
                string.Empty,
                string.Empty,
                sasVersion,
                string.Empty,
                string.Empty,
                string.Empty,
                string.Empty,
                string.Empty
            });
        
            var sas = GetHash(stringToSign, accountkey);
        
            var credentials =
                $"?sv={sasVersion}&sr=b&sig={UrlEncoder.Default.Encode(sas)}&st={UrlEncoder.Default.Encode(st)}&se={UrlEncoder.Default.Encode(se)}&sp=r";
        
            string blobUri = $"https://{accountName}.blob.core.windows.net/{blobContainer}/{blobName}";
            return blobUri + credentials;
        }
        
        private static string GetHash(string stringToSign, string key)
        {
            byte[] keyValue = Convert.FromBase64String(key);
        
            using (HMACSHA256 hmac = new HMACSHA256(keyValue))
            {
                return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            }
        }
    

    For more details refer this thread