Export (0) Print
Expand All

Controlling Access to Azure Queues with Java

Updated: April 4, 2014

This guide will show you how to perform common tasks using Azure Queues. The samples are written in Java and use the Azure SDK for Java. The scenarios covered include adding, processing, reading, and updating queues and metadata. Access control is fundamental to using queues securely and productively in your Java applications and so samples are presented by the type of access control demonstrated: Shared Access Signatures and Stored Access policy. Anonymous users do not have access to Azure queues. The samples were all compiled and run as Java applications in Eclipse and using the Azure Toolkit for Eclipse with Java (by Microsoft Open Technologies).

After reviewing the samples in the section about shared access signatures, you should be able to accomplish the following tasks with Java.

  • Create a new queue in your storage account

  • Generate a shared access signature (basic SAS) giving irrevocable temporary access to the queue

  • Distribute different access permissions to different users

  • Extend temporary add, process messages, read, or update access to one queue but no other queues

  • Provide access to a queue without revealing the Azure storage account key

  • Retrieve , process, and dequeue a message from a queue

  • Peek at the next message in a queue without processing or removal

  • Add a message to a private queue using a basic SAS

  • Delete a queue from the storage account

A shared access signature (SAS) contains all the information necessary to give any user controlled access to queues saved in an Azure storage account. There is no public access to queues for anonymous users that do not have a shared access signature or a stored access policy. A basic SAS is not associated with a shared access policy and will provide irrevocable access to any user in possession of the SAS for a limited time. A basic SAS has an expiration time which cannot be extended. Once a SAS has been distributed, it cannot be cancelled, access to the queue can only be revoked prior to the expiration time by changing the Azure storage account key.

An application in possession of the Azure storage key can generate a basic SAS for controlling access to a queue saved in the storage account by specifying one or more of the following constants in the SharedAccessQueuePermissions enum of a SharedAccessQueuePolicy object.

  • NONE – No shared access to the queue.

  • ADD – Add messages to the queue.

  • PROCESSMESSAGES – Get and delete messages in the queue.

  • READ – Peek at messages in the queue and get queue metadata.

  • UPDATE – Update messages in the queue.

For example, the following string represents a basic SAS containing all the information necessary to access the queue.

sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=nnnP5P5nPnnnP5P5nn%5PPnPPPPn5PnnPP5PP%5Pn5PPnnP%5P

The SAS can be appended to the url for the queue as query parameters to construct a SAS url. Because the SAS contains all the necessary information, any user in possession of this url has access. Note that to construct a working url, a query symbol (?) is required between the public access url and SAS.

http://grassy.queue.core.windows.net/queue1?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=nnnP5P5nPnnnP5P5nn%5PPnPPPPn5PnnPP5PP%5Pn5PPnnP%5P

Once this url is distributed it cannot be cancelled or extended beyond the expiration time. It can give any application that obtains it add, processmessages, read, and update access to the queue. It stops working after the expiration time and cannot be reactivated.

The following Java code creates a queue named queue1 if it does not already exist. It generates a basic SAS string with an applicable time span of 1 hour. Applicable time-spans greater than 1 hour can be specified. The period of applicability starts immediately and expires one hour later. During the applicable time span, any user in possession of the basic SAS has ADD, PROCESSMESSAGES, READ, and UPDATE access permissions for the queue. Rerunning this code a second time before the first expiration time does not revoke the permissions conveyed by the first SAS and old urls will continue to work. After the expiration time, a url appended with the expired SAS will not work. If this code is rerun after the expiration time, it generates a new valid SAS which can give permissions for another hour, but the expired SAS is not reactivated. This new basic SAS must be distributed to users.

public class BasicSASQ 
{
   public static void main(String[] args) throws InvalidKeyException,
      URISyntaxException, StorageException 
   {
   Account creds = new Account(); //Account key required to create SAS             
   final String storageConnectionString = creds.getstorageconnectionstring();
   CloudStorageAccount storageAccount = 
      CloudStorageAccount.parse(storageConnectionString);
   CloudQueueClient queClient = storageAccount.createCloudQueueClient();
   CloudQueue queue = queClient.getQueueReference("queue1"); 
   queue.createIfNotExist();
   SharedAccessQueuePolicy policy = new SharedAccessQueuePolicy();
   GregorianCalendar calendar = 
      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
   calendar.setTime(new Date());
   policy.setSharedAccessStartTime(calendar.getTime()); //Immediate applicability
   calendar.add(Calendar.HOUR, 1);  //Applicable time-span is 1 hour
   policy.setSharedAccessExpiryTime(calendar.getTime());
   //This basic SAS grants all access privileges 
   policy.setPermissions(EnumSet.of(SharedAccessQueuePermissions.ADD, 
      SharedAccessQueuePermissions.PROCESSMESSAGES,
      SharedAccessQueuePermissions.READ, SharedAccessQueuePermissions.UPDATE));
   QueuePermissions queuePermissions = new QueuePermissions();
   queue.uploadPermissions(queuePermissions);
   String qsas = queue.generateSharedAccessSignature(policy, null);
   System.out.println("The shared access signature for " 
      + queue.getName() + " was created.");
   System.out.println(qsas);
   }
}

The Account class provides the Azure storage account name and the account key. You may also add metadata when you create the queue. See the section titled Controlling Access to Azure Blob Containers with Java for code examples of how to write an Account class and for adding and reading metadata.

The Azure storage account key is required to create or delete an entire queue from the storage account. The previous code created queue1 and the following code deletes queue2 from the storage account.

public class Delqueue 
{
   public static void main(String[] args) throws InvalidKeyException, 
      URISyntaxException, StorageException 
   {
   Account creds = new Account(); //Account key required to delete queue            
   final String storageConnectionString = creds.getstorageconnectionstring();
   CloudStorageAccount storageAccount = 
      CloudStorageAccount.parse(storageConnectionString);
   CloudQueueClient queClient = storageAccount.createCloudQueueClient();
   CloudQueue queue = queClient.getQueueReference("queue2"); 
   System.out.println(queue.getName() +" exists? "+ queue.exists());
   queue.deleteIfExists();
   System.out.println(queue.getName() +" exists? "+ queue.exists());
   System.out.println("Delete queue has finished running.");
    }
}

Because ADD was included with the permissions associated with the example SAS for queue1, an application in possession of the SAS url can add a message to queue1 using Java code similar to the following and without knowledge of the Azure storage account key.

public class Addmessage 
{
   public static void main(String[] args) throws InvalidKeyException,
      URISyntaxException, StorageException 
   {
   String sas = "sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-
      14T17%3A23%3A15Z&sig=nnnP5P5nPnnnP5P5nn%5PPnPPPPn5PnnPP5PP%5Pn5PPnnP%5P";        
   StorageCredentialsSharedAccessSignature credentials = 
      new StorageCredentialsSharedAccessSignature(sas);
   URI baseuri = new URI("http://grassy.queue.core.windows.net");
   CloudQueueClient queueClient = new CloudQueueClient(baseuri,credentials); 
   CloudQueue queue = queueClient.getQueueReference("queue1");
   System.out.println(queue.getName() + " exists? " + queue.exists());
   //Creates and adds to queue the message: firstmessage
   CloudQueueMessage message = new CloudQueueMessage("firstmessage");
   queue.addMessage(message);
   System.out.println("Message added to " + queue.getName());
   }
}

Because PROCESSMESSAGES and READ is included with the permissions associated with the example SAS, an application in possession of the SAS url can get and process the next message in queue1 and then peek at the next message after that using Java code similar to the following and without knowledge of the Azure storage account key.

public class Dequeue 
{
   public static void main(String[] args) throws InvalidKeyException,
      URISyntaxException, StorageException 
   {
   String sas = "sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-
      14T17%3A23%3A15Z&sig=nnnP5P5nPnnnP5P5nn%5PPnPPPPn5PnnPP5PP%5Pn5PPnnP%5P";        
   StorageCredentialsSharedAccessSignature credentials = 
      new StorageCredentialsSharedAccessSignature(sas);
   URI baseuri = new URI("http://grassy.queue.core.windows.net");
   CloudQueueClient queueClient = new CloudQueueClient(baseuri,credentials); 
   CloudQueue queue = queueClient.getQueueReference("queue1");
   //Retrieve the front message from the queue 
   CloudQueueMessage retrievedMessage = queue.retrieveMessage();
   System.out.println(retrievedMessage.getMessageContentAsString());
   //Deletes the message from the queue
   queue.deleteMessage(retrievedMessage);
   //Peeks at the next message in the queue
   CloudQueueMessage peekedMessage = queue.peekMessage();
   System.out.println(peekedMessage.getMessageContentAsString());     
   }
}

After reviewing the samples about stored access policies, you should be able to accomplish the following tasks with Java.

  • Generate a policy SAS that gives access to a queue that can be revoked, extended, or updated.

  • Cancel all queue urls after distribution without changing your Azure storage key.

  • Reactivate a queue policy SAS after its expiration time.

  • Revoke or update queue urls based on a policy SAS at any time and change the access for old urls.

  • Create multiple policies for a single queue.

  • Use policy SAS and basic SAS together for maximum flexibility of queue access control.

Your application can have greater control over access to queues by using a policy SAS rather than a basic SAS. A basic SAS cannot be extended or cancelled once it has been distributed. A policy SAS can be cancelled or modified at any time. Because the policy is saved with the queue rather than the SAS url, the policy can be updated without having to change the SAS string (or the urls distributed to users.) When the policy for the container is updated, all old urls that have been constructed using the policy SAS are reactivated with the updated policy.

The following Java code creates a queue1 with a policy named baxter if queue1 does not already exist. It generates a policy SAS string with an applicable time span of 3 hours. The period of applicability starts immediately and expires three hours later. During the applicable time span, any user in possession of the policy SAS has ADD, PROCESSMESSAGES, READ, and UPDATE access to the container. After the expiration time, a url appended with the expired SAS will not work until it is reactivated by the storage account’s owner using the storage account key.

public class QueuePolicy
{
   public static void main(String[] args) throws InvalidKeyException,
      URISyntaxException, StorageException 
   {
   Account creds = new Account();//Account key required to create SAS            
   final String storageConnectionString = creds.getstorageconnectionstring();
   CloudStorageAccount storageAccount =
      CloudStorageAccount.parse(storageConnectionString);            
   CloudQueueClient queueClient = storageAccount.createCloudQueueClient();
   CloudQueue queue = queueClient.getQueueReference("queue1");
   queue.createIfNotExist();
   SharedAccessQueuePolicy policy = new SharedAccessQueuePolicy();
   GregorianCalendar calendar = 
      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
   calendar.setTime(new Date());
   policy.setSharedAccessStartTime(calendar.getTime()); //Immediate applicability
   calendar.add(Calendar.HOUR, 3); //Applicable time span is 3 hours
   policy.setSharedAccessExpiryTime(calendar.getTime()); 
   policy.setPermissions(EnumSet.of(SharedAccessQueuePermissions.ADD,
      SharedAccessQueuePermissions.PROCESSMESSAGES, 
      SharedAccessQueuePermissions.READ, SharedAccessQueuePermissions.UPDATE));
   QueuePermissions queuePermissions = new QueuePermissions();
   //Name the stored access policy: baxter
   queuePermissions.getSharedAccessPolicies().put("baxter", policy);
   queue.uploadPermissions(queuePermissions);
   String sas = queue.generateSharedAccessSignature(
      new SharedAccessQueuePolicy(),"baxter");           
   System.out.println("The stored access policy signature:");
   System.out.println(sas);                    
   }        
}

If queue1 exists, this code adds the policy baxter to the container. A queue can have no more than four simultaneous stored access policies. Because a basic SAS saves all its information in the SAS string and a policy SAS saves its information with the queue, the access rights of unexpired basic SAS urls are unaffected by adding or modifying a policy SAS. You cannot revoke a basic SAS that has already been distributed by creating a policy SAS for the container.

If the previous Java code is rerun before or after the expiration time of the policy SAS, this will renew the baxter policy SAS for an additional 3 hours and reactivate any revoked or expired baxter urls that have been distributed. You can also update the permissions (i.e. add or remove access permissions) at any time by editing and rerunning this code.

To revoke and cancel all the urls that have been distributed with the baxter policy SAS, rerun the code with an expiration time that is earlier than start time. For example, substitute the following code to revoke the policy SAS and cancel all the permissions to urls that have been distributed to users.

policy.setSharedAccessStartTime(calendar.getTime());
calendar.add(Calendar.HOUR, -1); //Expiration time is earlier than start time
policy.setSharedAccessExpiryTime(calendar.getTime());  

You can also revoke a policy SAS after distribution by removing or replacing the policy in the container. If the code is rerun on queue1, with the name of the policy changed from baxter to heath, the new policy heath overwrites the old policy baxter. This cancels all the urls already distributed with a baxter policy SAS. However, the old urls associated with baxter policy can be reactivated by rerunning the code a third time with the policy changed from heath to baxter (which cancels all the heath urls.)

The policy SAS can be appended to the basic url for the queue as query parameters to construct a decorated url with the controlled permissions in the same way as a basic SAS. Note that the SAS generated by the code above does not include the query symbol (?) required between the basic url and policy SAS. For example, the string for queue1 would be similar to the following.

http://grassy.queue.core.windows.net/queue1?sv=2012-02-12&sig=PPPPPn5nnnn5nPnPPnnnnPnnPPnnnPPnnn5PP55PPPP%5P&si=baxter

Applications can use the policy SAS in exactly the same way as a basic SAS. Simply substitute the policy SAS string for the basic SAS string in the previous examples to use shared access policy to control access with a shared access policy. Applications that have a policy SAS can perform add, processmessages, read, and update operations on the queue without knowledge of the Azure storage account key.

A useful pattern to implement flexible queue access control is to specify up to four stored access policies for the container that respectively give add, process messages, read, and update access. This approach still leaves the ability to also distribute as necessary short-lived basic SAS urls for the queue. The basic SAS urls can give access permissions independent of the policy. The following Java code demonstrates how two stored access policies can be saved for a single queue.

public class QueuePolicies
{
   public static void main(String[] args) throws InvalidKeyException, 
      URISyntaxException, StorageException 
   {
   Account creds = new Account();            
   final String storageConnectionString = creds.getstorageconnectionstring();
   CloudStorageAccount storageAccount =  
      CloudStorageAccount.parse(storageConnectionString);            
   CloudQueueClient queueClient = storageAccount.createCloudQueueClient();
   CloudQueue queue = queueClient.getQueueReference("queue1");
   queue.createIfNotExist();
   SharedAccessQueuePolicy policy = 
      new SharedAccessQueuePolicy();
   GregorianCalendar calendar = 
      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
   calendar.setTime(new Date());
   policy.setSharedAccessStartTime(calendar.getTime());
   calendar.add(Calendar.HOUR, 1);
   policy.setSharedAccessExpiryTime(calendar.getTime());
   policy.setPermissions(EnumSet.of(SharedAccessQueuePermissions.ADD, 
      SharedAccessQueuePermissions.PROCESSMESSAGES, 
      SharedAccessQueuePermissions.READ, SharedAccessQueuePermissions.UPDATE));
   SharedAccessQueuePolicy policy2 = new SharedAccessQueuePolicy();
   GregorianCalendar calendar2 = 
      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
   calendar.setTime(new Date());
   policy2.setSharedAccessStartTime(calendar2.getTime());
   calendar2.add(Calendar.HOUR, 1);
   policy2.setSharedAccessExpiryTime(calendar2.getTime());
   policy2.setPermissions(EnumSet.of(SharedAccessQueuePermissions.ADD, 
      SharedAccessQueuePermissions.PROCESSMESSAGES, 
      SharedAccessQueuePermissions.READ, SharedAccessQueuePermissions.UPDATE));
   QueuePermissions queuePermissions = new QueuePermissions();
   queuePermissions.getSharedAccessPolicies().put("baxter", policy);
   queuePermissions.getSharedAccessPolicies().put("heath", policy2);
   queue.uploadPermissions(queuePermissions);
   String sas = queue.generateSharedAccessSignature(
      new SharedAccessQueuePolicy(),"baxter");           
   System.out.println("The stored access policy signature:");
   System.out.println(sas); 
   String sas2 = queue.generateSharedAccessSignature(
      new SharedAccessQueuePolicy(),"heath");           
   System.out.println("The stored access policy2 signature:");
   System.out.println(sas2);             
   }        
}

See Also

Show:
© 2014 Microsoft