How to use SharedAccessSignature to access blobs

crunchy picture crunchy · May 4, 2012 · Viewed 8.2k times · Source

I am trying to access a blob stored in a private container in Windows Azure. The container has a Shared Access Signature but when I try to access the blob I get a StorgeClientException "Server failed to authenticate the request. Make sure the Authorization header is formed correctly including the signature".

The code that created the container and uploaded the blob looks like this:

// create the container, set a Shared Access Signature, and share it 

// first this to do is to create the connnection to the storage account
// this should be in app.config but as this isa test it will just be implemented
// here: 
// add a reference to Microsoft.WindowsAzure.StorageClient 
// and Microsoft.WindowsAzure.StorageClient set up the objects
//storageAccount = CloudStorageAccount.DevelopmentStorageAccount;

storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["ConnectionString"]);
blobClient = storageAccount.CreateCloudBlobClient();

// get a reference tot he container for the shared access signature
container = blobClient.GetContainerReference("blobcontainer");
container.CreateIfNotExist();

// now create the permissions policy to use and a public access setting
var permissions = container.GetPermissions();
permissions.SharedAccessPolicies.Remove("accesspolicy");
permissions.SharedAccessPolicies.Add("accesspolicy", new SharedAccessPolicy
                                                               {
                                                                   // this policy is live immediately
                                                                   // if the policy should be delatyed then use:
                                                                   //SharedAccessStartTime = DateTime.Now.Add(T); where T is some timespan
                                                                   SharedAccessExpiryTime =
                                                                       DateTime.UtcNow.AddYears(2),
                                                                   Permissions =
                                                                       SharedAccessPermissions.Read | SharedAccessPermissions.Write
                                                               });

// turn off public access
permissions.PublicAccess = BlobContainerPublicAccessType.Off;

// set the permission on the ocntianer
container.SetPermissions(permissions);

 var sas = container.GetSharedAccessSignature(new SharedAccessPolicy(), "accesspolicy");


StorageCredentialsSharedAccessSignature credentials = new StorageCredentialsSharedAccessSignature(sas);
CloudBlobClient client = new CloudBlobClient(storageAccount.BlobEndpoint,
                                             new StorageCredentialsSharedAccessSignature(sas));

CloudBlob sasblob = client.GetBlobReference("blobcontainer/someblob.txt");
sasblob.UploadText("I want to read this text via a rest call");

// write the SAS to file so I can use it later in other apps
using (var writer = new StreamWriter(@"C:\policy.txt"))
{
    writer.WriteLine(container.GetSharedAccessSignature(new SharedAccessPolicy(), "securedblobpolicy"));
}

The code I have been trying to use to read the blob looks like this:

// the storace credentials shared access signature is copied directly from the text file "c:\policy.txt"
CloudBlobClient client = new CloudBlobClient("https://my.azurestorage.windows.net/", new StorageCredentialsSharedAccessSignature("?sr=c&si=accesspolicy&sig=0PMoXpht2TF1Jr0uYPfUQnLaPMiXrqegmjYzeg69%2FCI%3D"));

CloudBlob blob = client.GetBlobReference("blobcontainer/someblob.txt");

Console.WriteLine(blob.DownloadText());
Console.ReadLine();

I can make the above work by adding the account credentials but that is exactly what I'm trying to avoid. I do not want something as sensitive as my account credentials just sitting out there and I have no idea on how to get the signature into the client app without having the account credentials.

Any help is greatly appreciated.

Answer

Mark Willsher picture Mark Willsher · May 5, 2012

Why this?

writer.WriteLine(container.GetSharedAccessSignature(new SharedAccessPolicy(), "securedblobpolicy"));

and not writing the sas string you already created?

It's late and I could easily be missing something but it seems that you might not be saving the same access signature that you're using to write the file in the first place.

Also perhaps not relevant here but I believe there is a limit on the number of container-wide policies you can have. Are you uploading multiple files to the same container with this code and creating a new container sas each time?

In general I think it would be better to request a sas for an individual blob at the time you need it with a short expiry time.