ActiveMQ Simple Authentication for Consumers and Producers

 IT, Java  Kommentare deaktiviert für ActiveMQ Simple Authentication for Consumers and Producers
Jul 032013
 

By default, ActiveMQ does not request a Username or password for consumers and producers. That means, everyone who knows your broker URL is able to connect to your broker and read your messages and/or send messages. For personal development this isn’t a big issue, but for business applications security plays an important role.

Because of that, I have played around with the authentication of consumers and producers on ActiveMQ brokers.

First of all you should know, that ActiveMQ supports a users and groups based authentication.In our example we would like to have two groups:

  • senders: they are allowed to send messages into queues (write access)
  • receivers: they are allowed to consume the messages (read access)

Setup groups and users for Receiver and Consumer:

To setup those two groups and one user for each group you have to add these lines (starting with „plugins“)  to your activemq.xml :

ATTENTION:  in earlier versions (I tested it also with 5.5.1) you have to insert the plugins-element in the correct alphabetical order. See also: http://activemq.apache.org/xml-reference.html –> Alphabetically ordered xml elements (5.4 – 5.5.1)

    <!--
        The <broker> element is used to configure the ActiveMQ broker.
    -->
    <broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">

      <plugins>
        <simpleAuthenticationPlugin>
            <users>
                <authenticationUser username="superman" password="boss" groups="senders,receivers,admins" />
                <authenticationUser username="mySendingApp" password="manager" groups="senders" />
                <authenticationUser username="myReceivingApp" password="manager" groups="receivers" />
            </users>
        </simpleAuthenticationPlugin>
      </plugins>

Link groups and users to queues and topics

After that you need to grant rights to the created groups „senders“ , „receivers“ and „admins“. Add the following lines after the closing </simpleAuthenticationPlugin> tag:

<authorizationPlugin>
   <map>
       <authorizationMap>
           <authorizationEntries>
               <authorizationEntry queue=">" write="senders" read="receivers" admin="admins" />
	       <authorizationEntry topic="ActiveMQ.Advisory.>" write="senders" read="receivers" admin="admins,senders,receivers" />
           </authorizationEntries>
       </authorizationMap>
   </map>
</authorizationPlugin>

Explanation: You can specify different access rights for the single queues. In my example I allow all users from group „senders“ to write inside all queues. queue=“>“ stands for all queues. ActiveMQ uses the „>“ as Wildcard (see also the website-link below). Also I allow all receivers to read from the queue.

Maybe you are wondering about the second <authorizationEntry> . ActiveMQ-Clients creating Advisory-Topics for several reasons. For each queue a client connects to, the client tries to create a Advisory-Topic. That is the reason why I added the second line. This line defines that all clients (with correct password and username) are able to create Topics that are named „ActiveMQ.Advisory.*“.  More about ActiveMQs advisory stuff see website link below.

Now you can restart the ActiveMQ broker in order to read the new configuration.

Client side: connect to a username/password protected queue

Now we have to setup the client side to connect to a secured broker. The ConnectionFactory class provides a method called „createConnection“. There is an overloaded method of this: createConnection(String arg1 , String arg2) where arg1 is the username and arg2 is the password.

Here a short example for a listener connecting to a secured broker:

public void startListener() throws NamingException, JMSException, InterruptedException {

	// Create a JNDI API InitialContext object
	Properties props = new Properties();
	props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
	props.setProperty(Context.PROVIDER_URL, "tcp://" + server + ":61616");

	jndiContext = new InitialContext(props);
	connectionFactory = (ConnectionFactory) jndiContext.lookup("ConnectionFactory");
	destination = (Destination) jndiContext.lookup("dynamicQueues/" + queueName);

	// Connect to ActiveMQ
	connection = connectionFactory.createConnection(username, password);
	connection.setClientID(clientID);
	// this helps to ensure, that not 2 instances can connect to the broker simultaneously
	// because it is not allowed to connect to the same broker with the same clientID
	connection.start();
	session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

	MessageConsumer subscriber = session.createConsumer(destination);
	subscriber.setMessageListener(new MessageListener() {

		@Override
		public void onMessage(Message msg) {
			try {
				System.out.println("Message arrived by consumer-ID : " + clientID + " CONTENT = " + ((TextMessage) msg).getText());
			} catch (JMSException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	});

	for (int i = 0; i &lt; 100; i++) {
		System.out.println("still alive .... " + i);
		Thread.sleep(10 * 1000);
	}
}

 

Have fun with simple secured JMS 😉

——————————————————————

Sources / Websites:

ActiveMQ Wildcards: http://activemq.apache.org/wildcards.html

ActiveMQ Sample Borker Config for secured JMS Connections: http://activemq.apache.org/complex-single-broker-configuration-stomp-only.html

ActiveMQ Advisory Topics: http://activemq.apache.org/advisory-message.html

Java API for ConnectionFactory:  http://docs.oracle.com/javaee/1.4/api/javax/jms/ConnectionFactory.html