JMS Security Example


This example shows you how configure and use security with JBoss Messaging.

With security properly configured, JBoss Messaging can restrict client access to its resouces, including connection creation, message sending/receiving, etc. This is done by configuring users and roles as well as permissions in the configuration files.

JBoss Messaging supports wild-card in security configuration. This feature makes security configuration very much flexible and it enables fine-grained control over permissions in an efficient way.

For a full description of how to configure security with JBoss Messaging, please consult the user manual.

This example demonstrates how to configure users/roles, how to configure topics with proper permissions using wild-card expressions, and how they take effects in a simple program.

First we need to configure users with roles. Users and Roles are configured in jbm-users.xml. This example has four users configured as below

     
		   <user name="bill" password="jbossmessaging">
		      <role name="user"/>
		   </user>
		  
		   <user name="andrew" password="jbossmessaging1">
		      <role name="europe-user"/>
		      <role name="user"/>
		   </user>
		   
		   <user name="frank" password="jbossmessaging2">
		      <role name="us-user"/>
		      <role name="news-user"/>
		      <role name="user"/>
		   </user>
		   
		   <user name="sam" password="jbossmessaging3">
		      <role name="news-user"/>
		      <role name="user"/>
		   </user>
     
     

Each user has three properties available: user name, password, and roles it belongs to. It should be noticed that a user can belong to more than one roles. In the above configuration, all users belong to role 'user'. User 'andrew' also belongs to role 'europe-user', user 'frank' also belongs to 'us-user' and 'news-user', and user 'sam' also belongs to 'news-user'.

User name and password consists of a valid account that can be used to establish connections to a JBoss Messaging server, while roles are used in controling the access privileges against JBoss Messaging topics and queues. You can achieve this control by configuring proper permissions in jbm-configuration.xml, like in the following


      <security-settings>
         <!-- any user can have full control of generic topics -->
		   <security-setting match="jms.topic.#">
		      <permission type="createDurableQueue" roles="user"/>
		      <permission type="deleteDurableQueue" roles="user"/>
		      <permission type="createTempQueue" roles="user"/>
		      <permission type="deleteTempQueue" roles="user"/>
		      <permission type="send" roles="user"/>
		      <permission type="consume" roles="user"/>
		   </security-setting>
		
		   <security-setting match="jms.topic.news.europe.#">
		      <permission type="createDurableQueue" roles="user"/>
		      <permission type="deleteDurableQueue" roles="user"/>
		      <permission type="createTempQueue" roles="user"/>
		      <permission type="deleteTempQueue" roles="user"/>
		      <permission type="send" roles="europe-user"/>
		      <permission type="consume" roles="news-user"/>
		   </security-setting>
		
		   <security-setting match="jms.topic.news.us.#">
		      <permission type="createDurableQueue" roles="user"/>
		      <permission type="deleteDurableQueue" roles="user"/>
		      <permission type="createTempQueue" roles="user"/>
		      <permission type="deleteTempQueue" roles="user"/>
		      <permission type="send" roles="us-user"/>
		      <permission type="consume" roles="news-user"/>
		   </security-setting>
     </security-settings>
     

Permissions can be defined on any group of queues, by using a wildcard. You can easily specify wildcards to apply certain permissions to a set of matching queues and topics. In the above configuration we have created four sets of permissions, each set matches against a special group of targets, indicated by wild-card match attributes.

You can provide a very loose permission control for a very general group of destinations. Then you add more strict control over specific topics. By the above we define the following access rules:

  • Only role 'us-user' can create/delete and pulish messages to topics whose names match wild-card pattern 'news.us.#'.
  • Only role 'europe-user' can create/delete and publish messages to topics whose names match wild-card pattern 'news.europe.#'.
  • Only role 'news-user' can subscribe messages to topics whose names match wild-card pattern 'news.us.#' and 'news.europe.#'.
  • For any other topics that don't match any of the above wild-card patterns, permissions are granted to users of role 'user'.
  • To illustrate the effect of permissions, three topics are deployed. Topic 'genericTopic' matches 'jms.topic.#' wild-card, topic 'news.europe.europeTopic' matches jms.topic.news.europe.#' wild-cards, and topic 'news.us.usTopic' matches 'jms.topic.news.us.#'.

    With JBoss Messaging, the security manager is also configurable. You can use JAASSecurityManager or JBossASSecurityManager based on you need. Please check out the jbm-jboss-beans.xml for how to do. In this example we just use the basic JBMSecurityManagerImpl which reads users/roles/passwords from the xml file jbm-users.xml.

    Example step-by-step

    To run the example, simply type ant from this directory


    1. First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the client-jndi.properties file in the directory ../common/config
    2.            
                 InitialContext initialContext = getContext(0);
                 
              
    3. We perform lookup on the topics
    4.            
                 Topic genericTopic = (Topic) initialContext.lookup("/topic/genericTopic");
                 Topic europeTopic = (Topic) initialContext.lookup("/topic/europeTopic");
                 Topic usTopic = (Topic) initialContext.lookup("/topic/usTopic");
                 
              
    5. We perform a lookup on the Connection Factory
    6.            
                 ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("/ConnectionFactory");
                 
              
    7. We try to create a JMS Connection without user/password. It will fail.
    8.            
                 try
                 {
                    cf.createConnection();
                    result = false;
                 }
                 catch (JMSSecurityException e)
                 {
                    System.out.println("Default user cannot get a connection. Details: " + e.getMessage());
                 }
                 
              
    9. Bill tries to make a connection using wrong password
    10.            
                 billConnection = null;
                 try
                 {
                    billConnection = createConnection("bill", "jbossmessaging1", cf);
                    result = false;
                 }
                 catch (JMSException e)
                 {
                    System.out.println("User bill failed to connect. Details: " + e.getMessage());
                 }
                 
              
    11. Bill makes a good connection.
    12.           
                 billConnection = createConnection("bill", "jbossmessaging", cf);
                 billConnection.start();
                
             
    13. Andrew makes a good connection
    14.            
                 andrewConnection = createConnection("andrew", "jbossmessaging1", cf);
                 andrewConnection.start();
                 
               
    15. Frank makes a good connection
    16.            
                 frankConnection = createConnection("frank", "jbossmessaging2", cf);
                 frankConnection.start();
                 
              
    17. Sam makes a good connection
    18.            
                 samConnection = createConnection("sam", "jbossmessaging3", cf);
                 samConnection.start();
                 
              
    19. We check every user can publish/subscribe genericTopics
    20.            
                 checkUserSendAndReceive(genericTopic, billConnection, "bill");
                 checkUserSendAndReceive(genericTopic, andrewConnection, "andrew");
                 checkUserSendAndReceive(genericTopic, frankConnection, "frank");
                 checkUserSendAndReceive(genericTopic, samConnection, "sam");
                 
              
    21. We check permissions on news.europe.europeTopic for bill: can't send and can't receive
    22.            
                 checkUserNoSendNoReceive(europeTopic, billConnection, "bill", andrewConnection, frankConnection);
                 
              
    23. We check permissions on news.europe.europeTopic for andrew: can send but can't receive
    24.            
                 checkUserSendNoReceive(europeTopic, andrewConnection, "andrew", frankConnection);
                 
              
    25. We check permissions on news.europe.europeTopic for frank: can't send but can receive
    26.            
                 checkUserReceiveNoSend(europeTopic, frankConnection, "frank", andrewConnection);
                 
              
    27. We check permissions on news.europe.europeTopic for sam: can't send but can receive
    28.            
                 checkUserReceiveNoSend(europeTopic, samConnection, "sam", andrewConnection);
                 
              
    29. We check permissions on news.us.usTopic for bill: can't send and can't receive
    30.            
                 checkUserNoSendNoReceive(usTopic, billConnection, "bill");
                 
              
    31. We check permissions on news.us.usTopic for andrew: can't send and can't receive
    32.            
                 checkUserNoSendNoReceive(usTopic, andrewConnection, "andrew");
                 
              
    33. We check permissions on news.us.usTopic for frank: can both send and receive
    34.            
                 checkUserSendAndReceive(usTopic, frankConnection, "frank");
                 
              
    35. We check permissions on news.us.usTopic for sam: can't send but can receive
    36.            
                 checkUserReceiveNoSend(usTopic, samConnection, "sam", frankConnection);
                 
              
    37. And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
    38.            
                 finally
                 {
                    if (billConnection != null)
                    {
                       billConnection.close();
                    }
                    if (andrewConnection != null)
                    {
                       andrewConnection.close();
                    }
                    if (frankConnection != null)
                    {
                       frankConnection.close();
                    }
                    if (samConnection != null)
                    {
                       samConnection.close();
                    }
      		         
                    // Also the initialContext
                    if (initialContext != null)
                    {
                       initialContext.close();
                    }
                 }