Search code examples
javaazureazure-storagesignature

Azure File share SAS token signature not generating as expected, How do one generate signature for file object to match the one generated in portal?


I am trying to create a signature for SAS token programmatically which should match with the one generated in the azure portal when a user selects few options. However the documentation is so confusing and doesn't guide you to achieve what is needed for the action. I have a file in azure file share and I want to access it by generating SAS token and sign it. I can easily do it by selecting the appropriate options in Azure portal and access the file, but I want to do the exact thing programmatically. I tried by java but the resulted SAS token signature doesn't match. Please help me.

Below is the SAS token when I generate it through Azure Portal:

?sv=2019-12-12&ss=f&srt=o&sp=r&se=2020-11-23T12:20:39Z&st=2020-11-23T04:20:39Z&spr=https&sig=XI%2FlSZSXp54XVwk2G%2F23j%2FjqsrojVqJoAonh6gdaAPk%3D

The corresponding options selected in azure portal for above sas token is as follows as shown in below image enter image description here

The key used is key1 and is as follows:

l1wxekiJj9IcTw350w5c1MtVfYVP3qcz3zdxzCCp+YVaXqs9faOJfl/Z07AoLDnsnyn+POGjxjcFy3EF9g/r9Q==

What I tried is to generate a signature for the below options(String to Sign) as taken from the generated SAS token by azure portal and using the key1 above.

sv=2019-12-12&ss=f&srt=o&sp=r&se=2020-11-23T12:20:39Z&st=2020-11-23T04:20:39Z&spr=https

Below is my java code which generates the signature for the above string to sign

import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
public class GenerateSAS {
    public static void main(String[] args) throws Exception{
        Mac sha256_HMAC = null;
        String hash = null;
        String input="sv=2019-12-12&ss=f&srt=o&sp=r&se=2020-11-23T12:20:39Z&st=2020-11-23T04:20:39Z&spr=https";
        input=URLEncoder.encode(input, "UTF-8");
        String key="l1wxekiJj9IcTw350w5c1MtVfYVP3qcz3zdxzCCp+YVaXqs9faOJfl/Z07AoLDnsnyn+POGjxjcFy3EF9g/r9Q==";
        sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        hash = new String(Base64.encodeBase64(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
        System.out.println(hash);
    }

The above code generates signature which is MK/uu+NlURscoX1dymzipRN/Jb4aXyVzfbIVBz8l02M= and this is not equal to what was generated in the azure portal, which was XI%2FlSZSXp54XVwk2G%2F23j%2FjqsrojVqJoAonh6gdaAPk%3D

Please help me to generate the signature correctly which shall help me append it to SAS token for file object access.


Solution

  • If you want to create sas token to access Azure file service resource, the signature string should be like as below. For more details, please refer to here

    StringToSign = accountname + "\n" +  
        signedpermissions + "\n" +  
        signedservice + "\n" +  
        signedresourcetype + "\n" +  
        signedstart + "\n" +  
        signedexpiry + "\n" +  
        signedIP + "\n" +  
        signedProtocol + "\n" +  
        signedversion + "\n"  
    

    For example

     public static void createSasToken(){
    
        String accountName = "accountName";
        String key = "accountKey";
        String resourceUrl = "https://"+accountName+".file.core.windows.net/fileShare/fileName";
        /**
         * please note the date formate should be  ISO 8601 UTC formats 
         * for further information, please refer to https://learn.microsoft.com/en-us/rest/api/storageservices/formatting-datetime-values
        */
        String start = "startTime";
        String expiry = "expiry";
        String apiVersion = "2019-12-12";
    
        String stringToSign = accountName + "\n" +
                    "r\n" +
                    "f\n" +
                    "o\n" +
                    start + "\n" +
                    expiry + "\n" +
                    "\n" +
                    "https\n" +
                    apiVersion +"\n";
    
        String signature = getHMAC256(key, stringToSign);
    
        try{
    
            String sasToken = "sv=" + azureApiVersion +
                "&ss=f" +
                "&srt=o" +
                "&sp=r" +
                "&se=" +URLEncoder.encode(expiry, "UTF-8") +
                "&st=" + URLEncoder.encode(start, "UTF-8") +
                "&spr=https" +
                "&sig=" + URLEncoder.encode(signature, "UTF-8");
    
        System.out.println(resourceUrl+"?"+sasToken);
    
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
    
    private static String getHMAC256(String accountKey, String signStr) {
        String signature = null;
        try {
            SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(accountKey), "HmacSHA256");
            Mac sha256HMAC = Mac.getInstance("HmacSHA256");
            sha256HMAC.init(secretKey);
            signature = Base64.getEncoder().encodeToString(sha256HMAC.doFinal(signStr.getBytes("UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return signature;
    }