Reputation: 3678
I would like to generate the SAS token for Azure table service from C# code. I generated the one from the portal which looks like
?sv=2016-05-31&ss=t&srt=sco&sp=rwdlacu&se=2017-03-23T20:05:14Z&st=2017-03-23T12:05:14Z&sip={MY_IP}&spr=https&sig=fL9GNAZqybSlQKWvaspwr%2FrFFtWO%2F5jVgFu1Ayu94Ic%3D
How to generate such kind of token from c# code? If there is any tutorial please redirect me to it. I tried with a method below, but the token generated is invalid.
UPDATED CODE
I am still getting an error 403 Forbidden. Is my code to compute the signature correct?
var StringToSign = "{Storage_account_name}" + "\n" +
"rwdlacu" + "\n" +
"t" + "\n" +
"sco" + "\n" +
"2017-03-24T12:05:14Z" + "\n" +
"2017-03-24T20:05:14Z" + "\n" +
"{IP}" + "\n" +
"https" + "\n" +
"2016-05-31" + "\n";
string encodedString = HttpUtility.UrlEncode(StringToSign);
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String("accountkey"));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(encodedString)));
Upvotes: 6
Views: 5136
Reputation: 1412
//account name
var storageAccountName = ConfigProvider.AccountName;
// your storage account access key here
var accessKey = ConfigProvider.BlobKey;
// connect to our storage account and create a blob client
var connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
storageAccountName,
accessKey);
var storageAccount = CloudStorageAccount.Parse(connectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
SharedAccessAccountPolicy policy = new SharedAccessAccountPolicy()
{
Permissions = SharedAccessAccountPermissions.Write | SharedAccessAccountPermissions.Create,
Services = SharedAccessAccountServices.Blob,
ResourceTypes = SharedAccessAccountResourceTypes.Container | SharedAccessAccountResourceTypes.Object,
SharedAccessExpiryTime = DateTime.UtcNow.AddMonths(1),
Protocols = SharedAccessProtocol.HttpsOnly,
};
string sasToken = storageAccount.GetSharedAccessSignature(policy);
Upvotes: 5
Reputation: 136356
The reason you're running into the issue is because you're calculating signature for SAS based on the logic for calculating Authorization
header. StringToSign
is different in both cases.
For SAS, this should be (for Service SAS
):
StringToSign = signedpermissions + "\n" +
signedstart + "\n" +
signedexpiry + "\n" +
canonicalizedresource + "\n" +
signedidentifier + "\n" +
signedIP + "\n" +
signedProtocol + "\n" +
signedversion + "\n" +
startingPartitionKey + "\n"
startingRowKey + "\n"
endingPartitionKey + "\n"
endingRowKey
If you want to use Account SAS
(which is what Portal does), it should be:
StringToSign = accountname + "\n" +
signedpermissions + "\n" +
signedservice + "\n" +
signedresourcetype + "\n" +
signedstart + "\n" +
signedexpiry + "\n" +
signedIP + "\n" +
signedProtocol + "\n" +
signedversion + "\n"
So based on your parameters, the StringToSign for Account SAS would be:
StringToSign = {youraccountname} + "\n" +
"rwdlacu" + "\n" +
"t" + "\n" +
"sco" + "\n" +
"2017-03-23T12:05:14Z" + "\n" +
"2017-03-23T20:05:14Z" + "\n" +
{yourip} + "\n" +
"https" + "\n" +
"2016-05-31 + "\n"
The computation for signature
is correct.
You may find these links helpful to learn more about computing SAS: Account SAS
and Service SAS
.
UPDATE
There's an issue with hmac
calculation as well. It should be using your account key and also it should use Convert.FromBase64String
.
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(accountKey));
Also, you should not URLEncode StringToSign
. Elements there should be URL decoded.
Lastly the SAS token should look like what you're getting back from the portal.
Code Sample
static void AccountSasSample()
{
var accountName = "your-account-name";
var accountKey = "your-account-key";
var start = DateTime.UtcNow.AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ssZ");
var end = DateTime.UtcNow.AddHours(1).ToString("yyyy-MM-ddTHH:mm:ssZ");
var permission = "rwdlacu";
var serviceType = "t";
var resourceTypes = "sco";
var ipAddress = "your-ip-address";
var protocol = "https";
var serviceVersion = "2016-05-31";
var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n", accountName, permission, serviceType, resourceTypes, start, end, ipAddress, protocol, serviceVersion);
Console.WriteLine(stringToSign);
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(accountKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = string.Format("?sv={0}&ss={1}&srt={2}&sp={3}&se={4}&st={5}&sip={6}&spr={7}&sig={8}", serviceVersion,
serviceType, resourceTypes, permission, end, start, ipAddress, protocol, HttpUtility.UrlEncode(signature));
Console.WriteLine(sasToken);
var urlToListTables = string.Format("https://{0}.table.core.windows.net/Tables{1}", accountName, sasToken);
//Copy this urlToListTables & paste it in browser's address bar. You should be able to see the list of tables in your storage account.
}
Upvotes: 7
Reputation: 6467
Why not use Azure Storage Client Library to generate SAS? You can refer to: https://learn.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1
Upvotes: 2