2014-10-31 06:20:28 -04:00
< html >
< head >
2014-11-19 03:44:57 -05:00
< title > ActiveMQ JMS Security Example< / title >
2014-10-31 06:20:28 -04:00
< link rel = "stylesheet" type = "text/css" href = "../common/common.css" / >
< link rel = "stylesheet" type = "text/css" href = "../common/prettify.css" / >
< script type = "text/javascript" src = "../common/prettify.js" > < / script >
< / head >
< body onload = "prettyPrint()" >
< h1 > JMS Security Example< / h1 >
2014-11-19 03:44:57 -05:00
< p > This example shows how to configure and use security using ActiveMQ.< / p >
2014-10-31 06:20:28 -04:00
2014-11-19 03:44:57 -05:00
< p > With security properly configured, ActiveMQ can restrict client access to its resources, including
2014-10-31 06:20:28 -04:00
connection creation, message sending/receiving, etc. This is done by configuring users and roles as well as permissions in
the configuration files. < / p >
2014-11-19 03:44:57 -05:00
< p > ActiveMQ supports wild-card security configuration. This feature makes security configuration very
2014-10-31 06:20:28 -04:00
flexible and enables fine-grained control over permissions in an efficient way.< / p >
2014-11-19 03:44:57 -05:00
< p > For a full description of how to configure security with ActiveMQ, please consult the user
2014-10-31 06:20:28 -04:00
manual.< / p >
< p > 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. < / p >
2014-11-19 14:58:44 -05:00
< p > First we need to configure users with roles. Users and Roles are configured in < code > activemq-users.xml< / code > . This example has four users
2014-10-31 06:20:28 -04:00
configured as below < / p >
< pre class = "prettyprint" >
< code >
2014-11-19 14:58:44 -05:00
< user name=" bill" password=" activemq" >
2014-10-31 06:20:28 -04:00
< role name=" user" />
< /user>
2014-11-20 05:08:43 -05:00
< user name=" andrew" password=" activemq1" >
2014-10-31 06:20:28 -04:00
< role name=" europe-user" />
< role name=" user" />
< /user>
2014-11-20 05:08:43 -05:00
< user name=" frank" password=" activemq2" >
2014-10-31 06:20:28 -04:00
< role name=" us-user" />
< role name=" news-user" />
< role name=" user" />
< /user>
2014-11-20 05:08:43 -05:00
< user name=" sam" password=" activemq3" >
2014-10-31 06:20:28 -04:00
< role name=" news-user" />
< role name=" user" />
< /user>
< / code >
< / pre >
< p >
Each user has three properties available: user name, password, and roles it belongs to. It should be noted that
a user can belong to more than one role. 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'.
< / p >
< p >
2014-11-19 03:44:57 -05:00
User name and password consists of a valid account that can be used to establish connections to a ActiveMQ server, while
roles are used in controlling the access privileges against ActiveMQ topics and queues. You can achieve this control by
2014-11-19 14:58:44 -05:00
configuring proper permissions in < code > activemq-configuration.xml< / code > , like the following
2014-10-31 06:20:28 -04:00
< / p >
< pre class = "prettyprint" > < code >
< 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=" createNonDurableQueue" roles=" user" />
< permission type=" deleteNonDurableQueue" 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=" createNonDurableQueue" roles=" user" />
< permission type=" deleteNonDurableQueue" 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=" createNonDurableQueue" roles=" user" />
< permission type=" deleteNonDurableQueue" roles=" user" />
< permission type=" send" roles=" us-user" />
< permission type=" consume" roles=" news-user" />
< /security-setting>
< /security-settings>
< / code > < / pre >
< p > 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.< / p >
< p > You can provide a very broad permission control as a default and then add more strict control
over specific addresses. By the above we define the following access rules:< / p >
< li > Only role 'us-user' can create/delete and pulish messages to topics whose names match wild-card pattern 'news.us.#'.< / li >
< li > Only role 'europe-user' can create/delete and publish messages to topics whose names match wild-card pattern 'news.europe.#'.< / li >
< li > Only role 'news-user' can subscribe messages to topics whose names match wild-card pattern 'news.us.#' and 'news.europe.#'.< / li >
< li > For any other topics that don't match any of the above wild-card patterns, permissions are granted to users of role 'user'.< / li >
< p > 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.#'.< / p >
2014-11-19 03:44:57 -05:00
< p > With ActiveMQ, the security manager is also configurable. You can use JAASSecurityManager or JBossASSecurityManager based on you need. Please
2014-11-19 14:58:44 -05:00
check out the activemq-beans.xml for how to do. In this example we just use the basic ActiveMQSecurityManagerImpl which reads users/roles/passwords from the xml
file < code > activemq-users.xml< / code > .
2014-10-31 06:20:28 -04:00
< h2 > Example step-by-step< / h2 >
< p > < i > To run the example, simply type < code > mvn verify< / code > from this directory< / i > < / p >
< ol >
< li > 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 < code > client-jndi.properties< / code > file in the directory < code > ../common/config< / code > < / li >
< pre class = "prettyprint" >
< code >
InitialContext initialContext = getContext(0);
< / code >
< / pre >
< li > We perform lookup on the topics< / li >
< pre class = "prettyprint" >
< code >
Topic genericTopic = (Topic) initialContext.lookup("/topic/genericTopic");
Topic europeTopic = (Topic) initialContext.lookup("/topic/europeTopic");
Topic usTopic = (Topic) initialContext.lookup("/topic/usTopic");
< / code >
< / pre >
< li > We perform a lookup on the Connection Factory< / li >
< pre class = "prettyprint" >
< code >
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("/ConnectionFactory");
< / code >
< / pre >
< li > We try to create a JMS Connection without user/password. It will fail.< / li >
< pre class = "prettyprint" >
< code >
try
{
cf.createConnection();
result = false;
}
catch (JMSSecurityException e)
{
System.out.println("Default user cannot get a connection. Details: " + e.getMessage());
}
< / code >
< / pre >
< li > Bill tries to make a connection using wrong password< / li >
< pre class = "prettyprint" >
< code >
billConnection = null;
try
{
2014-11-20 05:08:43 -05:00
billConnection = createConnection("bill", "activemq1", cf);
2014-10-31 06:20:28 -04:00
result = false;
}
catch (JMSException e)
{
System.out.println("User bill failed to connect. Details: " + e.getMessage());
}
< / code >
< / pre >
< li > Bill makes a good connection.< / li >
< pre class = "prettyprint" >
< code >
2014-11-19 14:58:44 -05:00
billConnection = createConnection("bill", "activemq", cf);
2014-10-31 06:20:28 -04:00
billConnection.start();
< / code >
< / pre >
< li > Andrew makes a good connection< / li >
< pre class = "prettyprint" >
< code >
2014-11-20 05:08:43 -05:00
andrewConnection = createConnection("andrew", "activemq1", cf);
2014-10-31 06:20:28 -04:00
andrewConnection.start();
< / code >
< / pre >
< li > Frank makes a good connection< / li >
< pre class = "prettyprint" >
< code >
2014-11-20 05:08:43 -05:00
frankConnection = createConnection("frank", "activemq2", cf);
2014-10-31 06:20:28 -04:00
frankConnection.start();
< / code >
< / pre >
< li > Sam makes a good connection< / li >
< pre class = "prettyprint" >
< code >
2014-11-20 05:08:43 -05:00
samConnection = createConnection("sam", "activemq3", cf);
2014-10-31 06:20:28 -04:00
samConnection.start();
< / code >
< / pre >
< li > We check every user can publish/subscribe genericTopics< / li >
< pre class = "prettyprint" >
< code >
checkUserSendAndReceive(genericTopic, billConnection, "bill");
checkUserSendAndReceive(genericTopic, andrewConnection, "andrew");
checkUserSendAndReceive(genericTopic, frankConnection, "frank");
checkUserSendAndReceive(genericTopic, samConnection, "sam");
< / code >
< / pre >
< li > We check permissions on news.europe.europeTopic for bill: can't send and can't receive< / li >
< pre class = "prettyprint" >
< code >
checkUserNoSendNoReceive(europeTopic, billConnection, "bill", andrewConnection, frankConnection);
< / code >
< / pre >
< li > We check permissions on news.europe.europeTopic for andrew: can send but can't receive< / li >
< pre class = "prettyprint" >
< code >
checkUserSendNoReceive(europeTopic, andrewConnection, "andrew", frankConnection);
< / code >
< / pre >
< li > We check permissions on news.europe.europeTopic for frank: can't send but can receive< / li >
< pre class = "prettyprint" >
< code >
checkUserReceiveNoSend(europeTopic, frankConnection, "frank", andrewConnection);
< / code >
< / pre >
< li > We check permissions on news.europe.europeTopic for sam: can't send but can receive< / li >
< pre class = "prettyprint" >
< code >
checkUserReceiveNoSend(europeTopic, samConnection, "sam", andrewConnection);
< / code >
< / pre >
< li > We check permissions on news.us.usTopic for bill: can't send and can't receive< / li >
< pre class = "prettyprint" >
< code >
checkUserNoSendNoReceive(usTopic, billConnection, "bill");
< / code >
< / pre >
< li > We check permissions on news.us.usTopic for andrew: can't send and can't receive< / li >
< pre class = "prettyprint" >
< code >
checkUserNoSendNoReceive(usTopic, andrewConnection, "andrew");
< / code >
< / pre >
< li > We check permissions on news.us.usTopic for frank: can both send and receive< / li >
< pre class = "prettyprint" >
< code >
checkUserSendAndReceive(usTopic, frankConnection, "frank");
< / code >
< / pre >
< li > We check permissions on news.us.usTopic for sam: can't send but can receive< / li >
< pre class = "prettyprint" >
< code >
checkUserReceiveNoSend(usTopic, samConnection, "sam", frankConnection);
< / code >
< / pre >
< li > And finally, < b > always< / b > remember to close your JMS connections and resources after use, in a < code > finally< / code > block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects< / li >
< pre class = "prettyprint" >
< code >
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();
}
}
< / code >
< / pre >
< / ol >
< / body >
< / html >