none
Accessing blobs in private container without Shared Access Secret key

    Question

  • Is there any way to access blobs in private blob container without Shared Access Secret key ? i mean any User / Role based security or domain level security i.e only our domain should be able to access blobs in private container etc.

    Actually i don't want to append SAS key after each blob url to access it, i want my container to be private and also i want to access each blob in that container without SAS key

    any way currently available or planned in future release ?



    Thursday, June 16, 2011 8:23 AM

Answers

  • Hi Yazeem,

    > That main page loads sucessfully but the js, css, xml files which this page accesses are unable to load because SAS key is not appended to their URL automatically.

    If the main page is served by a http handler and the js, css, xml files are linked using relative address, these files will also be served by the http handler too. For example, if the http handler serves a page in address http://xxx.cloudapp.net/blobproxy/index.html and the page links to a script file using tag <script src="myscript.js"></script>, actually the browser will use address http://xxx.cloudapp.net/blobproxy/myscript.js to access the script file. So the solution is to create a http handler to serve all requests to address http://xxx.cloudapp.netb/blobproxy/*.

    For test purpose, I made this sample. Please add a class file BlobProxy.cs to your web role project:

    using System;
    using System.Web;
    using Microsoft.WindowsAzure.StorageClient;
    using Microsoft.WindowsAzure;
    
    namespace WebApplication2
    {
      public class BlobProxy : IHttpHandler
      {
        // Please replace this with your blob container name.
        const string blobContainerName = "files";
    
        public bool IsReusable
        {
          get { return false; }
        }
    
        public void ProcessRequest(HttpContext context)
        {
          // Get the file name.
          string fileName = context.Request.Path.Replace("/blobproxy/", string.Empty);
    
          // Get the blob from blob storage.
          var storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
          var blobStorage = storageAccount.CreateCloudBlobClient();
          string blobAddress = blobContainerName + "/" + fileName;
          CloudBlob blob = blobStorage.GetBlobReference(blobAddress);
    
          // Read blob content to response.
          context.Response.Clear();
          try
          {
            blob.FetchAttributes();
    
            context.Response.ContentType = blob.Properties.ContentType;
            blob.DownloadToStream(context.Response.OutputStream);
          }
          catch (Exception ex)
          {
            context.Response.Write(ex.ToString());
          }
          context.Response.End();
        }
      }
    }
    

    Then please add this http handler to web.config file:

    <configuration>
      <system.webServer>
        <handlers>
          <add name="BlobProxy" verb="*" path="/blobproxy/*" type="WebApplication2.BlobProxy"/>
        </handlers>
      </system.webServer>
    </configuration>
    

    Before running the project, please replace blobContainerName with your own blob container that contains both html and related files. Then start debugging the Azure service project and then you can use the following address to access the page:

    http://127.0.0.1:[port number]/blobproxy/[page name]

    I above sample does not work for you, please let me know.

    Thanks.


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    • Marked as answer by yazeem Saturday, June 25, 2011 5:06 AM
    Friday, June 24, 2011 5:19 AM

All replies

  • Hi Yazeem,

    As for now, Azure Blob Service does not supports User / Role based or domain level access control. If you don't want to SAS key, you may want to create a http handler in a web role to serve these private content. Please refer to a related thread (http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/dbfb9d13-d463-4461-b51f-466261617cb7):

    You can create a http handler to serve and secure files from blob storage. When the browser send a request to your service viahttp://xxx.cloudapp.net/courses/index.html or http://xxx.cloudapp.net/courses/style.css, it will be actually served by your own http handler. The http handler will get the actual file content (no matter it is a html, js or image file) from blob storage and return the content. By using this way, we can protect the http handler using the the built-in ASP.NET authorization and authentication functionality. Or you can use your own way to authenticate users as you have full control of the http handler.

    If you have questions regarding serving blob storage using http handler, please let me know.

    Thanks.


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    Friday, June 17, 2011 2:36 AM
  • Thanks Wengchao Zeng for your reply,

    I have tried both HttpHandler and HttpModule to capture the requests send to azure blob but they capture only incoming request to application.

    How to capture outgoing request to azure blob ?

    Monday, June 20, 2011 5:36 AM
  • Hi Yazeem,

    Thanks for your response.

    May I ask you what you mean by "outgoing request"?

    Thanks,


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    Monday, June 20, 2011 7:25 AM
  • Hi,

    From "outgoing request", i mean to say the request that is send by Web Role application to azure Blob storage.

    I created HttpModule in my WebRole application, whenever i access any page in my application, i captures page requests and its associated data requests like requests for css, javascripts, images etc.

    But if i access azure blob data in event of a button , HttpModule only captures the event request. It does not capture the request it (webRole) makes to blob storage.

     

    Monday, June 20, 2011 10:18 AM
  • You'll have to have the requests served by your application and use that as a proxy for the data in blob storage.

    Eg the request comes into the application, the application pulls the data from blob storage and sends it back to the client

    Monday, June 20, 2011 3:15 PM
  • Hi Yazeem,

    If I understood correctly, it seems that you have met your original requirement "accessing blobs in private blob container without Shared Access Secret key". Now the question becomes that you want to capture the request when the web role accesses blob storage.

    HttpModule is used to capture the request to pages, not the outgoing request. Why do you want to capture the outgoing request? As the outgoing request is made by your code, you can implement access control in your own code before accessing blob storage.

    Thanks,


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    Tuesday, June 21, 2011 6:35 AM
  • Hello Wengchao Zeng,

    Thanks for your help.

    Actually i have stored eLearning courses on Blob storage, each container will be a course, all items of that course (xml,, Js, css, images etc.) are stored in that container as Block blob.

    This container is private and can be accessed by SAS key. When i send a request to main page of course with SAS key appended at the end of its url.

    That main page loads sucessfully but the js, css, xml files which this page accesses are unable to load because SAS key is not appended to their URL automatically.

    HttpModule does not capture the request made to resources like js,xml, etc which course wants to load. we only access the main page of that course and rest items will be loaded / unloaded by course.

    That's the reason why i am asking that whether there is any other mechanism like User / Role based security or domain level security.


    Wednesday, June 22, 2011 7:27 AM
  • Is it necessary to store the other content in private storage? 
    Thursday, June 23, 2011 1:48 PM
  • Hi Yazeem,

    > That main page loads sucessfully but the js, css, xml files which this page accesses are unable to load because SAS key is not appended to their URL automatically.

    If the main page is served by a http handler and the js, css, xml files are linked using relative address, these files will also be served by the http handler too. For example, if the http handler serves a page in address http://xxx.cloudapp.net/blobproxy/index.html and the page links to a script file using tag <script src="myscript.js"></script>, actually the browser will use address http://xxx.cloudapp.net/blobproxy/myscript.js to access the script file. So the solution is to create a http handler to serve all requests to address http://xxx.cloudapp.netb/blobproxy/*.

    For test purpose, I made this sample. Please add a class file BlobProxy.cs to your web role project:

    using System;
    using System.Web;
    using Microsoft.WindowsAzure.StorageClient;
    using Microsoft.WindowsAzure;
    
    namespace WebApplication2
    {
      public class BlobProxy : IHttpHandler
      {
        // Please replace this with your blob container name.
        const string blobContainerName = "files";
    
        public bool IsReusable
        {
          get { return false; }
        }
    
        public void ProcessRequest(HttpContext context)
        {
          // Get the file name.
          string fileName = context.Request.Path.Replace("/blobproxy/", string.Empty);
    
          // Get the blob from blob storage.
          var storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
          var blobStorage = storageAccount.CreateCloudBlobClient();
          string blobAddress = blobContainerName + "/" + fileName;
          CloudBlob blob = blobStorage.GetBlobReference(blobAddress);
    
          // Read blob content to response.
          context.Response.Clear();
          try
          {
            blob.FetchAttributes();
    
            context.Response.ContentType = blob.Properties.ContentType;
            blob.DownloadToStream(context.Response.OutputStream);
          }
          catch (Exception ex)
          {
            context.Response.Write(ex.ToString());
          }
          context.Response.End();
        }
      }
    }
    

    Then please add this http handler to web.config file:

    <configuration>
      <system.webServer>
        <handlers>
          <add name="BlobProxy" verb="*" path="/blobproxy/*" type="WebApplication2.BlobProxy"/>
        </handlers>
      </system.webServer>
    </configuration>
    

    Before running the project, please replace blobContainerName with your own blob container that contains both html and related files. Then start debugging the Azure service project and then you can use the following address to access the page:

    http://127.0.0.1:[port number]/blobproxy/[page name]

    I above sample does not work for you, please let me know.

    Thanks.


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    • Marked as answer by yazeem Saturday, June 25, 2011 5:06 AM
    Friday, June 24, 2011 5:19 AM
  • Thanks a lot Wengchao Zeng for your help. Its working great :)

    Saturday, June 25, 2011 5:06 AM
  • Hey Wengchao,

     

    I dont seem to get the  required result with the above code. Here is what I have done to access the .xml file that is stored in blob.


    Imports System.Web
    Imports Microsoft.WindowsAzure.StorageClient
    Imports Microsoft.WindowsAzure

    Namespace WebApplication
        Public Class BlobProxy
            Implements IHttpHandler
            ' Please replace this with your blob container name.
            Const blobContainerName As String = "eldata"

            Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
                Get
                    Return False
                End Get
            End Property

            Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
                ' Get the file name.
                Dim fileName As String = context.Request.Path.Replace("/BlobProxy/", String.Empty)

                ' Get the blob from blob storage.
                Dim storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString")
                Dim blobStorage = storageAccount.CreateCloudBlobClient
                Dim blobAddress As String = blobContainerName & "/" & fileName
                Dim blob As CloudBlob = blobStorage.GetBlobReference(blobAddress)
                Dim bool As Boolean = EL_ComFun.BlobExists(blob)

                ' Read blob content to response.
                context.Response.Clear()
                Try
                    blob.FetchAttributes()
                    context.Response.ContentType = blob.Properties.ContentType
                    blob.DownloadToStream(context.Response.OutputStream)
                Catch ex As Exception
                    context.Response.Write(ex.ToString())
                End Try
                context.Response.[End]()
            End Sub
        End Class
    End Namespace


    ------------------------------------------------------------------------------------------------

    and after this i try to access the xml file in an aspx page by providing the link

    dim str as String = "http://593b7d2f4e754850a34dd48167619f0a.cloudapp.net/BlobProxy/DicFiles/L5_CD1/9MGAA2_E/9MGAA2.xml"

    ds.ReadXml(flnmXML)

    This reading of xml file throws an error "The remote server returned an error: (500) Internal Server Error."

    I also want to know where to reference the class file that i created (BlobProxy.vb)

    Where am I going wrong? Could you please correct me to solve this problem ?

     

    Regards

    Sandeep

     

     

     

    Friday, August 05, 2011 11:32 AM
  • Hi Wengchao Zeng,

    The solution you suggested worked for me also, the downside when using this solution is that the traffic passes through the server also. Do you think there is another solution that could avoid this? What about using ARR (IIS Application Request Routing)?

    Thanks,

    Cornel

    Tuesday, August 05, 2014 8:31 AM