0
votes

I want to generate SAS Token, as per the Azure Doc following is the example for BLOB. I am still getting error. Can you please identify what is the mistake I am doing.

StringToSign = signedpermissions + "\n" +  
               signedstart + "\n" +  
               signedexpiry + "\n" +  
               canonicalizedresource + "\n" +  
               signedidentifier + "\n" +  
               signedIP + "\n" +  
               signedProtocol + "\n" +  
               signedversion + "\n" +  
               rscc + "\n" +  
               rscd + "\n" +  
               rsce + "\n" +  
               rscl + "\n" +  
               rsct

URL = https://myaccount.blob.core.windows.net/mycontainer/test.txt
canonicalizedresource = "/blob/myaccount/mycontainer/test.txt

I am getting following error

<?xml version="1.0" encoding="utf-8"?>
<Error>
    <Code>AuthenticationFailed</Code>
    <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:4b1d1c59-c01e-0052-0197-ffe09f000000
Time:2020-03-21T15:44:34.2757923Z</Message>
    <AuthenticationErrorDetail>Signature fields not well formed.</AuthenticationErrorDetail>
</Error>  

Following is my code

public void getSasToken() {

    this.storageName = 'zaindevtesting';
    this.storageContainer = 'zaindevblob';
    this.storageKey = 'xxxxxxZFQ==';
    this.storageUrl ='https://zaindevtesting.blob.core.windows.net';

    Datetime sasExpiry = Datetime.now();
    sasExpiry.addMinutes(15);
    Datetime sasStart = Datetime.now();
    sasStart.addMinutes(-5);


    string signedpermissions = 'rwdlac';
    String signedstart = sasStart.formatGMT('YYYY-MM-dd\'T\'HH:mm:ss\'Z\'');
    string signedexpiry = sasExpiry.formatGMT('YYYY-MM-dd\'T\'HH:mm:ss\'Z\'');
    string signedservice = 'b';
    String canonicalizedresource = '/blob/zaindevtesting/zaindevblob/test.txt';
    string signedidentifier = '';
    string signedIP = '';
    string signedProtocol = 'https';
    string signedversion = '2015-04-05';
    string rscc='';
    string rscd='';
    string rsce='';
    string rscl='';
    string rsct='';


    string stringToSign =signedpermissions + '\n' +  
               signedstart + '\n' +  
               signedexpiry + '\n' +  
               canonicalizedresource + '\n' +  
               signedidentifier + '\n' +  
               signedIP + '\n' +  
               signedProtocol + '\n' +  
               signedversion + '\n' +  
               rscc + '\n' +  
               rscd + '\n' +  
               rsce + '\n' +  
               rscl + '\n' +  
               rsct;

    string signedExpiryEncode = EncodingUtil.urlEncode(signedexpiry, 'UTF-8'); 
    string signedStartEncode = EncodingUtil.urlEncode(signedstart, 'UTF-8'); 
    String sasToken = '';
    Blob unicodeKey = EncodingUtil.base64Decode(storageKey);
    Blob data = Crypto.generateMac('HMACSHA256', Blob.valueOf(stringToSign), unicodeKey);
    sasToken = EncodingUtil.base64Encode(data);
    String sasTokenString= '?sv=' + signedversion + '&se=' + signedexpiry +'&st='+signedstart+'&sr='+signedservice+'&sp=' + signedpermissions + '&sig=' + sasToken;

    string sasURL = 'https://zaindevtesting.blob.core.windows.net/test.txt'+sasTokenString;
    System.debug('sasURL--->'+sasURL);
    System.debug(sasTokenString);
   // return sasToken;
}

This code generate following SAS Link

https://zaindevtesting.blob.core.windows.net/test.txt??sv=2017-11-09&st=2020-03-21T15%3A44%3A07Z&se=2020-03-21T15%3A44%3A07Z&sr=b&sp=rwdc&sig=eJVbGWI4rcyjggOYAE308ilXEA/zAsFYbuNi24IZhX4=

1

1 Answers

0
votes

Please try the following code:

public void generateSASToken()
{
    string storageName = 'zaindevtesting';
    string storageContainer = 'zaindevblob';
    string storageKey = 'xxxx==';
    string storageUrl ='https://zaindevtesting.blob.core.windows.net';

    Datetime sasExpiry = Datetime.now();
    sasExpiry = sasExpiry.addMinutes(15);
    Datetime sasStart = Datetime.now();
    sasStart = sasStart.addMinutes(-5);


    string signedpermissions = 'r';
    String signedstart = sasStart.formatGMT('YYYY-MM-dd\'T\'HH:mm:ss\'Z\'');
    string signedexpiry = sasExpiry.formatGMT('YYYY-MM-dd\'T\'HH:mm:ss\'Z\'');
    string signedservice = 'b';
    String canonicalizedresource = '/blob/zaindevtesting/zaindevblob/test.txt';
    string signedidentifier = '';
    string signedIP = '';
    string signedProtocol = '';
    string signedversion = '2015-04-05';
    string rscc='';
    string rscd='';
    string rsce='';
    string rscl='';
    string rsct='';


    string stringToSign =signedpermissions + '\n' +  
        signedstart + '\n' +  
        signedexpiry + '\n' +  
        canonicalizedresource + '\n' +  
        signedidentifier + '\n' +  
        signedIP + '\n' +  
        signedProtocol + '\n' +  
        signedversion + '\n' +  
        rscc + '\n' +  
        rscd + '\n' +  
        rsce + '\n' +  
        rscl + '\n' +  
        rsct;
    System.debug('stringToSign--->'+stringToSign);
    string signedExpiryEncode = EncodingUtil.urlEncode(signedexpiry, 'UTF-8'); 
    string signedStartEncode = EncodingUtil.urlEncode(signedstart, 'UTF-8'); 
    String sasToken = '';
    Blob unicodeKey = EncodingUtil.base64Decode(storageKey);
    Blob data = Crypto.generateMac('HMACSHA256', Blob.valueOf(stringToSign), unicodeKey);
    sasToken = EncodingUtil.base64Encode(data);
    sasToken = EncodingUtil.urlEncode(sasToken, 'UTF-8');        
    String sasTokenString= '?sv=' + signedversion + '&se=' + signedexpiry +'&st='+signedstart+'&sr='+signedservice+'&sp=' + signedpermissions + '&sig=' + sasToken;

    string sasURL = 'https://zaindevtesting.blob.core.windows.net/zaindevblob/test.txt'+sasTokenString;
    System.debug('sasURL--->'+sasURL);
    System.debug(sasTokenString);
    // return sasToken;
}

I just tried it with your storage account key and I was able to download the blob.

Found the following issues with your code:

  • Permissions has to be in specific order. You're using string signedpermissions = 'rwdlac'; which is not the correct order. I just specified the read permission.
  • Signed Protocol was specified in stringToString but was not included in the SAS URL. I omitted that from both places.
  • SAS Token was not URL encoded.
  • You generated SAS Token for zaindevtesting.blob.core.windows.net/zaindevblob/test.txt URL but forgot to include the blob container name in the final URL.