This example shows how to configure and use security using ActiveMQ Artemis.
With security properly configured, ActiveMQ Artemis can restrict client access to its resources, including connection creation, message sending/receiving, etc. This is done by configuring users and roles as well as permissions in the configuration files.
ActiveMQ Artemis supports wild-card security configuration. This feature makes security configuration very flexible and enables fine-grained control over permissions in an efficient way.
For a full description of how to configure security with ActiveMQ Artemis, 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 activemq-users.xml
. This example has four users
configured as below
<user name="bill" password="activemq">
<role name="user"/>
</user>
<user name="andrew" password="activemq1">
<role name="europe-user"/>
<role name="user"/>
</user>
<user name="frank" password="activemq2">
<role name="us-user"/>
<role name="news-user"/>
<role name="user"/>
</user>
<user name="sam" password="activemq3">
<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 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'.
User name and password consists of a valid account that can be used to establish connections to a ActiveMQ Artemis server, while
roles are used in controlling the access privileges against ActiveMQ Artemis topics and queues. You can achieve this control by
configuring proper permissions in broker.xml
, like 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="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>
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 broad permission control as a default and then add more strict control over specific addresses. By the above we define the following access rules:
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 ActiveMQ Artemis, the security manager is also configurable. You can use JAASSecurityManager or JBossASSecurityManager based on you need. Please
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 activemq-users.xml
.
To run the example, simply type mvn verify -Pexample
from this directory
client-jndi.properties
file in the directory ../common/config
InitialContext initialContext = getContext(0);
Topic genericTopic = (Topic) initialContext.lookup("/topic/genericTopic");
Topic europeTopic = (Topic) initialContext.lookup("/topic/europeTopic");
Topic usTopic = (Topic) initialContext.lookup("/topic/usTopic");
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("/ConnectionFactory");
try
{
cf.createConnection();
result = false;
}
catch (JMSSecurityException e)
{
System.out.println("Default user cannot get a connection. Details: " + e.getMessage());
}
billConnection = null;
try
{
billConnection = createConnection("bill", "activemq1", cf);
result = false;
}
catch (JMSException e)
{
System.out.println("User bill failed to connect. Details: " + e.getMessage());
}
billConnection = createConnection("bill", "activemq", cf);
billConnection.start();
andrewConnection = createConnection("andrew", "activemq1", cf);
andrewConnection.start();
frankConnection = createConnection("frank", "activemq2", cf);
frankConnection.start();
samConnection = createConnection("sam", "activemq3", cf);
samConnection.start();
checkUserSendAndReceive(genericTopic, billConnection, "bill");
checkUserSendAndReceive(genericTopic, andrewConnection, "andrew");
checkUserSendAndReceive(genericTopic, frankConnection, "frank");
checkUserSendAndReceive(genericTopic, samConnection, "sam");
checkUserNoSendNoReceive(europeTopic, billConnection, "bill", andrewConnection, frankConnection);
checkUserSendNoReceive(europeTopic, andrewConnection, "andrew", frankConnection);
checkUserReceiveNoSend(europeTopic, frankConnection, "frank", andrewConnection);
checkUserReceiveNoSend(europeTopic, samConnection, "sam", andrewConnection);
checkUserNoSendNoReceive(usTopic, billConnection, "bill");
checkUserNoSendNoReceive(usTopic, andrewConnection, "andrew");
checkUserSendAndReceive(usTopic, frankConnection, "frank");
checkUserReceiveNoSend(usTopic, samConnection, "sam", frankConnection);
finally
block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
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();
}
}