You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by gt...@apache.org on 2013/11/05 21:45:43 UTC

git commit: https://issues.apache.org/jira/browse/AMQ-4849 - runtime modifications to simpleAuthenticationPlugin plugin implemented with test

Updated Branches:
  refs/heads/trunk 4367ec1b8 -> 67a7d30b4


https://issues.apache.org/jira/browse/AMQ-4849 - runtime modifications to simpleAuthenticationPlugin plugin implemented with test


Project: http://git-wip-us.apache.org/repos/asf/activemq/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq/commit/67a7d30b
Tree: http://git-wip-us.apache.org/repos/asf/activemq/tree/67a7d30b
Diff: http://git-wip-us.apache.org/repos/asf/activemq/diff/67a7d30b

Branch: refs/heads/trunk
Commit: 67a7d30b4702647a8b51758e61aa628618f42fa9
Parents: 4367ec1
Author: gtully <ga...@gmail.com>
Authored: Tue Nov 5 20:37:31 2013 +0000
Committer: gtully <ga...@gmail.com>
Committed: Tue Nov 5 20:38:23 2013 +0000

----------------------------------------------------------------------
 .../activemq/security/AuthenticationUser.java   |  3 +
 .../security/SimpleAuthenticationBroker.java    | 12 ++-
 .../security/SimpleAuthenticationPlugin.java    | 12 +++
 .../plugin/RuntimeConfigurationBroker.java      | 83 ++++++++++++++++----
 .../src/main/resources/binding.xjb              |  8 ++
 .../org/apache/activemq/AuthenticationTest.java | 71 +++++++++++++++++
 .../activemq/authenticationTest-two-users.xml   | 59 ++++++++++++++
 .../activemq/authenticationTest-users.xml       | 54 +++++++++++++
 8 files changed, 286 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java
----------------------------------------------------------------------
diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java b/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java
index edd0eab..65d34d5 100644
--- a/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java
+++ b/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java
@@ -28,6 +28,9 @@ public class AuthenticationUser {
     String password;
     String groups;
 
+    public AuthenticationUser() {
+    }
+
     public AuthenticationUser(String username, String password, String groups) {
         this.username = username;
         this.password = password;

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java
----------------------------------------------------------------------
diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java
index 6e61e88..46544f7 100644
--- a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java
+++ b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java
@@ -34,8 +34,8 @@ public class SimpleAuthenticationBroker extends AbstractAuthenticationBroker {
     private boolean anonymousAccessAllowed = false;
     private String anonymousUser;
     private String anonymousGroup;
-    private final Map<String,String> userPasswords;
-    private final Map<String,Set<Principal>> userGroups;
+    private Map<String,String> userPasswords;
+    private Map<String,Set<Principal>> userGroups;
 
     public SimpleAuthenticationBroker(Broker next, Map<String,String> userPasswords, Map<String,Set<Principal>> userGroups) {
         super(next);
@@ -55,6 +55,14 @@ public class SimpleAuthenticationBroker extends AbstractAuthenticationBroker {
         this.anonymousGroup = anonymousGroup;
     }
 
+    public void setUserPasswords(Map<String,String> value) {
+        userPasswords = value;
+    }
+
+    public void setUserGroups(Map<String, Set<Principal>> value) {
+        userGroups = value;
+    }
+
     @Override
     public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
 

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java
----------------------------------------------------------------------
diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java
index 7d518ea..a334a98 100644
--- a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java
+++ b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java
@@ -93,14 +93,26 @@ public class SimpleAuthenticationPlugin implements BrokerPlugin {
         this.anonymousAccessAllowed = anonymousAccessAllowed;
     }
 
+    public boolean isAnonymousAccessAllowed() {
+        return anonymousAccessAllowed;
+    }
+
     public void setAnonymousUser(String anonymousUser) {
         this.anonymousUser = anonymousUser;
     }
 
+    public String getAnonymousUser() {
+        return anonymousUser;
+    }
+
     public void setAnonymousGroup(String anonymousGroup) {
         this.anonymousGroup = anonymousGroup;
     }
 
+    public String getAnonymousGroup() {
+        return anonymousGroup;
+    }
+
     /**
      * Sets the groups a user is in. The key is the user name and the value is a
      * Set of groups

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java
----------------------------------------------------------------------
diff --git a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java
index 0d08faf..ce26534 100644
--- a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java
+++ b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java
@@ -17,7 +17,6 @@
 package org.apache.activemq.plugin;
 
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
@@ -69,10 +68,12 @@ import org.apache.activemq.broker.region.virtual.VirtualTopic;
 import org.apache.activemq.command.ActiveMQDestination;
 import org.apache.activemq.command.ActiveMQQueue;
 import org.apache.activemq.command.ActiveMQTopic;
+import org.apache.activemq.command.ConnectionInfo;
 import org.apache.activemq.filter.DestinationMapEntry;
 import org.apache.activemq.network.DiscoveryNetworkConnector;
 import org.apache.activemq.network.NetworkConnector;
 import org.apache.activemq.plugin.jmx.RuntimeConfigurationView;
+import org.apache.activemq.schema.core.DtoAuthenticationUser;
 import org.apache.activemq.schema.core.DtoAuthorizationEntry;
 import org.apache.activemq.schema.core.DtoAuthorizationMap;
 import org.apache.activemq.schema.core.DtoAuthorizationPlugin;
@@ -83,11 +84,15 @@ import org.apache.activemq.schema.core.DtoNetworkConnector;
 import org.apache.activemq.schema.core.DtoPolicyEntry;
 import org.apache.activemq.schema.core.DtoPolicyMap;
 import org.apache.activemq.schema.core.DtoQueue;
+import org.apache.activemq.schema.core.DtoSimpleAuthenticationPlugin;
 import org.apache.activemq.schema.core.DtoTopic;
 import org.apache.activemq.schema.core.DtoVirtualDestinationInterceptor;
 import org.apache.activemq.schema.core.DtoVirtualTopic;
+import org.apache.activemq.security.AuthenticationUser;
 import org.apache.activemq.security.AuthorizationBroker;
 import org.apache.activemq.security.AuthorizationMap;
+import org.apache.activemq.security.SimpleAuthenticationBroker;
+import org.apache.activemq.security.SimpleAuthenticationPlugin;
 import org.apache.activemq.security.TempDestinationAuthorizationEntry;
 import org.apache.activemq.security.XBeanAuthorizationEntry;
 import org.apache.activemq.security.XBeanAuthorizationMap;
@@ -95,9 +100,7 @@ import org.apache.activemq.spring.Utils;
 import org.apache.activemq.util.IntrospectionSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.FactoryBean;
-import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
 import org.springframework.beans.factory.xml.PluggableSchemaResolver;
 import org.springframework.core.io.Resource;
 import org.w3c.dom.Document;
@@ -112,13 +115,15 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
     public static final Logger LOG = LoggerFactory.getLogger(RuntimeConfigurationBroker.class);
     public static final String objectNamePropsAppendage = ",service=RuntimeConfiguration,name=Plugin";
     private final ReentrantReadWriteLock addDestinationBarrier = new ReentrantReadWriteLock();
+    private final ReentrantReadWriteLock addConnectionBarrier = new ReentrantReadWriteLock();
     PropertiesPlaceHolderUtil placeHolderUtil = null;
     private long checkPeriod;
     private long lastModified = -1;
     private Resource configToMonitor;
     private DtoBroker currentConfiguration;
     private Runnable monitorTask;
-    private ConcurrentLinkedQueue<Runnable> destinationInterceptorUpdateWork = new ConcurrentLinkedQueue<Runnable>();
+    private ConcurrentLinkedQueue<Runnable> addDestinationWork = new ConcurrentLinkedQueue<Runnable>();
+    private ConcurrentLinkedQueue<Runnable> addConnectionWork = new ConcurrentLinkedQueue<Runnable>();
     private ObjectName objectName;
     private String infoString;
     private Schema schema;
@@ -184,13 +189,13 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
     // modification to virtual destinations interceptor needs exclusive access to destination add
     @Override
     public Destination addDestination(ConnectionContext context, ActiveMQDestination destination, boolean createIfTemporary) throws Exception {
-        Runnable work = destinationInterceptorUpdateWork.poll();
+        Runnable work = addDestinationWork.poll();
         if (work != null) {
             try {
                 addDestinationBarrier.writeLock().lockInterruptibly();
                 do {
                     work.run();
-                    work = destinationInterceptorUpdateWork.poll();
+                    work = addDestinationWork.poll();
                 } while (work != null);
                 return super.addDestination(context, destination, createIfTemporary);
             } finally {
@@ -206,6 +211,31 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
         }
     }
 
+    // modification to authentication plugin needs exclusive access to connection add
+    @Override
+    public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
+        Runnable work = addConnectionWork.poll();
+        if (work != null) {
+            try {
+                addConnectionBarrier.writeLock().lockInterruptibly();
+                do {
+                    work.run();
+                    work = addConnectionWork.poll();
+                } while (work != null);
+                super.addConnection(context, info);
+            } finally {
+                addConnectionBarrier.writeLock().unlock();
+            }
+        } else {
+            try {
+                addConnectionBarrier.readLock().lockInterruptibly();
+                super.addConnection(context, info);
+            } finally {
+                addConnectionBarrier.readLock().unlock();
+            }
+        }
+    }
+
     public String updateNow() {
         LOG.info("Manual configuration update triggered");
         infoString = "";
@@ -235,7 +265,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
     }
 
     private void info(String s) {
-        LOG.info(s);
+        LOG.info(filterPasswords(s));
         if (infoString != null) {
             infoString += s;
             infoString += ";";
@@ -243,7 +273,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
     }
 
     private void info(String s, Throwable t) {
-        LOG.info(s, t);
+        LOG.info(filterPasswords(s), t);
         if (infoString != null) {
             infoString += s;
             infoString += ", " + t;
@@ -255,8 +285,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
         DtoBroker changed = loadConfiguration(configToMonitor);
         if (changed != null && !currentConfiguration.equals(changed)) {
             LOG.info("change in " + configToMonitor + " at: " + new Date(lastModified));
-            LOG.debug("current:" + currentConfiguration);
-            LOG.debug("new    :" + changed);
+            LOG.debug("current:" + filterPasswords(currentConfiguration));
+            LOG.debug("new    :" + filterPasswords(changed));
             processSelectiveChanges(currentConfiguration, changed);
             currentConfiguration = changed;
         } else {
@@ -320,7 +350,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
                 answer.add(val);
             }
         } catch (NoSuchMethodException mappingIncomplete) {
-            LOG.debug(o + " has no modifiable elements");
+            LOG.debug(filterPasswords(o) + " has no modifiable elements");
         } catch (Exception e) {
             info("Failed to access getContents for " + o + ", runtime modifications not supported", e);
         }
@@ -360,6 +390,24 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
                 info("failed to apply modified AuthorizationMap to AuthorizationBroker", e);
             }
 
+        } else if (candidate instanceof DtoSimpleAuthenticationPlugin) {
+            try {
+                final SimpleAuthenticationPlugin updatedPlugin = fromDto(candidate, new SimpleAuthenticationPlugin());
+                final SimpleAuthenticationBroker authenticationBroker =
+                    (SimpleAuthenticationBroker) getBrokerService().getBroker().getAdaptor(SimpleAuthenticationBroker.class);
+                addConnectionWork.add(new Runnable() {
+                    public void run() {
+                        authenticationBroker.setUserGroups(updatedPlugin.getUserGroups());
+                        authenticationBroker.setUserPasswords(updatedPlugin.getUserPasswords());
+                        authenticationBroker.setAnonymousAccessAllowed(updatedPlugin.isAnonymousAccessAllowed());
+                        authenticationBroker.setAnonymousUser(updatedPlugin.getAnonymousUser());
+                        authenticationBroker.setAnonymousGroup(updatedPlugin.getAnonymousGroup());
+                    }
+                });
+            } catch (Exception e) {
+                info("failed to apply SimpleAuthenticationPlugin modifications to SimpleAuthenticationBroker", e);
+            }
+
         } else if (candidate instanceof DtoPolicyMap) {
 
             List<Object> existingEntries = filter(existing, DtoPolicyMap.PolicyEntries.class);
@@ -450,7 +498,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
             }
         } else if (o instanceof DtoVirtualDestinationInterceptor) {
             // whack it
-            destinationInterceptorUpdateWork.add(new Runnable() {
+            addDestinationWork.add(new Runnable() {
                 public void run() {
                     List<DestinationInterceptor> interceptorsList = new ArrayList<DestinationInterceptor>();
                     for (DestinationInterceptor candidate : getBrokerService().getDestinationInterceptors()) {
@@ -500,7 +548,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
             }
         } else if (o instanceof DtoVirtualDestinationInterceptor) {
             final DtoVirtualDestinationInterceptor dto = (DtoVirtualDestinationInterceptor) o;
-            destinationInterceptorUpdateWork.add(new Runnable() {
+            addDestinationWork.add(new Runnable() {
                 public void run() {
 
                     boolean updatedExistingInterceptor = false;
@@ -570,7 +618,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
         Properties properties = new Properties();
         IntrospectionSupport.getProperties(dto, properties, null);
         replacePlaceHolders(properties);
-        LOG.trace("applying props: " + properties + ", to " + instance.getClass().getSimpleName());
+        LOG.trace("applying props: " + filterPasswords(properties) + ", to " + instance.getClass().getSimpleName());
         IntrospectionSupport.setProperties(instance, properties);
 
         // deal with nested elements
@@ -594,6 +642,11 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
         return instance;
     }
 
+    Pattern matchPassword = Pattern.compile("password=.*,");
+    private String filterPasswords(Object toEscape) {
+        return matchPassword.matcher(toEscape.toString()).replaceAll("password=???,");
+    }
+
     private Object matchType(List<Object> parameterValues, Class<?> aClass) {
         Object result = parameterValues;
         if (Set.class.isAssignableFrom(aClass)) {
@@ -607,6 +660,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
             return new ActiveMQTopic();
         } else if (DtoQueue.class.isAssignableFrom(elementContent.getClass())) {
             return new ActiveMQQueue();
+        } else if (DtoAuthenticationUser.class.isAssignableFrom(elementContent.getClass())) {
+            return new AuthenticationUser();
         } else {
             info("update not supported for dto: " + elementContent);
             return new Object();

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-runtime-config/src/main/resources/binding.xjb
----------------------------------------------------------------------
diff --git a/activemq-runtime-config/src/main/resources/binding.xjb b/activemq-runtime-config/src/main/resources/binding.xjb
index 6e786a5..64b66ce 100644
--- a/activemq-runtime-config/src/main/resources/binding.xjb
+++ b/activemq-runtime-config/src/main/resources/binding.xjb
@@ -124,5 +124,13 @@
      <jxb:property name="Contents" />
    </jxb:bindings>
 
+   <jxb:bindings node="xs:element[@name='simpleAuthenticationPlugin']/xs:complexType/xs:choice">
+     <jxb:property name="Contents" />
+   </jxb:bindings>
+
+   <jxb:bindings node="xs:element[@name='simpleAuthenticationPlugin']/xs:complexType/xs:choice/xs:choice/xs:element[@name='users']/xs:complexType/xs:sequence">
+     <jxb:property name="Contents" />
+   </jxb:bindings>
+
  </jxb:bindings>
 </jxb:bindings>

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java
----------------------------------------------------------------------
diff --git a/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java
new file mode 100644
index 0000000..eae6223
--- /dev/null
+++ b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq;
+
+import javax.jms.JMSException;
+import javax.jms.Session;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class AuthenticationTest extends RuntimeConfigTestSupport {
+
+    String configurationSeed = "authenticationTest";
+
+    @Test
+    public void testMod() throws Exception {
+        final String brokerConfig = configurationSeed + "-authentication-broker";
+        applyNewConfig(brokerConfig, configurationSeed + "-users");
+        startBroker(brokerConfig);
+        assertTrue("broker alive", brokerService.isStarted());
+
+        assertAllowed("test_user_password", "USERS.A");
+        assertDenied("another_test_user_password", "USERS.A");
+
+        // anonymous
+        assertDenied(null, "USERS.A");
+
+        applyNewConfig(brokerConfig, configurationSeed + "-two-users", SLEEP);
+
+        assertAllowed("test_user_password", "USERS.A");
+        assertAllowed("another_test_user_password", "USERS.A");
+        assertAllowed(null, "USERS.A");
+
+    }
+
+    private void assertDenied(String userPass, String destination) {
+        try {
+            assertAllowed(userPass, destination);
+            fail("Expected not allowed exception");
+        } catch (JMSException expected) {
+            LOG.debug("got:" + expected, expected);
+        }
+    }
+
+    private void assertAllowed(String userPass, String dest) throws JMSException {
+        ActiveMQConnection connection = new ActiveMQConnectionFactory("vm://localhost").createActiveMQConnection(userPass, userPass);
+        connection.start();
+        try {
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            session.createConsumer(session.createQueue(dest));
+        } finally {
+            connection.close();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml
----------------------------------------------------------------------
diff --git a/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml
new file mode 100644
index 0000000..9fa2c6a
--- /dev/null
+++ b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<beans
+        xmlns="http://www.springframework.org/schema/beans"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
+
+  <broker xmlns="http://activemq.apache.org/schema/core" start="false" persistent="false">
+    <plugins>
+      <runtimeConfigurationPlugin checkPeriod="1000"/>
+
+      <simpleAuthenticationPlugin anonymousAccessAllowed="true" anonymousGroup="users" anonymousUser="au">
+        <users>
+          <authenticationUser groups="users" password="test_user_password" username="test_user_password"/>
+          <authenticationUser groups="users" password="another_test_user_password" username="another_test_user_password"/>
+        </users>
+      </simpleAuthenticationPlugin>
+
+      <!--  lets configure a destination based authorization mechanism -->
+      <authorizationPlugin>
+        <map>
+          <authorizationMap>
+            <authorizationEntries>
+              <authorizationEntry queue=">" read="admins" write="admins" admin="admins"/>
+              <authorizationEntry queue="USERS.>" read="users" write="users" admin="users"/>
+
+              <authorizationEntry topic=">" read="admins" write="admins" admin="admins"/>
+              <authorizationEntry topic="USERS.>" read="users" write="users" admin="users"/>
+
+              <authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users"
+                                  admin="guests,users"/>
+            </authorizationEntries>
+
+            <tempDestinationAuthorizationEntry>
+              <tempDestinationAuthorizationEntry read="tempDestinationAdmins" write="tempDestinationAdmins"
+                                                 admin="tempDestinationAdmins"/>
+            </tempDestinationAuthorizationEntry>
+          </authorizationMap>
+        </map>
+      </authorizationPlugin>
+    </plugins>
+  </broker>
+</beans>

http://git-wip-us.apache.org/repos/asf/activemq/blob/67a7d30b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml
----------------------------------------------------------------------
diff --git a/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml
new file mode 100644
index 0000000..9ed5535
--- /dev/null
+++ b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<beans
+        xmlns="http://www.springframework.org/schema/beans"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
+
+  <broker xmlns="http://activemq.apache.org/schema/core" start="false" persistent="false">
+    <plugins>
+      <runtimeConfigurationPlugin checkPeriod="1000"/>
+
+      <simpleAuthenticationPlugin anonymousAccessAllowed="false" anonymousGroup="ag" anonymousUser="au"><users><authenticationUser groups="users" password="test_user_password" username="test_user_password"/></users></simpleAuthenticationPlugin>
+
+      <!--  lets configure a destination based authorization mechanism -->
+      <authorizationPlugin>
+        <map>
+          <authorizationMap>
+            <authorizationEntries>
+              <authorizationEntry queue=">" read="admins" write="admins" admin="admins"/>
+              <authorizationEntry queue="USERS.>" read="users" write="users" admin="users"/>
+
+              <authorizationEntry topic=">" read="admins" write="admins" admin="admins"/>
+              <authorizationEntry topic="USERS.>" read="users" write="users" admin="users"/>
+
+              <authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users"
+                                  admin="guests,users"/>
+            </authorizationEntries>
+
+            <tempDestinationAuthorizationEntry>
+              <tempDestinationAuthorizationEntry read="tempDestinationAdmins" write="tempDestinationAdmins"
+                                                 admin="tempDestinationAdmins"/>
+            </tempDestinationAuthorizationEntry>
+          </authorizationMap>
+        </map>
+      </authorizationPlugin>
+    </plugins>
+  </broker>
+</beans>