locked
Blob SAS REST Interface doesn't support blob names that start with forward slash "/" RRS feed

  • Question

  • I have in a sample app been able to reproduce this.

    Basically here is the code, use a file in a private container, and the code below works. Then simply rename the blob to have a slash in the front, e.g. "/HdrImage.gif" and in both places shown below insert a slash and it fails with the error and it drops the extra slashes in the front. The signature must actually embed the incorrect string. Tried to Uri.Encode the name, but doesn't work either.

    Any idea, or do I have to rename all of my blobs without the leading slash? When I imported them, I unfortunately put an extra slash in the front of the blob name to simply look "right" with several folder deep structure. Not a fan of folders where they don't start with a slash! But now trying to get SAS access to content on the fly as users request content, I can't use the SAS because it doesn't work with the leading slashes.

    Error Message:

    Signature did not match. String to sign used was r  2012-08-13T05:55:08Z /mystorage/test/HdrImage.gif 2012-02-12

    Sample Code:

            protected void APITest2()
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings[connectionStringSettingName]);
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    
                DateTime starttime = DateTime.UtcNow.AddMinutes(-1);
                DateTime endtime = DateTime.UtcNow + TimeSpan.FromMinutes(5);
    
                string sig = MakeBlobReadSignature(endtime, "mystorage", "test", "HdrImage.gif");
    
                var uri = new UriBuilder();
                uri.Scheme = "http"; // or https works too
                uri.Host = string.Format("{0}.{1}", "mystorage", "blob.core.windows.net");
                uri.Path = string.Format("test/{0}", "HdrImage.gif");
                uri.Query = string.Format("se={1}&sr=b&sp=r&sig={2}",
                    Uri.EscapeDataString(starttime.ToString("yyyy-MM-ddTHH:mm:ssZ")), //not needed, excluded from string
                    Uri.EscapeDataString(endtime.ToString("yyyy-MM-ddTHH:mm:ssZ")),
                    Uri.EscapeDataString(sig));
    
                Response.Write(String.Format("SAS Link: <a href=\"{0}\" target=\"_blank\">{0}</a><br />", uri.ToString()));
            }
    
            private string MakeBlobReadSignature(DateTime endtime, string account, string container, string blobname)
            {
                string stringtosign =
                    string.Format("r\n\n{1:yyyy-MM-ddTHH:mm:ssZ}\n/{2}/{3}/{4}\n\n2012-02-12",
                    null, endtime, account, container, blobname); //also excluded the startime here, the null
    
                return storageAccount.Credentials.ComputeHmac(stringtosign);
            }
    
    Thank you!
    Monday, August 13, 2012 5:58 AM

All replies

  • Hi,

    I am working on a code which is similar to yours and its working fine for me. Please look at the code below:

    private string MakeBlobReadSignature(CloudStorageAccount account, DateTime StartTime, DateTime EndTime, string Path) { string stringtosign = string.Format("r\n{0:yyyy-MM-ddTHH:mm:ssZ}\n{1:yyyy-MM-ddTHH:mm:ssZ}\n/{2}{3}\n{4}\n{5}", StartTime, EndTime, account.Credentials.AccountName, Path, null, "2012-02-12"); return account.Credentials.ComputeHmac(stringtosign); } private string CreateBlobSASignature(string BlobURL, DateTime EndTime, DateTime StartTime) { GetAccountInformation(); var uri = new UriBuilder(); uri = new UriBuilder(@"folder/Blobname"); //HardCoded to provide you the example uri.Query = string.Format("sv=2012-02-12&st={0}&se={1}&sr=b&sp=r&sig={2}", Uri.EscapeDataString(StartTime.ToString("yyyy-MM-ddTHH:mm:ssZ")), Uri.EscapeDataString(EndTime.ToString("yyyy-MM-ddTHH:mm:ssZ")), Uri.EscapeDataString(MakeBlobReadSignature(account, StartTime, EndTime, BlobURL, account.Credentials.AccountName, uri.Path))); return uri.ToString(); }



    I hope it helps!!! If you found this post useful, Please "Mark as answer" or "Vote as Helpful"
    Thanks! VIJAY.


    Monday, August 13, 2012 6:09 AM
  • I can reproduce this. Someone from the Windows Azure storage team should investigate... this definitely looks like a bug. Here's my version of the code:

    var container = blobs.GetContainerReference("test");
    container.CreateIfNotExist();
    
    var blob = container.GetBlobReference("/leadingslash");
    Console.WriteLine(blob.Uri.AbsoluteUri);
    blob.UploadText("Hello, World!");
    
    var uri = blob.Uri.AbsoluteUri + blob.GetSharedAccessSignature(new SharedAccessPolicy { Permissions = SharedAccessPermissions.Read, SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromMinutes(5) });
    Console.WriteLine(uri);
    
    try { Console.WriteLine(new WebClient().DownloadString(uri)); }
    catch (WebException e) { Console.WriteLine("ERROR: {0}", new StreamReader(e.Response.GetResponseStream()).ReadToEnd()); }
    

    The error message seems to suggest that the SAS should be computed without the double slash, but this doesn't work. Oddly, if I make the container public and try to use a SAS, it works (and fails if I don't include the double slash).

    FYI, I'm testing against cloud storage. I haven't tried dev storage.

    Monday, August 13, 2012 6:51 AM
  • Thanks for helping confirm the issue and show me that all the SAS can be done in one line of code too!

    var uri = blob.Uri.AbsoluteUri + blob.GetSharedAccessSignature(new SharedAccessPolicy { Permissions = SharedAccessPermissions.Read, SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromMinutes(5) });

    Rob

    Monday, August 13, 2012 4:00 PM