Haris Hasan
Haris Hasan

Reputation: 30097

SharedAccessSignature not working when used on client side

I am facing a wired issue..

I want to allow certain users to read/write file from/to Azure-Container. For this I am using the concept of SharedAccessSignature.

I am generating the shared access signature in a RESTFUL (ASP.NET MVC4) web service which clients call to get the access key ..

  CloudStorageAccount storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
  CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient ();
  CloudBlobContainer container = blobClient.GetContainerReference (containerName);
  container.CreateIfNotExist ();
  BlobContainerPermissions containerPermissions = new BlobContainerPermissions ();
  containerPermissions.PublicAccess = BlobContainerPublicAccessType.Off;
  container.SetPermissions (containerPermissions);
  string sas = container.GetSharedAccessSignature (new SharedAccessPolicy ()
        {
            SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes (30),
            Permissions = SharedAccessPermissions.Write | SharedAccessPermissions.Read
        });
  //return sas to user

I return sas to the client where he tries to upload a blob using following code

  CloudBlobClient sasBlobClient = new CloudBlobClient ("http://127.0.0.1:10000/devstoreaccount1", new StorageCredentialsSharedAccessSignature (sak));
  CloudBlob blob = sasBlobClient.GetBlobReference (containerName + "/myblob.txt");
  blob.UploadText ("Hello SAS World");

on the last line client throws exception

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

Inner Exception : {"The remote server returned an error: (403) Forbidden."}

Interesting part is that if I put the client side code right after getting sas (string sas = container.GetShare....... ) it works without any exception. But if I put my client code in a separate console application (which then retrieves the key through a REST call) it throws exception.

Upvotes: 1

Views: 776

Answers (1)

Sandrino Di Mattia
Sandrino Di Mattia

Reputation: 24895

I tested your code in a Console Application and it works fine (I passed the sas variable to the CloudBlobClient). But then I set up a REST service using the ASP.NET Web API and retrieved the key using a WebClient:

  WebClient wc = new WebClient();
  var sas = wc.DownloadString("http://127.0.0.1:47413/api/values/1");

In both the Web Application and the Console Application I wrote the SAS key to my output window using Trace, and this was the result:

WebApp: ?se=2012-08-02T19%3A54%3A53Z&sr=c&sp=rw&sig=oWEF7r5HpkEh%2BH1aTVKGR7VF3gbWwq84gv%2BZFbXRhOA%3D

Client: "?se=2012-08-02T19%3A54%3A53Z&sr=c&sp=rw&sig=oWEF7r5HpkEh%2BH1aTVKGR7VF3gbWwq84gv%2BZFbXRhOA%3D"

As you can see it looks like the SAS key is being wrapped in double quotes. I don't know what you're using to create your REST service, but I'm using the ASP.NET Web API. And here it uses the JSON formatter as default formatter. So the SAS key being returned is correct, the only problem is that it's being returned in JSON format.

To get the actual SAS key you'll need to deserialize it to a string (sounds weird no?), here is an example with Json.NET:

var correctSAS = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(sas);

Upvotes: 2

Related Questions