2
votes

I am trying to get a shared access signature for a single blob and then download the blob using the REST api. However, I always get a forbidden 403 error message. Both on storage emulator and the cloud. Here is my code:

CloudStorageAccount storageAccount = CloudStorageAccount.Parse("myConnectionStringHere...");

CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("containerName");
CloudBlob blob = container.GetBlobReference("blobName");

string sasToken = blob.GetSharedAccessSignature(new SharedAccessPolicy()
            {
                Permissions = SharedAccessPermission.Read,
                SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(24)
            }
            );

string completeUri = string.Format(CultureInfo.InvariantCulture, "{0}{1}", blob.Uri, sasToken);

// now use the uri to make the rest call and download
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(completeUri);
request.Method = "GET";
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
    using (Stream s = resp.GetResponseStream())
        {
            using (FileStream fs = new FileStream("test.jpg", FileMode.Create, FileAccess.Write))
                {
                        byte[] buffer = new byte[8 * 1024];
                        int len;
                        while ((len = s.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fs.Write(buffer, 0, len);
                        }
                    }
                }
            }

I keep getting the 403 error when invoking GetResponse. Any help appreciated!

EDIT: forgot to mention: I am using the latest azure sdk (2.0)

EDIT 2: I experimented a lot and found a tool called Azure Management Studio. This tool is able to create an SAS token. I did that, and used it with my REST call code. This worked just fine, so the error has to be inside the token creation code I have written. However, the format of the sas string is exactly the same. I don't know what else to try out

1
Can you provide an example of a blob and container name that you would use?Jason Haley
container name: "cname" blob name: "bname"Christian
Looking at some of my code, I use: blob.Uri.AbsoluteUri + sasToken for the url.Jason Haley
does the token creation maybe need to be submitted to blob storage before actually using the sas token?Christian
I don't think so, its just the code you have (blob.Uri) will really be blob.Uri.ToString() which could be different than the blob.Uri.AbsoluteUriJason Haley

1 Answers

8
votes

A few things I noticed:

  1. You mentioned that you're using SDK 2.0 however I think you're not using the latest storage client library (2.0.6). From your code, it seems you're still using old storage client library (1.8). Can you please check in your code if you're referencing Microsoft.WindowsAzure.StorageClient or Microsoft.WindowsAzure.Storage. If it is former, then you're using old library.
  2. If you're using old storage client library, then please note that with old storage client library which makes use of old Storage REST API, for anonymous SAS tokens (i.e. tokens without container access policy) you can't specify an expiration time more than 1 hour from current time (in UTC of course). If I try to use your URL, I get the following error message (under AuthenticationErrorDetail node:

Access without signed identifier cannot have time window more than 1 hour

Can you try by creating a SAS token which is valid for less than 1 hour? E.g.

var sasToken = blob.GetSharedAccessSignature(new SharedAccessPolicy
    {
        Permissions = SharedAccessPermission.Read,
        SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromMinutes(30)
    }
);

If you continue to want to use the older storage client library, you have a few choices:

  1. Create a SAS Token which is valid for less than an hour as explained above.
  2. Use a container level access policy to create a SAS token. With a container level access policy, you will be able to define SAS tokens which have an expiry date more than 1 hour. For more on this, please click here: http://msdn.microsoft.com/en-us/library/windowsazure/ee393341.aspx

If you use the new storage client library, you would be able to define longer duration token without using a container access policy. However there are a lot of differences between the two versions of the library and migration from older to newer version is not trivial. I wrote a blog post some days ago about migrating code from older version to newer version. You can read it here: http://gauravmantri.com/tag/storage-client-library/. Lastly, I wrote a blog post on SAS, which you can read here: http://gauravmantri.com/2013/02/13/revisiting-windows-azure-shared-access-signature/.