Sunday, August 23, 2015

How to generate a SharedAccessSignature for the Azure Queue REST API

import java.nio.charset.StandardCharsets;
import java.util.Calendar;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.mule.modules.microsoftservicebus.utils.ServiceBusUtils;
import org.mule.util.Base64;

/**
 * RESTful calls to an Azure Queue Service must be authorized. This class
 * generates a SharedAccessSignature that can be used as the Authorization
 * header of the REST call.
 * <p>
 * Example - View all the queues
 * <pre>
 * GET /$Resources/Queues?api-version=2015-01 HTTP/1.1
 * Host: MY_NAMESPACE.servicebus.windows.net
 * Authorization: SharedAccessSignature sr=https://MY_NAMESPACE.servicebus.windows.net&sig=OfdrmxrugTKQA240Zi59u9vxmQx88NPzf%2besFuqTVM4%3d&se=1440367081&skn=RootManageSharedAccessKey
 * </pre>
 * <p>
 * Example - View the messages on a queue
 * <pre>
 * GET /intervals/messages?api-version=2015-01 HTTP/1.1
 * Host: MY_NAMESPACE.servicebus.windows.net
 * Authorization: SharedAccessSignature sr=https://MY_NAMESPACE.servicebus.windows.net&sig=OfdrmxrugTKQA240Zi59u9vxmQx88NPzf%2besFuqTVM4%3d&se=1440367081&skn=RootManageSharedAccessKey
 * </pre>
 * <p>
 * Example - View the messages on a queue's DeadLetterQueue
 * <pre>
 * GET /intervals/$DeadLetterQueue/messages?api-version=2015-01 HTTP/1.1
 * Host: MY_NAMESPACE.servicebus.windows.net
 * Authorization: SharedAccessSignature sr=https://MY_NAMESPACE.servicebus.windows.net&sig=OfdrmxrugTKQA240Zi59u9vxmQx88NPzf%2besFuqTVM4%3d&se=1440367081&skn=RootManageSharedAccessKey
 * </pre>
 *
 */
public class RestApiUtil {

       public static String generateSharedAccessSignature(String url, String keyName, String key) throws Exception {
             String sasToken = "";

             String encodedUrl = ServiceBusUtils.urlEncodeLowerCase(url);
             Calendar calendar = Calendar.getInstance();
             calendar.add(Calendar.HOUR, 1);
             Long expiry = Long.valueOf(calendar.getTimeInMillis() / 1000L);
             String stringToSign = (new StringBuilder()).append(encodedUrl).append("\n").append(expiry).toString();

             Mac mac = Mac.getInstance("HmacSHA256");
             SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
             mac.init(signingKey);

             String signature = Base64.encodeBytes(mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)));

             sasToken = String.format("SharedAccessSignature sr=%s&sig=%s&se=%s&skn=%s", new Object[] { encodedUrl,
                           ServiceBusUtils.urlEncodeLowerCase(signature), expiry, keyName });

             return sasToken;
       }

       public static void main(String... args) throws Exception {

             String url = "https://MY_NAMESPACE.servicebus.windows.net";
             String keyName = "RootManageSharedAccessKey";
             String key = "2ZOcYrXxx/H33+LyhxJQ24yKkW4+zw6KY6w90z+p+4k=";

             String token = RestApiUtil.generateSharedAccessSignature(url, keyName, key);

             System.out.println("-- Authorization header --");
             System.out.println(token);
       }

}