You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ce...@apache.org on 2014/02/24 16:30:49 UTC

[2/4] Fix for https://issues.apache.org/jira/browse/AMQ-3621 - Integrate Apache Shiro with ActiveMQ as "security solution" - many thanks to Les Hazlewood (lhazlewood) for the patch!

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/authc/DefaultAuthenticationPolicyTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/authc/DefaultAuthenticationPolicyTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authc/DefaultAuthenticationPolicyTest.java
new file mode 100644
index 0000000..0d39061
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authc/DefaultAuthenticationPolicyTest.java
@@ -0,0 +1,339 @@
+/**
+ * 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.shiro.authc;
+
+import org.apache.activemq.broker.Connection;
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.broker.Connector;
+import org.apache.activemq.broker.region.ConnectionStatistics;
+import org.apache.activemq.command.Command;
+import org.apache.activemq.command.ConnectionControl;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.activemq.command.Response;
+import org.apache.activemq.shiro.subject.SubjectAdapter;
+import org.apache.activemq.shiro.subject.SubjectConnectionReference;
+import org.apache.shiro.env.DefaultEnvironment;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class DefaultAuthenticationPolicyTest {
+
+    private DefaultAuthenticationPolicy policy;
+
+    @Before
+    public void setUp() {
+        this.policy = new DefaultAuthenticationPolicy();
+    }
+
+    @Test
+    public void testVmConnectionAuthenticationRequired() {
+        boolean required = true;
+        policy.setVmConnectionAuthenticationRequired(required);
+        assertEquals(required, policy.isVmConnectionAuthenticationRequired());
+    }
+
+    @Test
+    public void testSystemAccountUsername() {
+        String name = "foo";
+        policy.setSystemAccountUsername(name);
+        assertEquals(name, policy.getSystemAccountUsername());
+    }
+
+    @Test
+    public void testSystemAccountRealmName() {
+        String name = "fooRealm";
+        policy.setSystemAccountRealmName(name);
+        assertEquals(name, policy.getSystemAccountRealmName());
+    }
+
+    @Test
+    public void testAnonymousAllowed() {
+        boolean allowed = true;
+        policy.setAnonymousAccessAllowed(allowed);
+        assertEquals(allowed, policy.isAnonymousAccessAllowed());
+    }
+
+    @Test
+    public void testAnonymousAccountUsername() {
+        String name = "blah";
+        policy.setAnonymousAccountUsername(name);
+        assertEquals(name, policy.getAnonymousAccountUsername());
+    }
+
+    @Test
+    public void testAnonymousAccountRealmName() {
+        String name = "blahRealm";
+        policy.setAnonymousAccountRealmName(name);
+        assertEquals(name, policy.getAnonymousAccountRealmName());
+    }
+
+    @Test
+    public void testIsAnonymousAccount() {
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return new SimplePrincipalCollection("anonymous", "iniRealm");
+            }
+        };
+        assertTrue(policy.isAnonymousAccount(subject));
+    }
+
+    @Test
+    public void testIsAnonymousAccountWithNullPrincipals() {
+        assertFalse(policy.isAnonymousAccount(new SubjectAdapter()));
+    }
+
+    @Test
+    public void testIsSystemAccountWithNullPrincipals() {
+        assertFalse(policy.isSystemAccount(new SubjectAdapter()));
+    }
+
+    @Test
+    public void testIsAuthenticationRequiredWhenAlreadyRequired() {
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public boolean isAuthenticated() {
+                return true;
+            }
+        };
+        SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), subject);
+
+        assertFalse(policy.isAuthenticationRequired(sc));
+    }
+
+    @Test
+    public void testIsAuthenticationRequiredWhenAnonymousAllowedAnonymousSubject() {
+
+        policy.setAnonymousAccessAllowed(true);
+
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return new SimplePrincipalCollection("anonymous", "iniRealm");
+            }
+        };
+        SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), subject);
+
+        assertFalse(policy.isAuthenticationRequired(sc));
+    }
+
+    @Test
+    public void testIsAuthenticationRequiredWhenAnonymousAllowedAndNotAnonymousSubject() {
+
+        policy.setAnonymousAccessAllowed(true);
+
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return new SimplePrincipalCollection("system", "iniRealm");
+            }
+        };
+        SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), subject);
+
+        assertFalse(policy.isAuthenticationRequired(sc));
+    }
+
+    @Test
+    public void testIsAuthenticationRequiredWhenSystemConnectionAndSystemSubject() {
+
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return new SimplePrincipalCollection("system", "iniRealm");
+            }
+        };
+        SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), subject);
+
+        assertFalse(policy.isAuthenticationRequired(sc));
+    }
+
+    @Test
+    public void testIsAuthenticationRequiredWhenSystemConnectionRequiresAuthentication() {
+
+        policy.setVmConnectionAuthenticationRequired(true);
+
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return new SimplePrincipalCollection("system", "iniRealm");
+            }
+        };
+        SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), subject);
+
+        assertTrue(policy.isAuthenticationRequired(sc));
+    }
+
+    @Test
+    public void testIsAuthenticationRequiredWhenSystemConnectionDoesNotRequireAuthenticationAndNotSystemAccount() {
+
+        Subject subject = new SubjectAdapter() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return new SimplePrincipalCollection("foo", "iniRealm");
+            }
+        };
+        SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), subject);
+
+        assertTrue(policy.isAuthenticationRequired(sc));
+    }
+
+    @Test
+    public void testIsAssumeIdentity() {
+        policy.setAnonymousAccessAllowed(true);
+        assertTrue(policy.isAssumeIdentity(null));
+    }
+
+    @Test
+    public void testIsAssumeIdentityWithSystemConnection() {
+
+        ConnectionContext ctx = new ConnectionContext();
+        Connection connection = new Connection() {
+            @Override
+            public Connector getConnector() {
+                return null;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public void dispatchSync(Command message) {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public void dispatchAsync(Command command) {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public Response service(Command command) {
+                return null;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public void serviceException(Throwable error) {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isSlow() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isBlocked() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isConnected() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isActive() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public int getDispatchQueueSize() {
+                return 0;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public ConnectionStatistics getStatistics() {
+                return null;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isManageable() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public String getRemoteAddress() {
+                return "vm://localhost";
+            }
+
+            @Override
+            public void serviceExceptionAsync(IOException e) {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public String getConnectionId() {
+                return null;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isNetworkConnection() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isFaultTolerantConnection() {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public void updateClient(ConnectionControl control) {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public void start() throws Exception {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public void stop() throws Exception {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public int getActiveTransactionCount() {
+                return 0;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public Long getOldestActiveTransactionDuration() {
+                return null;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+        };
+
+        ctx.setConnection(connection);
+
+        SubjectConnectionReference sc = new SubjectConnectionReference(ctx, new ConnectionInfo(),
+                new DefaultEnvironment(), new SubjectAdapter());
+
+        assertTrue(policy.isAssumeIdentity(sc));
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQPermissionResolverTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQPermissionResolverTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQPermissionResolverTest.java
new file mode 100644
index 0000000..363f60b
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQPermissionResolverTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.shiro.authz;
+
+import org.apache.shiro.authz.Permission;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class ActiveMQPermissionResolverTest {
+
+    @Test
+    public void testDefault() {
+        ActiveMQPermissionResolver resolver = new ActiveMQPermissionResolver();
+        assertTrue(resolver.isCaseSensitive());
+        Permission p = resolver.resolvePermission("Foo:Bar");
+        assertNotNull(p);
+        assertTrue(p instanceof ActiveMQWildcardPermission);
+        assertTrue(p.implies(new ActiveMQWildcardPermission("Foo:Bar")));
+        assertFalse(p.implies(new ActiveMQWildcardPermission("foo:bar")));
+    }
+
+    @Test
+    public void testCaseInsensitive() {
+        ActiveMQPermissionResolver resolver = new ActiveMQPermissionResolver();
+        resolver.setCaseSensitive(false);
+        assertFalse(resolver.isCaseSensitive());
+        Permission p = resolver.resolvePermission("Foo:Bar");
+        assertNotNull(p);
+        assertTrue(p instanceof ActiveMQWildcardPermission);
+        assertTrue(p.implies(new ActiveMQWildcardPermission("foo:bar")));
+        assertTrue(p.implies(new ActiveMQWildcardPermission("Foo:Bar", true)));
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQWildcardPermissionTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQWildcardPermissionTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQWildcardPermissionTest.java
new file mode 100644
index 0000000..515aeeb
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/ActiveMQWildcardPermissionTest.java
@@ -0,0 +1,158 @@
+/**
+ * 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.shiro.authz;
+
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.authz.permission.WildcardPermission;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class ActiveMQWildcardPermissionTest {
+
+    @Test
+    public void testNotWildcardPermission() {
+        ActiveMQWildcardPermission perm = new ActiveMQWildcardPermission("topic:TEST:*");
+        Permission dummy = new Permission() {
+            @Override
+            public boolean implies(Permission p) {
+                return false;
+            }
+        };
+       assertFalse(perm.implies(dummy));
+    }
+
+    @Test
+    public void testIntrapartWildcard() {
+        ActiveMQWildcardPermission superset = new ActiveMQWildcardPermission("topic:ActiveMQ.Advisory.*:read");
+        ActiveMQWildcardPermission subset = new ActiveMQWildcardPermission("topic:ActiveMQ.Advisory.Topic:read");
+
+        assertTrue(superset.implies(subset));
+        assertFalse(subset.implies(superset));
+    }
+
+    @Test
+    public void testMatches() {
+        assertMatch("x", "x");
+        assertNoMatch("x", "y");
+
+        assertMatch("xx", "xx");
+        assertNoMatch("xy", "xz");
+
+        assertMatch("?", "x");
+        assertMatch("x?", "xy");
+        assertMatch("?y", "xy");
+        assertMatch("x?z", "xyz");
+
+        assertMatch("*", "x");
+        assertMatch("x*", "x");
+        assertMatch("x*", "xy");
+        assertMatch("xy*", "xy");
+        assertMatch("xy*", "xyz");
+
+        assertMatch("*x", "x");
+        assertNoMatch("*x", "y");
+
+        assertMatch("*x", "wx");
+        assertNoMatch("*x", "wz");
+        assertMatch("*x", "vwx");
+
+        assertMatch("x*z", "xz");
+        assertMatch("x*z", "xyz");
+        assertMatch("x*z", "xyyz");
+
+        assertNoMatch("ab*t?z", "abz");
+        assertNoMatch("ab*d*yz", "abcdz");
+
+        assertMatch("ab**cd**ef*yz", "abcdefyz");
+        assertMatch("a*c?*z", "abcxyz");
+        assertMatch("a*cd*z", "abcdxyz");
+
+        assertMatch("*", "x:x");
+        assertMatch("*", "x:x:x");
+        assertMatch("x", "x:y");
+        assertMatch("x", "x:y:z");
+
+        assertMatch("foo?armat*", "foobarmatches");
+        assertMatch("f*", "f");
+        assertNoMatch("foo", "f");
+        assertMatch("fo*b", "foob");
+        assertNoMatch("fo*b*r", "fooba");
+        assertNoMatch("foo*", "f");
+
+        assertMatch("t*k?ou", "thankyou");
+        assertMatch("he*l*world", "helloworld");
+        assertNoMatch("foo", "foob");
+
+        assertMatch("*:ActiveMQ.Advisory", "foo:ActiveMQ.Advisory");
+        assertNoMatch("*:ActiveMQ.Advisory", "foo:ActiveMQ.Advisory.");
+        assertMatch("*:ActiveMQ.Advisory*", "foo:ActiveMQ.Advisory");
+        assertMatch("*:ActiveMQ.Advisory*", "foo:ActiveMQ.Advisory.");
+        assertMatch("*:ActiveMQ.Advisory.*", "foo:ActiveMQ.Advisory.Connection");
+        assertMatch("*:ActiveMQ.Advisory*:read", "foo:ActiveMQ.Advisory.Connection:read");
+        assertNoMatch("*:ActiveMQ.Advisory*:read", "foo:ActiveMQ.Advisory.Connection:write");
+        assertMatch("*:ActiveMQ.Advisory*:*", "foo:ActiveMQ.Advisory.Connection:read");
+        assertMatch("*:ActiveMQ.Advisory*:*", "foo:ActiveMQ.Advisory.");
+        assertMatch("topic", "topic:TEST:*");
+        assertNoMatch("*:ActiveMQ*", "topic:TEST:*");
+        assertMatch("topic:ActiveMQ.Advisory*", "topic:ActiveMQ.Advisory.Connection:create");
+        assertMatch("foo?ar", "foobar");
+    }
+
+    protected static void assertMatch(String pattern, String value) {
+        assertTrue(matches(pattern, value));
+    }
+
+    protected static void assertNoMatch(String pattern, String value) {
+        assertFalse(matches(pattern, value));
+    }
+
+    protected static boolean matches(String pattern, String value) {
+        ActiveMQWildcardPermission patternPerm = new ActiveMQWildcardPermission(pattern);
+        WildcardPermission valuePerm = new WildcardPermission(value, true);
+        return patternPerm.implies(valuePerm);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testGetPartsByReflectionThrowingException() {
+
+        ActiveMQWildcardPermission perm = new ActiveMQWildcardPermission("foo:bar") {
+            @Override
+            protected List<Set<String>> doGetPartsByReflection(WildcardPermission wp) throws Exception {
+                throw new RuntimeException("Testing failure");
+            }
+        };
+
+        WildcardPermission otherPerm = new WildcardPermission("foo:bar:baz");
+
+        perm.implies(otherPerm);
+    }
+
+    @Test
+    public void testImpliesWithExtraParts() {
+        ActiveMQWildcardPermission perm1 = new ActiveMQWildcardPermission("foo:bar:baz");
+        ActiveMQWildcardPermission perm2 = new ActiveMQWildcardPermission("foo:bar");
+        assertFalse(perm1.implies(perm2));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/AuthorizationFilterTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/AuthorizationFilterTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/AuthorizationFilterTest.java
new file mode 100644
index 0000000..bc63f30
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/AuthorizationFilterTest.java
@@ -0,0 +1,364 @@
+/**
+ * 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.shiro.authz;
+
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.broker.ProducerBrokerExchange;
+import org.apache.activemq.broker.StubBroker;
+import org.apache.activemq.command.ActiveMQDestination;
+import org.apache.activemq.command.ActiveMQTextMessage;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.activemq.command.ConsumerInfo;
+import org.apache.activemq.command.DestinationInfo;
+import org.apache.activemq.command.ProducerInfo;
+import org.apache.activemq.shiro.subject.SubjectAdapter;
+import org.apache.activemq.shiro.subject.SubjectConnectionReference;
+import org.apache.activemq.shiro.subject.SubjectSecurityContext;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.authz.UnauthorizedException;
+import org.apache.shiro.env.Environment;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collection;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class AuthorizationFilterTest {
+
+    private AuthorizationFilter filter;
+    private StubBroker nextBroker;
+
+    @Before
+    public void setUp() {
+        filter = new AuthorizationFilter();
+        nextBroker = new StubBroker();
+        filter.setNext(nextBroker);
+    }
+
+    @Test
+    public void testDefaults() {
+        ActionPermissionResolver resolver = filter.getActionPermissionResolver();
+        assertNotNull(resolver);
+        assertTrue(resolver instanceof DestinationActionPermissionResolver);
+    }
+
+    @Test
+    public void testSetActionPermissionResolver() {
+        ActionPermissionResolver resolver = new DestinationActionPermissionResolver();
+        filter.setActionPermissionResolver(resolver);
+        assertSame(resolver, filter.getActionPermissionResolver());
+    }
+
+    private ConnectionContext createContext(Subject subject) {
+        ConnectionContext ctx = new ConnectionContext();
+        ConnectionInfo info = new ConnectionInfo();
+        Environment environment = new Environment() {
+            @Override
+            public org.apache.shiro.mgt.SecurityManager getSecurityManager() {
+                return null; //not needed in this test.
+            }
+        };
+        SubjectConnectionReference ref = new SubjectConnectionReference(ctx, info, environment, subject);
+        SubjectSecurityContext secCtx = new SubjectSecurityContext(ref);
+        ctx.setSecurityContext(secCtx);
+        return ctx;
+    }
+
+    @Test
+    public void testSubjectToString() {
+        Subject subject = new PermsSubject() {
+            @Override
+            public PrincipalCollection getPrincipals() {
+                return null;
+            }
+        };
+        String string = filter.toString(subject);
+        assertEquals("", string);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testAddDestinationInfoNotAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+        DestinationInfo info = new DestinationInfo(null, DestinationInfo.ADD_OPERATION_TYPE, dest);
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+
+        filter.addDestinationInfo(context, info);
+    }
+
+    @Test
+    public void testAddDestinationInfoAuthorized() throws Exception {
+
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+        DestinationInfo info = new DestinationInfo(null, DestinationInfo.ADD_OPERATION_TYPE, dest);
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:create");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+
+        filter.addDestinationInfo(context, info);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testAddDestinationNotAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+
+        filter.addDestination(context, dest, true);
+    }
+
+    @Test
+    public void testAddDestinationAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:create");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+
+        filter.addDestination(context, dest, true);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testRemoveDestinationInfoNotAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+        DestinationInfo info = new DestinationInfo(null, DestinationInfo.REMOVE_OPERATION_TYPE, dest);
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+
+        filter.removeDestinationInfo(context, info);
+    }
+
+    @Test
+    public void testRemoveDestinationInfoAuthorized() throws Exception {
+
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+        DestinationInfo info = new DestinationInfo(null, DestinationInfo.REMOVE_OPERATION_TYPE, dest);
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:remove");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+
+        filter.removeDestinationInfo(context, info);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testRemoveDestinationNotAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+
+        filter.removeDestination(context, dest, 1000);
+    }
+
+    @Test
+    public void testRemoveDestinationAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:remove");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+
+        filter.removeDestination(context, dest, 1000);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testAddConsumerNotAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+        ConsumerInfo info = new ConsumerInfo(null);
+        info.setDestination(dest);
+
+        filter.addConsumer(context, info);
+    }
+
+    @Test
+    public void testAddConsumerAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:read");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+        ConsumerInfo info = new ConsumerInfo(null);
+        info.setDestination(dest);
+
+        filter.addConsumer(context, info);
+    }
+
+    @Test
+    public void testAddProducerWithoutDestination() throws Exception {
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+        ProducerInfo info = new ProducerInfo(null);
+        filter.addProducer(context, info);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testAddProducerNotAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+        ProducerInfo info = new ProducerInfo(null);
+        info.setDestination(dest);
+
+        filter.addProducer(context, info);
+    }
+
+    @Test
+    public void testAddProducerAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:write");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+        ProducerInfo info = new ProducerInfo(null);
+        info.setDestination(dest);
+
+        filter.addProducer(context, info);
+    }
+
+    @Test(expected=UnauthorizedException.class)
+    public void testBrokerExchangeSendNotAuthorized() throws Exception {
+        String name = "myTopic";
+
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+        ActiveMQTextMessage message = new ActiveMQTextMessage();
+        message.setDestination(dest);
+        message.setText("Hello, world!");
+
+        Subject subject = new PermsSubject();
+        ConnectionContext context = createContext(subject);
+        ProducerBrokerExchange exchange = new ProducerBrokerExchange();
+        exchange.setConnectionContext(context);
+
+        filter.send(exchange, message);
+    }
+
+    @Test
+    public void testBrokerExchangeSendAuthorized() throws Exception {
+        String name = "myTopic";
+        ActiveMQDestination dest = new ActiveMQTopic(name);
+        ActiveMQTextMessage message = new ActiveMQTextMessage();
+        message.setDestination(dest);
+        message.setText("Hello, world!");
+
+        Subject subject = new PermsSubject() {
+            @Override
+            public boolean isPermitted(Permission toCheck) {
+                Permission assigned = createPerm("topic:myTopic:write");
+                assertEquals(assigned.toString(), toCheck.toString());
+                return assigned.implies(toCheck);
+            }
+        };
+
+        ConnectionContext context = createContext(subject);
+        ProducerBrokerExchange exchange = new ProducerBrokerExchange();
+        exchange.setConnectionContext(context);
+
+        filter.send(exchange, message);
+    }
+
+
+    protected Permission createPerm(String perm) {
+        return new DestinationActionPermissionResolver().createPermission(perm);
+    }
+
+
+    private static class PermsSubject extends SubjectAdapter {
+
+        @Override
+        public PrincipalCollection getPrincipals() {
+            return new SimplePrincipalCollection("foo", "someRealm");
+        }
+
+        @Override
+        public boolean isPermittedAll(Collection<Permission> permissions) {
+            assertNotNull(permissions);
+            assertEquals(1, permissions.size());
+            return isPermitted(permissions.iterator().next());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionPermissionResolverTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionPermissionResolverTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionPermissionResolverTest.java
new file mode 100644
index 0000000..329979f
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionPermissionResolverTest.java
@@ -0,0 +1,153 @@
+/**
+ * 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.shiro.authz;
+
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.command.ActiveMQDestination;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.command.ActiveMQTempQueue;
+import org.apache.activemq.command.ActiveMQTempTopic;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.apache.activemq.filter.AnyDestination;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.authz.permission.WildcardPermission;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collection;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class DestinationActionPermissionResolverTest {
+
+    private DestinationActionPermissionResolver resolver;
+
+    @Before
+    public void setUp() {
+        this.resolver = new DestinationActionPermissionResolver();
+    }
+
+    @Test
+    public void testDefaults() {
+        assertNull(resolver.getPermissionStringPrefix());
+        //default is true to reflect ActiveMQ's case-sensitive destination names:
+        assertTrue(resolver.isPermissionStringCaseSensitive());
+    }
+
+    @Test
+    public void testPermissionStringPrefixProp() {
+        String prefix = "foo";
+        resolver.setPermissionStringPrefix(prefix);
+        assertEquals(prefix, resolver.getPermissionStringPrefix());
+    }
+
+    @Test
+    public void testCaseSensitiveProp() {
+        resolver.setPermissionStringCaseSensitive(true);
+        assertTrue(resolver.isPermissionStringCaseSensitive());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPermissionsWithNonDestinationActionInstance() {
+        resolver.getPermissions(new Action() {
+            @Override
+            public String toString() {
+                return "foo";
+            }
+        });
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPermissionsWithNullArgument() {
+        resolver.getPermissions((Action)null);
+    }
+
+    void assertPermString(String perm, Collection<Permission> perms) {
+        assertEquals(1, perms.size());
+        assertEquals(perm, perms.iterator().next().toString());
+    }
+
+    @Test
+    public void testGetPermissionsWithTopic() {
+        ActiveMQTopic topic = new ActiveMQTopic("myTopic");
+        DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "create");
+        Collection<Permission> perms = resolver.getPermissions(action);
+        assertPermString("topic:myTopic:create", perms);
+    }
+
+    @Test
+    public void testGetPermissionsWithTemporaryTopic() {
+        ActiveMQTempTopic topic = new ActiveMQTempTopic("myTempTopic");
+        DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "remove");
+        Collection<Permission> perms = resolver.getPermissions(action);
+        assertPermString("temp-topic:myTempTopic:remove", perms);
+    }
+
+    @Test
+    public void testGetPermissionsWithQueue() {
+        ActiveMQQueue queue = new ActiveMQQueue("myQueue");
+        DestinationAction action = new DestinationAction(new ConnectionContext(), queue, "write");
+        Collection<Permission> perms = resolver.getPermissions(action);
+        assertPermString("queue:myQueue:write", perms);
+    }
+
+    @Test
+    public void testGetPermissionsWithTemporaryQueue() {
+        ActiveMQTempQueue queue = new ActiveMQTempQueue("myTempQueue");
+        DestinationAction action = new DestinationAction(new ConnectionContext(), queue, "read");
+        Collection<Permission> perms = resolver.getPermissions(action);
+        assertPermString("temp-queue:myTempQueue:read", perms);
+    }
+
+    @Test
+    public void testPermissionWithPrefix() {
+        resolver.setPermissionStringPrefix("activeMQ");
+        ActiveMQTopic topic = new ActiveMQTopic("myTopic");
+        DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "create");
+        Collection<Permission> perms = resolver.getPermissions(action);
+        assertPermString("activeMQ:topic:myTopic:create", perms);
+    }
+
+    //Ensures if they explicitly set a prefix with a colon suffix that we don't add another one
+    @Test
+    public void testPermissionWithPrefixAndExplicitColon() {
+        resolver.setPermissionStringPrefix("activeMQ:");
+        ActiveMQTopic topic = new ActiveMQTopic("myTopic");
+        DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "create");
+        Collection<Permission> perms = resolver.getPermissions(action);
+        assertPermString("activeMQ:topic:myTopic:create", perms);
+    }
+
+    @Test
+    public void testAlternateWildcardPermissionToStringWithMultipleActions() {
+        Permission perm = resolver.createPermission("foo:bar:action1,action2");
+        assertTrue(perm instanceof WildcardPermission);
+        assertEquals("foo:bar:action1,action2", perm.toString());
+
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testCreatePermissionStringWithCompositeDestination() {
+        ActiveMQTopic topicA = new ActiveMQTopic("A");
+        ActiveMQTopic topicB = new ActiveMQTopic("B");
+        ActiveMQDestination composite = new AnyDestination(new ActiveMQDestination[]{topicA, topicB});
+        resolver.createPermissionString(composite, "read");
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionTest.java
new file mode 100644
index 0000000..a5a9158
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/authz/DestinationActionTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.shiro.authz;
+
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class DestinationActionTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullConnectionContext() {
+        new DestinationAction(null, new ActiveMQQueue("foo"), "create");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullDestination() {
+        new DestinationAction(new ConnectionContext(), null, "create");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullVerb() {
+        new DestinationAction(new ConnectionContext(), new ActiveMQQueue("foo"), null);
+    }
+
+    @Test
+    public void testDefault() {
+        ConnectionContext ctx = new ConnectionContext();
+        ActiveMQQueue queue = new ActiveMQQueue("foo");
+        String verb = "create";
+
+        DestinationAction action = new DestinationAction(ctx, queue, verb);
+        assertSame(ctx, action.getConnectionContext());
+        assertSame(queue, action.getDestination());
+        assertEquals(verb, action.getVerb());
+        assertEquals("create destination: queue://foo", action.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/EnvironmentFilterTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/EnvironmentFilterTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/EnvironmentFilterTest.java
new file mode 100644
index 0000000..b95c9fb
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/EnvironmentFilterTest.java
@@ -0,0 +1,30 @@
+/**
+ * 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.shiro.env;
+
+import org.junit.Test;
+
+/**
+ * @since 5.10.0
+ */
+public class EnvironmentFilterTest {
+
+    @Test(expected=IllegalStateException.class)
+    public void testNullEnvironment() {
+        new EnvironmentFilter(){}.getEnvironment();
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/IniEnvironmentTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/IniEnvironmentTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/IniEnvironmentTest.java
new file mode 100644
index 0000000..0d7d654
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/env/IniEnvironmentTest.java
@@ -0,0 +1,121 @@
+/**
+ * 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.shiro.env;
+
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.config.ConfigurationException;
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @since 5.10.0
+ */
+public class IniEnvironmentTest {
+
+    IniEnvironment env;
+
+    @Before
+    public void setUp() {
+        env = new IniEnvironment();
+    }
+
+    protected void authenticate() {
+        authenticate("foo", "bar");
+    }
+
+    protected void authenticate(String username, String password) {
+        Subject subject = new Subject.Builder(env.getSecurityManager()).buildSubject();
+        subject.login(new UsernamePasswordToken(username, password));
+    }
+
+    @Test
+    public void testIniInstanceConstructorArg() {
+        Ini ini = new Ini();
+        ini.addSection("users").put("foo", "bar");
+        env = new IniEnvironment(ini);
+        authenticate();
+    }
+
+    @Test
+    public void testStringConstructorArg() {
+        String config =
+                "[users]\n" +
+                "foo = bar";
+
+        env = new IniEnvironment(config);
+        authenticate();
+    }
+
+    @Test
+    public void testSetIni() {
+        Ini ini = new Ini();
+        ini.addSection("users").put("foo", "bar");
+
+        env = new IniEnvironment();
+        env.setIni(ini);
+        env.init();
+
+        authenticate();
+    }
+
+    @Test
+    public void testSetIniString() {
+        String config =
+                "[users]\n" +
+                "foo = bar";
+
+        env = new IniEnvironment();
+        env.setIniConfig(config);
+        env.init();
+
+        authenticate();
+    }
+
+    @Test
+    public void testSetIniResourcePath() {
+        env = new IniEnvironment();
+        env.setIniResourcePath("classpath:minimal.shiro.ini");
+        env.init();
+
+        authenticate("system", "manager");
+    }
+
+    @Test
+    public void testDefaultClasspathIni() {
+        env = new IniEnvironment();
+        env.init();
+
+        authenticate("system", "manager");
+    }
+
+    @Test(expected = ConfigurationException.class)
+    public void testNoDefaultClasspathIni() {
+        env = new IniEnvironment() {
+            @Override
+            protected void apply(Ini ini) {
+                super.apply(ini);
+                //clear out the objects to simulate as if the ini file wasn't found:
+                this.objects.clear();
+            }
+        };
+        env.init();
+        authenticate("system", "manager");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/session/mgt/DisabledSessionManagerTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/session/mgt/DisabledSessionManagerTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/session/mgt/DisabledSessionManagerTest.java
new file mode 100644
index 0000000..df02ee0
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/session/mgt/DisabledSessionManagerTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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.shiro.session.mgt;
+
+import org.apache.shiro.session.mgt.DefaultSessionKey;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class DisabledSessionManagerTest {
+
+    private DisabledSessionManager mgr;
+
+    @Before
+    public void setUp() {
+        this.mgr = new DisabledSessionManager();
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testStart() {
+        mgr.start(null);
+    }
+
+    @Test
+    public void testGetSession() {
+        assertNull(mgr.getSession(null));
+        assertNull(mgr.getSession(new DefaultSessionKey("foo")));
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/ConnectionSubjectResolverTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/ConnectionSubjectResolverTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/ConnectionSubjectResolverTest.java
new file mode 100644
index 0000000..1404b71
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/ConnectionSubjectResolverTest.java
@@ -0,0 +1,80 @@
+/**
+ * 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.shiro.subject;
+
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.activemq.security.SecurityContext;
+import org.apache.shiro.env.DefaultEnvironment;
+import org.apache.shiro.subject.Subject;
+import org.junit.Test;
+
+import java.security.Principal;
+import java.util.Set;
+
+/**
+ * @since 5.10.0
+ */
+public class ConnectionSubjectResolverTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullConstructorArg() {
+        new ConnectionSubjectResolver((ConnectionContext)null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullSecurityContext() {
+        SubjectConnectionReference reference =
+                new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                        new DefaultEnvironment(), new SubjectAdapter());
+
+        new ConnectionSubjectResolver(reference);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNonSubjectSecurityContext() {
+        SubjectConnectionReference reference =
+                new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                        new DefaultEnvironment(), new SubjectAdapter());
+        reference.getConnectionContext().setSecurityContext(new SecurityContext("") {
+            @Override
+            public Set<Principal> getPrincipals() {
+                return null;
+            }
+        });
+
+        new ConnectionSubjectResolver(reference);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNullSubject() {
+
+        SubjectConnectionReference reference =
+                new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                        new DefaultEnvironment(), new SubjectAdapter());
+        reference.getConnectionContext().setSecurityContext(new SubjectSecurityContext(reference) {
+            @Override
+            public Subject getSubject() {
+                return null;
+            }
+        });
+
+        ConnectionSubjectResolver resolver = new ConnectionSubjectResolver(reference);
+        resolver.getSubject();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/DefaultConnectionSubjectFactoryTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/DefaultConnectionSubjectFactoryTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/DefaultConnectionSubjectFactoryTest.java
new file mode 100644
index 0000000..1774f50
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/DefaultConnectionSubjectFactoryTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.shiro.subject;
+
+import org.apache.activemq.shiro.ConnectionReference;
+import org.apache.activemq.shiro.authc.AuthenticationPolicy;
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class DefaultConnectionSubjectFactoryTest {
+
+    private DefaultConnectionSubjectFactory factory;
+
+    @Before
+    public void setUp() {
+        this.factory = new DefaultConnectionSubjectFactory();
+    }
+
+    @Test
+    public void testSetAuthenticationPolicy() {
+        AuthenticationPolicy policy = new AuthenticationPolicy() {
+            @Override
+            public void customizeSubject(Subject.Builder subjectBuilder, ConnectionReference ref) {
+                //To change body of implemented methods use File | Settings | File Templates.
+            }
+
+            @Override
+            public boolean isAuthenticationRequired(SubjectConnectionReference ref) {
+                return false;  //To change body of implemented methods use File | Settings | File Templates.
+            }
+        };
+        factory.setAuthenticationPolicy(policy);
+        assertSame(policy, factory.getAuthenticationPolicy());
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectAdapter.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectAdapter.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectAdapter.java
new file mode 100644
index 0000000..58f25e5
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectAdapter.java
@@ -0,0 +1,185 @@
+/**
+ * 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.shiro.subject;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.ExecutionException;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.Subject;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * @since 5.10.0
+ */
+public class SubjectAdapter implements Subject {
+
+    @Override
+    public Object getPrincipal() {
+        return null;
+    }
+
+    @Override
+    public PrincipalCollection getPrincipals() {
+        return null;
+    }
+
+    @Override
+    public boolean isPermitted(String permission) {
+        return false;
+    }
+
+    @Override
+    public boolean isPermitted(Permission permission) {
+        return false;
+    }
+
+    @Override
+    public boolean[] isPermitted(String... permissions) {
+        return new boolean[0];
+    }
+
+    @Override
+    public boolean[] isPermitted(List<Permission> permissions) {
+        return new boolean[0];
+    }
+
+    @Override
+    public boolean isPermittedAll(String... permissions) {
+        return false;
+    }
+
+    @Override
+    public boolean isPermittedAll(Collection<Permission> permissions) {
+        return false;
+    }
+
+    @Override
+    public void checkPermission(String permission) throws AuthorizationException {
+    }
+
+    @Override
+    public void checkPermission(Permission permission) throws AuthorizationException {
+    }
+
+    @Override
+    public void checkPermissions(String... permissions) throws AuthorizationException {
+    }
+
+    @Override
+    public void checkPermissions(Collection<Permission> permissions) throws AuthorizationException {
+    }
+
+    @Override
+    public boolean hasRole(String roleIdentifier) {
+        return false;
+    }
+
+    @Override
+    public boolean[] hasRoles(List<String> roleIdentifiers) {
+        return new boolean[0];  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public boolean hasAllRoles(Collection<String> roleIdentifiers) {
+        return false;
+    }
+
+    @Override
+    public void checkRole(String roleIdentifier) throws AuthorizationException {
+    }
+
+    @Override
+    public void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException {
+    }
+
+    @Override
+    public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
+    }
+
+    @Override
+    public void login(AuthenticationToken token) throws AuthenticationException {
+    }
+
+    @Override
+    public boolean isAuthenticated() {
+        return false;
+    }
+
+    @Override
+    public boolean isRemembered() {
+        return false;
+    }
+
+    @Override
+    public Session getSession() {
+        return null;
+    }
+
+    @Override
+    public Session getSession(boolean create) {
+        return null;
+    }
+
+    @Override
+    public void logout() {
+    }
+
+    @Override
+    public <V> V execute(Callable<V> callable) throws ExecutionException {
+        return null;
+    }
+
+    @Override
+    public void execute(Runnable runnable) {
+    }
+
+    @Override
+    public <V> Callable<V> associateWith(Callable<V> callable) {
+        return null;
+    }
+
+    @Override
+    public Runnable associateWith(Runnable runnable) {
+        return runnable;
+    }
+
+    @Override
+    public void runAs(PrincipalCollection principals) throws NullPointerException, IllegalStateException {
+    }
+
+    @Override
+    public boolean isRunAs() {
+        return false;
+    }
+
+    @Override
+    public PrincipalCollection getPreviousPrincipals() {
+        return null;
+    }
+
+    @Override
+    public PrincipalCollection releaseRunAs() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectConnectionReferenceTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectConnectionReferenceTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectConnectionReferenceTest.java
new file mode 100644
index 0000000..82b187b
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectConnectionReferenceTest.java
@@ -0,0 +1,33 @@
+/**
+ * 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.shiro.subject;
+
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.shiro.env.DefaultEnvironment;
+import org.junit.Test;
+
+/**
+ * @since 5.10.0
+ */
+public class SubjectConnectionReferenceTest {
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testNullSubject() {
+        new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(), new DefaultEnvironment(), null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectFilterTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectFilterTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectFilterTest.java
new file mode 100644
index 0000000..e2cbec7
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectFilterTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.shiro.subject;
+
+import org.apache.activemq.security.SecurityContext;
+import org.apache.activemq.shiro.SecurityContextFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 5.10.0
+ */
+public class SubjectFilterTest {
+
+    private SubjectFilter filter;
+
+    @Before
+    public void setUp() {
+        filter = new SubjectFilter();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void setNullSubjectConnectionFactory() {
+        filter.setConnectionSubjectFactory(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void setNullSecurityContextFactory() {
+        filter.setSecurityContextFactory(null);
+    }
+
+    @Test
+    public void testSetSecurityContextFactory() {
+        SecurityContextFactory factory = new SecurityContextFactory() {
+            @Override
+            public SecurityContext createSecurityContext(SubjectConnectionReference ref) {
+                return null;
+            }
+        };
+        filter.setSecurityContextFactory(factory);
+        assertSame(factory, filter.getSecurityContextFactory());
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectSecurityContextTest.java
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectSecurityContextTest.java b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectSecurityContextTest.java
new file mode 100644
index 0000000..49d70ed
--- /dev/null
+++ b/activemq-shiro/src/test/java/org/apache/activemq/shiro/subject/SubjectSecurityContextTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.shiro.subject;
+
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.shiro.env.DefaultEnvironment;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @since 5.10.0
+ */
+public class SubjectSecurityContextTest {
+
+    SubjectSecurityContext ctx;
+
+    @Before
+    public void setUp() {
+        SubjectConnectionReference conn = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
+                new DefaultEnvironment(), new SubjectAdapter());
+        ctx = new SubjectSecurityContext(conn);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testInOneOf() {
+        ctx.isInOneOf(null);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testGetAuthorizedReadDests() {
+        ctx.getAuthorizedReadDests();
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testGetAuthorizedWriteDests() {
+        ctx.getAuthorizedWriteDests();
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testGetPrincipals() {
+        ctx.getPrincipals();
+    }
+}

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/resources/empty.shiro.ini
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/resources/empty.shiro.ini b/activemq-shiro/src/test/resources/empty.shiro.ini
new file mode 100644
index 0000000..abe7ae5
--- /dev/null
+++ b/activemq-shiro/src/test/resources/empty.shiro.ini
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+# This empty file will cause an error at Shiro startup (as expected).  Used for testing purposes only.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/resources/minimal.shiro.ini
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/resources/minimal.shiro.ini b/activemq-shiro/src/test/resources/minimal.shiro.ini
new file mode 100644
index 0000000..0ccfc86
--- /dev/null
+++ b/activemq-shiro/src/test/resources/minimal.shiro.ini
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+[main]
+
+# Shiro object graph configuration here if desired/necessary
+
+[users]
+
+# users section format:
+#
+# username = password [, assignedRole1, assignedRole2, ..., assignedRoleN]
+#
+# for example:
+#
+# scott = tiger, users, administrators, advisory
+#
+# Roles and permissions assigned to roles are defined in the [roles] section
+# below. By transitive association, any user assigned a role is granted the
+# role's permissions.
+
+# ActiveMQ System User
+# needed for in-VM/local connections when authentication is enabled:
+system = manager, system
+
+[roles]
+
+# roles section format:
+#
+# roleName = wildcardPermission1, wildcardPermission2, ..., wildcardPermissionN
+
+# The 'system' role is assigned all permissions (*).  Be careful when assigning
+# this to actual users other than then system user!
+system = *
+
+# Full access rights should generally be given to the ActiveMQ.Advisory.*
+# destinations because by default an ActiveMQConnection uses advisory topics to
+# get early knowledge of temp destination creation and deletion. For more info:
+#
+#   http://activemq.apache.org/security.html
+#
+# So we create an 'advisory' role here with a wildcard/catch-all permissions
+# for all advisory topics.  To make your life easy, ensure you assign this to
+# any/all users, e.g.
+#
+#   jsmith = password, advisory, ...
+
+advisory = topic:ActiveMQ.Advisory*
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/resources/nosystem.shiro.ini
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/resources/nosystem.shiro.ini b/activemq-shiro/src/test/resources/nosystem.shiro.ini
new file mode 100644
index 0000000..6409c7f
--- /dev/null
+++ b/activemq-shiro/src/test/resources/nosystem.shiro.ini
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+[main]
+
+# THIS IS USED FOR TESTING PURPOSES ONLY.  DO NOT BASE YOUR CONFIGURATION OFF OF THIS FILE.
+
+# Shiro object graph configuration here if desired/necessary
+
+[users]
+# username is purposefully different than the system username:
+foo = bar, foo, advisory
+
+[roles]
+# Full access rights should generally be given to the ActiveMQ.Advisory.* destinations because by default an
+# ActiveMQConnection uses advisory topics to get early knowledge of temp destination creation and deletion.
+# See http://activemq.apache.org/security.html for more.
+#
+# So we create an 'advisory' role here with a wildcard/catch-all permissions for all advisory topics:
+advisory = topic:ActiveMQ.Advisory*
+
+# test specific roles/perms:
+foo = queue:QUEUE.org.apache.activemq.shiro.ShiroPluginTest.testRuntimeDisableEnableChanges:*

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/resources/org/apache/activemq/shiro/embedded-ini-config.xml
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/resources/org/apache/activemq/shiro/embedded-ini-config.xml b/activemq-shiro/src/test/resources/org/apache/activemq/shiro/embedded-ini-config.xml
new file mode 100644
index 0000000..dfe8e68
--- /dev/null
+++ b/activemq-shiro/src/test/resources/org/apache/activemq/shiro/embedded-ini-config.xml
@@ -0,0 +1,95 @@
+<?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.
+-->
+<!-- this file can only be parsed using the xbean-spring library -->
+<!-- START SNIPPET: example -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:amq="http://activemq.apache.org/schema/core"
+       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"
+            useJmx="false" persistent="false" populateJMSXUserID="true">
+
+        <destinations>
+            <queue physicalName="TEST.Q"/>
+        </destinations>
+
+        <transportConnectors>
+            <transportConnector name="default" uri="tcp://0.0.0.0:61616"/>
+        </transportConnectors>
+
+        <plugins>
+            <bean id="shiroPlugin"
+                  class="org.apache.activemq.shiro.ShiroPlugin"
+                  xmlns="http://www.springframework.org/schema/beans">
+                <property name="iniConfig">
+                    <value>
+                        [main]
+
+                        # Shiro object graph configuration here if desired/necessary
+
+                        [users]
+
+                        # users section format:
+                        #
+                        # username = password [, assignedRole1, assignedRole2, ..., assignedRoleN]
+                        #
+                        # for example:
+                        #
+                        # scott = tiger, users, administrators, advisory
+                        #
+                        # Roles and permissions assigned to roles are defined in the [roles] section
+                        # below. By transitive association, any user assigned a role is granted the
+                        # role's permissions.
+
+                        # ActiveMQ System User
+                        # needed for in-VM/local connections when authentication is enabled:
+                        system = manager, system
+
+                        [roles]
+
+                        # roles section format:
+                        #
+                        # roleName = wildcardPermission1, wildcardPermission2, ..., wildcardPermissionN
+
+                        # The 'system' role is assigned all permissions (*). Be careful when assigning
+                        # this to actual users other than then system user:
+                        system = *
+
+                        # Full access rights should generally be given to the ActiveMQ.Advisory.*
+                        # destinations because by default an ActiveMQConnection uses advisory topics to
+                        # get early knowledge of temp destination creation and deletion. For more info:
+                        #
+                        # http://activemq.apache.org/security.html
+                        #
+                        # So we create an 'advisory' role here with a wildcard/catch-all permissions
+                        # for all advisory topics. To make your life easy, ensure you assign this to
+                        # any/all users, e.g.
+                        #
+                        # jsmith = password, advisory, ...
+
+                        advisory = topic:ActiveMQ.Advisory*
+                    </value>
+                </property>
+            </bean>
+        </plugins>
+    </broker>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/activemq/blob/f9451e56/activemq-shiro/src/test/resources/org/apache/activemq/shiro/external-ini-config.xml
----------------------------------------------------------------------
diff --git a/activemq-shiro/src/test/resources/org/apache/activemq/shiro/external-ini-config.xml b/activemq-shiro/src/test/resources/org/apache/activemq/shiro/external-ini-config.xml
new file mode 100644
index 0000000..b4102d6
--- /dev/null
+++ b/activemq-shiro/src/test/resources/org/apache/activemq/shiro/external-ini-config.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<!-- this file can only be parsed using the xbean-spring library -->
+<!-- START SNIPPET: example -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:amq="http://activemq.apache.org/schema/core"
+       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"
+            useJmx="false" persistent="false" populateJMSXUserID="true">
+
+        <destinations>
+            <queue physicalName="TEST.Q"/>
+        </destinations>
+
+        <transportConnectors>
+            <transportConnector name="default" uri="tcp://0.0.0.0:61616"/>
+        </transportConnectors>
+
+        <plugins>
+            <bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin"
+                  xmlns="http://www.springframework.org/schema/beans">
+
+                <!-- Reference Shiro's ini config from an external path, e.g. classpath: -->
+                <property name="iniResourcePath" value="classpath:org/apache/activemq/shiro/external-ini-config.xml"/>
+
+                <!-- or it could be in another location, such as a URL or file:
+                <property name="iniResourcePath" value="url:http://config.somehost.com/mybroker/shiro.ini"/>
+                <property name="iniResourcePath" value="file:/usr/local/somewhere/shiro.ini"/> -->
+            </bean>
+        </plugins>
+    </broker>
+
+</beans>