How to use SharedAccessSignature to access blobs
Asked Answered
S

2

7

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.

Saporous answered 4/5, 2012 at 17:35 Comment(0)
G
4

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.

Glint answered 5/5, 2012 at 7:14 Comment(3)
container.GetSharedAccessSignature(new SharedAccessPolicy(), "securedblobpolicy")) is returning the sas string from the container (or at least that's what I assume it's doing, I could be wrong.)Saporous
Geez, that was painful. So apparently I was not retrieving the same key when I used the GetSharedAccessSignature method. Thanks for pointing that out Mark. Now I just have to deal with feeling like a fool :)Saporous
Glad to be of help - and don't feel bad - we all do it!Glint
L
1

Is "my.azurestorage.windows.net" just a typo? I would expect something there like "https://account.blob.core.windows.net".

Otherwise the code looks pretty similar to the code in http://blog.smarx.com/posts/shared-access-signatures-are-easy-these-days, which works.

Lodging answered 5/5, 2012 at 5:50 Comment(3)
my.azurestorage.windows.net is there as there is no need to make account info public. And the code may look pretty similar to the code in the blog you referenced, and it does work to an extent, but it does not allow anonymous access to a blob with the use of the shared access signature. That's the problem!Saporous
But to be sure, your actual value there ends in .blob.core.windows.net, right? (And the prefix is the name of your storage account?)Lodging
the value in the actual application is the address for the container. I haven't got my code open right now but what's in there is accurate as I can access the containers and blobs when I provide the account credentials. I'm still not sure why the named policy was not returning the correct values, but it's working now. Thanks for the input.Saporous

© 2022 - 2024 — McMap. All rights reserved.