6

I have created several containers in a azure storage and also uploaded some files into these containers. Now I need to give domain level access to the container/blobs. So I tried it from code level like below.

        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
        CloudConfigurationManager.GetSetting("StorageConnectionString"));

        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        ServiceProperties blobServiceProperties = new ServiceProperties();
            blobServiceProperties.Cors.CorsRules.Add(new CorsRule(){
                AllowedHeaders = new List<string>() {"*"},
                ExposedHeaders = new List<string>() {"*"},
                AllowedMethods = CorsHttpMethods.Post | CorsHttpMethods.Put | CorsHttpMethods.Get | CorsHttpMethods.Delete ,
                AllowedOrigins = new List<string>() { "http://localhost:8080/"},
                MaxAgeInSeconds = 3600,
            });

          blobClient.SetServiceProperties(GetBlobServiceProperties());  

But above code seems to be work if I am creating everything from code (Correct me if I am wrong). I also find setting like below Here,

 <CorsRule>
  <AllowedOrigins>http://www.contoso.com, http://www.fabrikam.com</AllowedOrigins>
  <AllowedMethods>PUT,GET</AllowedMethods>
  <AllowedHeaders>x-ms-meta-data*,x-ms-meta-target,x-ms-meta-source</AllowedHeaders>
  <ExposedHeaders>x-ms-meta-*</ExposedHeaders>
  <MaxAgeInSeconds>200</MaxAgeInSeconds>
</CorsRule>

But I didn't get where this code have to put. I mean in which file. Or is there any setting for CORS while creating container or blob from azure portal. Please assist. Any help would be appreciable. Thanks!

Nicholas Petersen
  • 9,104
  • 7
  • 59
  • 69
Rajaram Shelar
  • 7,537
  • 24
  • 66
  • 107

3 Answers3

12

The following answers the question that was actually asked in the title. It appears the questioner already knew how to do this largely from his code, but here is my answer to this. Unfortunately the code samples MS has put out has been far from easy or clear, so I hope this helps someone else. In this solution all you need is a CloudStorageAccount instance, which you can call this function from then (as an extension method).

// USAGE:

        // -- example usage (in this case adding a wildcard CORS rule to this account --

        CloudStorageAccount acc = getYourStorageAccount();

        acc.SetCORSPropertiesOnBlobService(cors => {
            var wildcardRule = new CorsRule() { AllowedMethods = CorsHttpMethods.Get, AllowedOrigins = { "*" } };
            cors.CorsRules.Add(wildcardRule);
            return cors;
        });

// CODE:

    /// <summary>
    /// Allows caller to replace or alter the current CorsProperties on a given CloudStorageAccount.
    /// </summary>
    /// <param name="storageAccount">Storage account.</param>
    /// <param name="alterCorsRules">The returned value will replace the 
    /// current ServiceProperties.Cors (ServiceProperties) value. </param>
    public static void SetCORSPropertiesOnBlobService(this CloudStorageAccount storageAccount,
        Func<CorsProperties, CorsProperties> alterCorsRules)
    {
        if (storageAccount == null || alterCorsRules == null) throw new ArgumentNullException();

        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        ServiceProperties serviceProperties = blobClient.GetServiceProperties();

        serviceProperties.Cors = alterCorsRules(serviceProperties.Cors) ?? new CorsProperties();

        blobClient.SetServiceProperties(serviceProperties);
    }

It may be helpful to consider the properties of the CorsRule class:

        CorsRule corsRule = new CorsRule() {
            AllowedMethods = CorsHttpMethods.Get,       // Gets or sets the HTTP methods permitted to execute for this origin
            AllowedOrigins = { "*" },                   // (IList<string>) Gets or sets domain names allowed via CORS.
            //AllowedHeaders = { "*" },                 // (IList<string>) Gets or sets headers allowed to be part of the CORS request
            //ExposedHeaders = null,                    // (IList<string>) Gets or sets response headers that should be exposed to client via CORS
            //MaxAgeInSeconds = 33333                   // Gets or sets the length of time in seconds that a preflight response should be cached by browser
        };
Nicholas Petersen
  • 9,104
  • 7
  • 59
  • 69
4

Let me try to answer your question. As you know, Azure Storage offers a REST API for managing storage contents. An operation there is Set Blob Service Properties and one of the things you do there is manage CORS rules for blob service. The XML you have included in the question is the request payload for this operation. The C# code you mentioned is actually storage client library which is essentially a wrapper over this REST API written in .Net. So when you use the code above, it actually invokes the REST API and sends the XML.

Now coming to options on setting up CORS rules, there're a few ways you can achieve that. If you're interested in setting them up programmatically, then you can either write some code which consumes the REST API or you could directly use .Net storage client library as you have done above. You could simply create a console application, put the code in there and execute that to set the CORS rule. If you're looking for some tools to do that, then you can try one of the following tools:

Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • Thanks for response. I have put C# code in the global.asax application_start event and try to set CORS rule for particular container. But when I tried to access any particular URL from browser, it was downloading this file, that means CORS logic is not working. Can you suggest how to implement this. – Rajaram Shelar Feb 20 '15 at 13:31
  • I'm confused now :P. CORS is useful when you want to access or invoke REST API using JavaScript. If I'm not mistaken you're more interested in restricting access to container. Am I correct? – Gaurav Mantri Feb 20 '15 at 14:16
  • @ Gaurav Mantri : Yes.. you got me.. I need exactly what you say – Rajaram Shelar Feb 20 '15 at 14:37
  • What you need to do is change the container ACL to Private if you don't want anybody else to directly download the blob by typing blob url. This I believe you can do on the portal itself. – Gaurav Mantri Feb 20 '15 at 15:25
  • Yeah. I did this. But I want to get blob images from image src. If i make it private then they are not accessible. Can we have something like allowing blob storage for the request coming from particular domain(my webisite)? – Rajaram Shelar Feb 21 '15 at 10:13
  • Sorry to push this but where would I open a console and enter those commands in for example Azure Storage Explorer (version 6 preview 3)? – Andreas Galster Mar 25 '15 at 06:38
-1

Its not a good idea to give domain level access to your containers. You can make the container private, upload the files (create blob) and then share it by using Shared Access Policy.

The below code can help you.

static void Main(string[] args)
        {
            var account = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorageAccount"].ConnectionString);
            var bClient = account.CreateCloudBlobClient();
            var container = bClient.GetContainerReference("test-share-container-1");
            container.CreateIfNotExists();

            // clear all existing policy
            ClearPolicy(container);

            string newPolicy = "blobsharepolicy";
            CreateSharedAccessPolicyForBlob(container, newPolicy);
            var bUri = BlobUriWithNewPolicy(container, newPolicy);

            Console.ReadLine();
        }

        static void ClearPolicy(CloudBlobContainer container)
        {
            var perms = container.GetPermissions();
            perms.SharedAccessPolicies.Clear();
            container.SetPermissions(perms);
        }       

        static string BlobUriWithNewPolicy(CloudBlobContainer container, string policyName)
        {
            var blob = container.GetBlockBlobReference("testfile1.txt");
            string blobContent = "Hello there !!";
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(blobContent));
            ms.Position = 0;
            using (ms)
            {
                blob.UploadFromStream(ms);
            }

            return blob.Uri + blob.GetSharedAccessSignature(null, policyName);
        }

        static void CreateSharedAccessPolicyForBlob(CloudBlobContainer container, string policyName)
        {
            SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
            {
                SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
                Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
            };
            var permissions = container.GetPermissions();            
            permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
            container.SetPermissions(permissions);
        }


<connectionStrings>
    <add name="AzureStorageAccount" connectionString="DefaultEndpointsProtocol=https;AccountName=[name];AccountKey=[key]" />
  </connectionStrings>
Pramod
  • 72
  • 3