Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No 'Access-Control-Allow-Origin' header is present on the requested resource while uploading to Azure Blob

I've been struggling with this for about a day now. I am testing direct to Azure Blob storage upload and getting the dreaded CORS issue. "XMLHttpRequest cannot load https://tempodevelop.blob.core.windows.net/tmp/a4d8e867-f13e-343f-c6d3-a603…Ym0PlrBn%2BU/UzUs7QUhQw%3D&sv=2014-02-14&se=2016-10-12T17%3A59%3A26.638531. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 403."

Things I have already tried:

  1. set the CORS to all hosts: enter image description here
  2. tried hosting my app locally and on heroku
  3. made sure that I could upload a file using a different tool (Azure Storage Explorer)
  4. configured my AccessPolicy to 'rwdl' and I am definitely getting an access signature (verified in unit tests).

The code as a whole is available here: https://github.com/mikebz/azureupload

But the relevant parts are here, front end upload:

<script>

    /* 
     * not a true GUID, see here: http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
     */ 
    function guid() {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000)
            .toString(16)
            .substring(1);
        }
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
            s4() + '-' + s4() + s4() + s4();
    }

    function startUpload() {   
        var fileName = guid();

        jQuery.getJSON("/formfileupload/signature/" + fileName , function(data) {
                console.log("got a signature: " + data.bloburl);
                uploadFile(data.bloburl, data.signature);
            })
            .fail(function(jqxhr, textStatus, error) {
                console.log( "error: " + textStatus + " - " + error );
            })
    }
    
    function uploadFile(bloburl, signature) {        
        var xhr = new XMLHttpRequest();
        fileData = document.getElementById('fileToUpload').files[0];
        xhr.open("PUT", bloburl + "?" + signature);
        xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
        xhr.setRequestHeader('x-ms-blob-content-type', fileData.type);
        result = xhr.send(fileData);
    }
</script>

The signature generation code in python is here:

def generate_access_signature(self, filename):
    """
    calls the Azure Web service to generate a temporary access signature.
    """
    blob_service = BlobService(
        account_name=self.account_name, 
        account_key=self.account_key
    )

    expire_at = datetime.utcnow()
    expire_at = expire_at + timedelta(seconds = 30)
    access_policy = AccessPolicy(permission="rwdl", expiry=expire_at.isoformat())

    sas_token = blob_service.generate_shared_access_signature( 
        container_name="tmp",
        blob_name = filename, 
        shared_access_policy=SharedAccessPolicy(access_policy)
    )
    return sas_token
like image 211
mikebz Avatar asked Oct 12 '16 18:10

mikebz


2 Answers

According to the error message [The response had HTTP status code 403], it may be the CORS is not enabled for the service or no CORS rules matches the preflight request. Detail Please refer to the Cross-Origin Resource Sharing (CORS) Support for the Azure Storage Services. Or it may be the SAS signature incorrect. Please have a try to troubleshoot

  1. try to check the CORS setting on the Azure Portal under the Blob Service. As there are other services like table, queue, file. Expected

  2. Also Azure explore tools you can use to generate the SAS token enter image description here

Get the SAS and try to debug it with the generated SAS demo code enter image description here

like image 182
Tom Sun - MSFT Avatar answered Oct 20 '22 08:10

Tom Sun - MSFT


Thanks to Tom and Microsoft's support the issue has been resolved.
Solution part #1 - make sure you use the Azure Storage Library for Python version 0.33 or later.

Here is my requirements file:

azure-common==1.1.4
azure-nspkg==1.0.0
azure-storage==0.33.0
cffi==1.8.3
cryptography==1.5.2
dj-database-url==0.4.1
Django==1.10.2
enum34==1.1.6
futures==3.0.5
gunicorn==19.6.0
idna==2.1
ipaddress==1.0.17
pep8==1.7.0
psycopg2==2.6.2
pyasn1==0.1.9
pycparser==2.16
python-dateutil==2.5.3
requests==2.11.1
six==1.10.0
whitenoise==3.2.2

Second issue is generating the signature. The code that generates the right signature is here:

from azure.storage.blob import BlockBlobService, ContainerPermissions
from datetime import datetime, timedelta


class AzureUtils:

    def __init__(self, account_name, account_key):
        if account_name is None:
            raise ValueError("account_name should not be None")
        if account_key is None:
            raise ValueError("account_key should not be None")
        self.account_name = account_name
        self.account_key = account_key

    def generate_access_signature(self, filename):
        """
        calls the Azure Web service to generate a temporary access signature.
        """
        block_blob_service = BlockBlobService(
            account_name=self.account_name,
            account_key=self.account_key
        )

        expire_at = datetime.utcnow()
        expire_at = expire_at + timedelta(seconds=30)

        permissions = ContainerPermissions.READ | ContainerPermissions.WRITE | ContainerPermissions.DELETE | ContainerPermissions.LIST

        sas_token = block_blob_service.generate_container_shared_access_signature(
                "tmp",
                permission=permissions,
                expiry=expire_at
        )

        return sas_token

The solution can also be retrieved here: https://github.com/mikebz/azureupload

like image 1
mikebz Avatar answered Oct 20 '22 10:10

mikebz