locked
Using the BackgroundDownloader to retrieve private Blobs from Windows Azure Storage

    Question

  • I am attempting to use the BackgroundDownloader to download files to the app after a user makes a purchase in the store.  However, I do not want the URLs that these files are available at to be publicly accessible.

    My current approach is to use the Background downloader to download these files from Azure storage (this seems to be noted as possible at: http://social.msdn.microsoft.com/Forums/windowsapps/en-US/10dbd598-33f9-4bbe-b808-4baea7045d8d/can-we-use-the-backgrounddownloader-to-download-blobs-from-azure-?forum=winappswithcsharp ).

    However, I am getting stuck here -- I am not sure how to access these files using the BackgroundDownloader.  After searching, I think I need to create a Shared Access Signature (SAS) token, which can be appended to the URI to allow the BackgroundDownloader to access the file.  Is this the correct approach?

    Finally, I am having trouble getting out the URI that contain the SAS.  I'm trying to pass it through a StorageBlobBlock first to get this, but it seems to strip out the SAS.  I've pasted my current code below; any help would be greatly appreciated.

    Thanks!

    public async static Task<Uri> GetBlobDownloadUri(string fileName, string containerName)
            {
    
                // The connection string for the storage account.  (Modified for my account).
                string storageConnectionString =
                   "DefaultEndpointsProtocol=https;" +
                   "AccountName=<account>;" +
                   "AccountKey=<key>";
    
                // Create the storage account with the connection string.
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
                // Create the blob client object.
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    
                // Get a reference to the container for which shared access signature will be created.
                CloudBlobContainer container = blobClient.GetContainerReference(containerName);
     
                // Create blob container permissions, consisting of a shared access policy 
                // and a public access setting. 
                BlobContainerPermissions blobPermissions = new BlobContainerPermissions();
    
                // The shared access policy provides 
                // read/write access to the container for 2 hours.
                blobPermissions.SharedAccessPolicies.Add("mypolicy", new SharedAccessBlobPolicy()
                {
                    // To ensure SAS is valid immediately, don’t set start time.
                    // This way, you can avoid failures caused by small clock differences.
                    SharedAccessExpiryTime = DateTime.UtcNow.AddHours(2),
                    Permissions = SharedAccessBlobPermissions.Read
                });
    
                // The public access setting explicitly specifies that 
                // the container is private, so that it can't be accessed anonymously.
                blobPermissions.PublicAccess = BlobContainerPublicAccessType.Off;
    
                // Set the permission policy on the container.
                await container.SetPermissionsAsync(blobPermissions);
    
                // Get the shared access signature to share with users.
                string sasToken =
                   container.GetSharedAccessSignature(new SharedAccessBlobPolicy(), "mypolicy");
    
                //get uri -- by adding to blob?
                Uri blobUri = new Uri("<my azure url>" + containerName + "/" + fileName);
    
                // Create credentials with the SAS token. The SAS token was created in previous example.
                StorageCredentials credentials = new StorageCredentials(sasToken);
    
                // Create a new blob.
                CloudBlockBlob blob = new CloudBlockBlob(blobUri, credentials);
    
                return blob.Uri;
    
    }



    • Edited by RoboMatt Saturday, May 31, 2014 3:02 PM
    Friday, May 30, 2014 2:45 AM

Answers

  • Thanks for the reply, and for the suggestion to use a browser to check the URL -- I had been doing that, but as you surmised my problem was in creating the URL with the token included.  I think I have this figured out, but a full reply to your statements is below.

    If you can get the URL constructed in such a way that it contains the access token (which will authenticate the equest) and then start the HTTP download, then the BackgroundDownloader can download the files without performing any custom authentication.

    That is what I thought -- hence my question of "I think I need to create a Shared Access Signature (SAS) token, which can be appended to the URI to allow the BackgroundDownloader to access the file.  Is this the correct approach?"  It sounds like you are trying to say this is the correct approach, and there is no other way to use BackgroundDownloader.

    Are you even at a point where you have the URL created that will let you do that?

    I was not -- that is why I said "I am having trouble getting out the URI that contains the SAS." However, I have now figured this out myself via the following page: http://gauravmantri.com/2013/02/13/revisiting-windows-azure-shared-access-signature/ .  The following code block now works for me, in case anyone else encounters this problem:

    public async static Task<Uri> GetBlobDownloadUri(string fileName, string containerName)
            {
    
                // The connection string for the storage account.  (Modified for my account).
                string storageConnectionString =
                   "DefaultEndpointsProtocol=https;" +
                   "AccountName=<account>;" +
                   "AccountKey=<key>";
    
                // Create the storage account with the connection string.
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
                // Create the blob client object.
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    
                // Get a reference to the container for which shared access signature will be created.
                CloudBlobContainer container = blobClient.GetContainerReference(containerName);
     
                // Create blob container permissions, consisting of a shared access policy 
                // and a public access setting. 
                BlobContainerPermissions blobPermissions = new BlobContainerPermissions();
    
                // The shared access policy provides 
                // read/write access to the container for 2 hours.
                blobPermissions.SharedAccessPolicies.Add("mypolicy", new SharedAccessBlobPolicy()
                {
                    // To ensure SAS is valid immediately, don’t set start time.
                    // This way, you can avoid failures caused by small clock differences.
                    SharedAccessExpiryTime = DateTime.UtcNow.AddHours(2),
                    Permissions = SharedAccessBlobPermissions.Read
                });
    
                // The public access setting explicitly specifies that 
                // the container is private, so that it can't be accessed anonymously.
                blobPermissions.PublicAccess = BlobContainerPublicAccessType.Off;
    
                // Set the permission policy on the container.
                await container.SetPermissionsAsync(blobPermissions);
    
                // Get the shared access signature to share with users.
                string sasToken =
                   container.GetSharedAccessSignature(new SharedAccessBlobPolicy(), "mypolicy");
    
                // Get and return full URI
                return new Uri(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}{1}", "<myAzureAddress>" + containerName + "/" + fileName, sasToken));
    
    
    }

    However, I still want to know if this is going about the problem the correct way, or if there is a better solution -- that was the core of my question.  As I stated above:

    "I am attempting to use the BackgroundDownloader to download files to the app after a user makes a purchase in the store.  However, I do not want the URLs that these files are available at to be publicly accessible. [Is using] the Background downloader to download these files from Azure storage [by appending a] SAS token [to the URI] the correct approach?"

    Saturday, May 31, 2014 3:19 PM

All replies

  • Let's try to simplify your requirement. The BackgroundDownloader needs a HTTP/HTTPS URL (or FTP protocol) to perform the download operation. If you can get the URL constructed in such a way that it contains the access token (which will authenticate the request) and then start the HTTP download, then the BackgroundDownloader can download the files without performing any custom authentication.

    Are you even at a point where you have the URL created that will let you do that? If you have the URL created that satisfies this, you can try downloading the file using Fiddler tool or even Internet Explorer and see how the download happens.

    If the question is about how to create the URL to download the files from your Azure account, maybe you should ask this question on the Azure forums - about generating the HTTP URL that will let you download files in the background (or using IE).


    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    Saturday, May 31, 2014 12:03 AM
    Moderator
  • Thanks for the reply, and for the suggestion to use a browser to check the URL -- I had been doing that, but as you surmised my problem was in creating the URL with the token included.  I think I have this figured out, but a full reply to your statements is below.

    If you can get the URL constructed in such a way that it contains the access token (which will authenticate the equest) and then start the HTTP download, then the BackgroundDownloader can download the files without performing any custom authentication.

    That is what I thought -- hence my question of "I think I need to create a Shared Access Signature (SAS) token, which can be appended to the URI to allow the BackgroundDownloader to access the file.  Is this the correct approach?"  It sounds like you are trying to say this is the correct approach, and there is no other way to use BackgroundDownloader.

    Are you even at a point where you have the URL created that will let you do that?

    I was not -- that is why I said "I am having trouble getting out the URI that contains the SAS." However, I have now figured this out myself via the following page: http://gauravmantri.com/2013/02/13/revisiting-windows-azure-shared-access-signature/ .  The following code block now works for me, in case anyone else encounters this problem:

    public async static Task<Uri> GetBlobDownloadUri(string fileName, string containerName)
            {
    
                // The connection string for the storage account.  (Modified for my account).
                string storageConnectionString =
                   "DefaultEndpointsProtocol=https;" +
                   "AccountName=<account>;" +
                   "AccountKey=<key>";
    
                // Create the storage account with the connection string.
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
                // Create the blob client object.
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    
                // Get a reference to the container for which shared access signature will be created.
                CloudBlobContainer container = blobClient.GetContainerReference(containerName);
     
                // Create blob container permissions, consisting of a shared access policy 
                // and a public access setting. 
                BlobContainerPermissions blobPermissions = new BlobContainerPermissions();
    
                // The shared access policy provides 
                // read/write access to the container for 2 hours.
                blobPermissions.SharedAccessPolicies.Add("mypolicy", new SharedAccessBlobPolicy()
                {
                    // To ensure SAS is valid immediately, don’t set start time.
                    // This way, you can avoid failures caused by small clock differences.
                    SharedAccessExpiryTime = DateTime.UtcNow.AddHours(2),
                    Permissions = SharedAccessBlobPermissions.Read
                });
    
                // The public access setting explicitly specifies that 
                // the container is private, so that it can't be accessed anonymously.
                blobPermissions.PublicAccess = BlobContainerPublicAccessType.Off;
    
                // Set the permission policy on the container.
                await container.SetPermissionsAsync(blobPermissions);
    
                // Get the shared access signature to share with users.
                string sasToken =
                   container.GetSharedAccessSignature(new SharedAccessBlobPolicy(), "mypolicy");
    
                // Get and return full URI
                return new Uri(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}{1}", "<myAzureAddress>" + containerName + "/" + fileName, sasToken));
    
    
    }

    However, I still want to know if this is going about the problem the correct way, or if there is a better solution -- that was the core of my question.  As I stated above:

    "I am attempting to use the BackgroundDownloader to download files to the app after a user makes a purchase in the store.  However, I do not want the URLs that these files are available at to be publicly accessible. [Is using] the Background downloader to download these files from Azure storage [by appending a] SAS token [to the URI] the correct approach?"

    Saturday, May 31, 2014 3:19 PM
  • The BackgroundDownloader will just download files and report you success or failure. If you want to know whether accessing the files using this type of security tokens appended to the download URL is the right approach or not, I would advise you to repost your question on the Azure forums.

    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    Monday, June 9, 2014 4:56 PM
    Moderator