azuretokenazure-storageazure-file-share

Error when python program reads a file from an Azure fileshare: "Signature did not match. String to sign used was r..."


I have written the following Python code to generate a SAS token for a file placed in an Azure file share directory:

def getParcelFilePath(webcountyval):
    filePath = rf"/plan/IN/{webcountyval}%20parcels.dbf"
    file_sas_token = generate_file_sas(
       account_name=os.environ["AZURE_STORAGE_ACCOUNT_NAME"],
       account_key=os.environ["AZURE_STORAGE_ACCOUNT_KEY"],
       share_name="dev",
       file_path=filePath,
       permission=AccountSasPermissions(read=True),
       expiry=datetime.datetime.now() + datetime.timedelta(hours=8),
       start=datetime.datetime.now()
     )

     filePathWithToken = os.environ["AZURE_STORAGE_SHARE_URL"] + filePath + "?" + file_sas_token
     return(filePathWithToken)

I live in the Central time zone. To ensure that the authentication does not fail, you can see that I have passed 8 hours to the timedelta() function.

The following URL is generated for the file: https://crestlinecapitalstorage.file.core.windows.net/dev/plan/IN/elkhart%20parcels.dbf?st=2024-11-11T23%3A14%3A30Z&se=2024-11-12T07%3A14%3A30Z&sp=r&sv=2024-11-04&sr=f&sig=[redacted_sig]

When I paste this URL into the browser, it shows the following error: Signature did not match. String to sign used was r 2024-11-11T23:14:30Z 2024-11-12T07:14:30Z /file/crestlinecapitalstorage/dev/plan/IN/elkhart parcels.dbf 2024-11-04

What could be the reason for the error?


Solution

  • It is quite possible that the file_path value “/plan/in/{webcountyval}%20parcels.dbf” was incorrect. The extra ‘/’ at the beginning may not be needed. Anyway, instead of spending any more nightmarish moments trying to get the URL with a SAS token to work, I found a workaround, which is easier to work with and maintain (see AI Overview provided by Google search).

    Here's the final code:

    def getFileClient(stateval, webcountyval):
        filePath = rf"plan/{stateval}/{webcountyval} parcels.dbf"
        accountKey = os.environ["AZURE_STORAGE_ACCOUNT_KEY"]
        shareName = "dev"
    
        # Create a ShareClient object
        shareClient = ShareClient(
            account_url=os.environ["AZURE_STORAGE_ACCOUNT_URL"],
            credential=accountKey,
            share_name=shareName
        )
    
        # Get a reference to the file
        fileClient = shareClient.get_file_client(filePath)
        return(fileClient)
    
    def parcelDBFDataSave(parcelFileClient):
    
      # Download the file
      fileContent = parcelFileClient.download_file().readall()
      with tempfile.NamedTemporaryFile(delete=False) as tempParcelFile:
        tempParcelFile.write(fileContent)
        tempParcelFileName = tempParcelFile.name
    
      # Read the first five records 
      with DBF(tempParcelFileName) as dbfRecords:
        i = 0
        for record in dbfRecords:
            logging.info(record)
            i += 1
            if i > 5: break
    
      return(SUCCESS)
    
    ccParcelFileClient = getFileClient(stateabbr, webCounty)
    result = parcelDBFDataSave(ccParcelFileClient)