To run the example, simply type mvn verify from this directory,
or mvn -PnoServer verify if you want to start and create the server manually.
This example shows how to configure and use security using ActiveMQ Artemis with LDAP.
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();
}
}