Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query Azure Table with Shared Access Signature returns not implemented, but with connection string works

Spend many hours to try to sort this out.

I have a table and want to create a read-only SAS and give to client components to read access. But never succeed.

If just use connection string and hook up table directly like this:

    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SliStorageConnection);

    // Create the table client.
    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

    var table = tableClient.GetTableReference(GlobalFilterTable);

    TableOperation tableOperation = TableOperation.Retrieve<TableEntity>(FilterTablePartition, "filter1");
    TableResult tableResult = table.Execute(tableOperation);

It works fine. But with SAS like below, always returns 501 Not Implemented

    var policy = new SharedAccessTablePolicy
    {
        SharedAccessExpiryTime = DateTime.Now.AddMinutes(30),
        Permissions = SharedAccessTablePermissions.Query
    };

    string sas = table.GetSharedAccessSignature(
        policy,
        null,
        FilterTablePartition,
        String.Empty,
        FilterTablePartition,
        String.Empty);

    Uri tableSasUri = new Uri(table.Uri, sas);
    AccessTable(tableSasUri.AbsoluteUri.ToString());

private static void AccessTable(string tableSas)
{
    string filterTableBaseUrl = tableSas.Substring(0, tableSas.IndexOf('?'));

    var filterTableSasCredentials = new StorageCredentials(tableSas.Substring(filterTableBaseUrl.Length));
    CloudTableClient tableClient = new CloudTableClient(new Uri(filterTableBaseUrl), filterTableSasCredentials);

    var _manifestFilterCloudTable = tableClient.GetTableReference(GlobalFilterTable);

    TableOperation tableOperation = TableOperation.Retrieve<TableEntity>(FilterTablePartition, "filter1");
    TableResult tableResult = _manifestFilterCloudTable.Execute(tableOperation);
}

Tried different ways, give less than 1 hour time, named or anonymous policy identifier, use signature only ("sig") to create StorageCredentials. All failed with different errors. Mostly 501 not implemented, sometime resource not found, sometimes 403 Forbidden.

Couldn't find useful info online. I am using Microsoft.WindowsAzure.Storage version 3.1 SDK.

Any help is highly appreciated

like image 963
Steve Lee Avatar asked Sep 29 '22 21:09

Steve Lee


1 Answers

I believe the problem is in the following two lines of code:

CloudTableClient tableClient = new CloudTableClient(new Uri(filterTableBaseUrl), filterTableSasCredentials);

    var _manifestFilterCloudTable = tableClient.GetTableReference(GlobalFilterTable);

Basically what is happening is that the table name is repeated twice in the table URL in manifestFilterCloudTable. When you're creating CloudTableClient, the URI should not include the table name. It should only be something like https://[youraccountname].table.core.windows.net.

Please use the following code in your AccessTable method:

        string filterTableBaseUrl = tableSas.Substring(0, tableSas.IndexOf('?'));
        var filterTableSasCredentials = new StorageCredentials(tableSas.Substring(filterTableBaseUrl.Length));
        filterTableBaseUrl = filterTableBaseUrl.Substring(0, filterTableBaseUrl.LastIndexOf("/"));
        tableClient = new CloudTableClient(new Uri(filterTableBaseUrl), filterTableSasCredentials);

        var _manifestFilterCloudTable = tableClient.GetTableReference("Address");

        TableOperation tableOperation = TableOperation.Retrieve<TableEntity>(FilterTablePartition, "filter1");
        TableResult tableResult = _manifestFilterCloudTable.Execute(tableOperation);

Another thing I noticed that for SharedAccessPolicy, you're using DateTime.Now. Depending on the timezone where the code is executed, you may run into 403 errors because date/time in Azure is in UTC. Please use DateTime.UtcNow instead.

like image 100
Gaurav Mantri Avatar answered Nov 03 '22 07:11

Gaurav Mantri