Repository: activemq-artemis
Updated Branches:
  refs/heads/master 4cdcc618f -> e85bb3ca4


ARTEMIS-229 validate user and role with address


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

Branch: refs/heads/master
Commit: 6890f126cbd3df6ef0b096d4f1256ef540b9b36f
Parents: 4cdcc61
Author: Julian Scheid <julian...@gmail.com>
Authored: Fri Sep 25 14:08:28 2015 +0200
Committer: Julian Scheid <julian...@gmail.com>
Committed: Fri Sep 25 15:58:15 2015 +0200

----------------------------------------------------------------------
 .../core/security/impl/SecurityStoreImpl.java   |  12 +-
 .../core/security/ActiveMQSecurityManager2.java |  49 +++++
 .../integration/security/SecurityTest.java      | 211 +++++++++++++++++++
 3 files changed, 271 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6890f126/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
----------------------------------------------------------------------
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
index 209b424..a12ff4f 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java
@@ -34,6 +34,7 @@ import 
org.apache.activemq.artemis.core.server.management.NotificationService;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
 import 
org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
+import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
 import org.apache.activemq.artemis.utils.ConcurrentHashSet;
 import org.apache.activemq.artemis.utils.TypedProperties;
 
@@ -159,7 +160,16 @@ public class SecurityStoreImpl implements SecurityStore, 
HierarchicalRepositoryC
             return;
          }
 
-         if (!securityManager.validateUserAndRole(user, session.getPassword(), 
roles, checkType)) {
+         final boolean validated;
+         if (securityManager instanceof ActiveMQSecurityManager2) {
+            final ActiveMQSecurityManager2 securityManager2 = 
(ActiveMQSecurityManager2) securityManager;
+            validated = securityManager2.validateUserAndRole(user, 
session.getPassword(), roles, checkType, saddress);
+         }
+         else {
+            validated = securityManager.validateUserAndRole(user, 
session.getPassword(), roles, checkType);
+         }
+
+         if (!validated) {
             if (notificationService != null) {
                TypedProperties props = new TypedProperties();
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6890f126/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
----------------------------------------------------------------------
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
new file mode 100644
index 0000000..2962153
--- /dev/null
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
@@ -0,0 +1,49 @@
+/*
+ * 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.artemis.spi.core.security;
+
+import java.util.Set;
+
+import org.apache.activemq.artemis.core.security.CheckType;
+import org.apache.activemq.artemis.core.security.Role;
+
+/**
+ * Used to validate whether a user is authorized to connect to the
+ * server and perform certain functions on certain destinations.
+ *
+ * This is an evolution of {@link ActiveMQSecurityManager} that adds
+ * the ability to perform authorization taking the destination address
+ * into account.
+ */
+public interface ActiveMQSecurityManager2 extends ActiveMQSecurityManager {
+
+   /**
+    * Determine whether the given user is valid and whether they have
+    * the correct role for the given destination address.
+    *
+    * This method is called instead of
+    * {@link ActiveMQSecurityManager.validateUserAndRole}.
+    *
+    * @param user      the user
+    * @param password  the user's password
+    * @param roles     the user's roles
+    * @param checkType which permission to validate
+    * @param address   the address for which to perform authorization
+    * @return true if the user is valid and they have the correct roles for 
the given destination address
+    */
+   boolean validateUserAndRole(String user, String password, Set<Role> roles, 
CheckType checkType, String address);
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6890f126/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
----------------------------------------------------------------------
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
index 15b5423..1eb0ed8 100644
--- 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
@@ -33,10 +33,14 @@ import 
org.apache.activemq.artemis.api.core.client.ServerLocator;
 import org.apache.activemq.artemis.tests.util.CreateMessage;
 import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
 import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.security.CheckType;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.ActiveMQServer;
 import org.apache.activemq.artemis.core.server.Queue;
+import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
+import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
+import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
 import 
org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManagerImpl;
 import org.junit.Assert;
 import org.junit.Before;
@@ -1049,6 +1053,213 @@ public class SecurityTest extends ActiveMQTestBase {
 
    }
 
+   @Test
+   public void testCustomSecurityManager() throws Exception {
+      final Configuration configuration = 
createDefaultInVMConfig().setSecurityEnabled(true);
+      final ActiveMQSecurityManager customSecurityManager = new 
ActiveMQSecurityManager() {
+            public boolean validateUser(final String username, final String 
password) {
+               return (username.equals("foo") || username.equals("bar") || 
username.equals("all")) &&
+                  password.equals("frobnicate");
+            }
+            public boolean validateUserAndRole(
+               final String username,
+               final String password,
+               final Set<Role> requiredRoles,
+               final CheckType checkType) {
+
+               if ((username.equals("foo") || username.equals("bar") || 
username.equals("all")) &&
+                   password.equals("frobnicate")) {
+
+                  if (username.equals("all")) {
+                     return true;
+                  }
+                  else if (username.equals("foo")) {
+                     return checkType == CheckType.CONSUME || checkType == 
CheckType.CREATE_NON_DURABLE_QUEUE;
+                  }
+                  else if (username.equals("bar")) {
+                     return checkType == CheckType.SEND || checkType == 
CheckType.CREATE_NON_DURABLE_QUEUE;
+                  }
+                  else {
+                     return false;
+                  }
+               }
+               else {
+                  return false;
+               }
+            }
+         };
+      final ActiveMQServer server = addServer(new 
ActiveMQServerImpl(configuration, customSecurityManager));
+      server.start();
+
+      final ServerLocator locator = createInVMNonHALocator();
+      locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true);
+      final ClientSessionFactory factory = createSessionFactory(locator);
+      ClientSession adminSession = factory.createSession("all", "frobnicate", 
false, true, true, false, -1);
+
+      final String queueName = "test.queue";
+      adminSession.createQueue(queueName, queueName, false);
+
+      // Wrong user name
+      try {
+         factory.createSession("baz", "frobnicate", false, true, true, false, 
-1);
+         Assert.fail("should throw exception");
+      }
+      catch (ActiveMQSecurityException se) {
+         //ok
+      }
+      catch (ActiveMQException e) {
+         fail("Invalid Exception type:" + e.getType());
+      }
+
+      // Wrong password
+      try {
+         factory.createSession("foo", "xxx", false, true, true, false, -1);
+         Assert.fail("should throw exception");
+      }
+      catch (ActiveMQSecurityException se) {
+         //ok
+      }
+      catch (ActiveMQException e) {
+         fail("Invalid Exception type:" + e.getType());
+      }
+
+      // Correct user and password, allowed to send but not receive
+      {
+         final ClientSession session = factory.createSession("foo", 
"frobnicate", false, true, true, false, -1);
+         checkUserReceiveNoSend(queueName, session, adminSession);
+      }
+
+      // Correct user and password, allowed to receive but not send
+      {
+         final ClientSession session = factory.createSession("bar", 
"frobnicate", false, true, true, false, -1);
+         checkUserSendNoReceive(queueName, session);
+      }
+
+   }
+
+   @Test
+   public void testCustomSecurityManager2() throws Exception {
+      final Configuration configuration = 
createDefaultInVMConfig().setSecurityEnabled(true);
+      final ActiveMQSecurityManager customSecurityManager = new 
ActiveMQSecurityManager2() {
+            public boolean validateUser(final String username, final String 
password) {
+               return (username.equals("foo") || username.equals("bar") || 
username.equals("all")) &&
+                  password.equals("frobnicate");
+            }
+            public boolean validateUserAndRole(
+               final String username,
+               final String password,
+               final Set<Role> requiredRoles,
+               final CheckType checkType) {
+
+               fail("Unexpected call to overridden method");
+               return false;
+            }
+
+            public boolean validateUserAndRole(
+               final String username,
+               final String password,
+               final Set<Role> requiredRoles,
+               final CheckType checkType,
+               final String address) {
+
+               if ((username.equals("foo") || username.equals("bar") || 
username.equals("all")) &&
+                   password.equals("frobnicate")) {
+
+                  if (username.equals("all")) {
+                     return true;
+                  }
+                  else if (username.equals("foo")) {
+                     return address.equals("test.queue") && checkType == 
CheckType.CONSUME;
+                  }
+                  else if (username.equals("bar")) {
+                     return address.equals("test.queue") && checkType == 
CheckType.SEND;
+                  }
+                  else {
+                     return false;
+                  }
+               }
+               else {
+                  return false;
+               }
+            }
+         };
+      final ActiveMQServer server = addServer(new 
ActiveMQServerImpl(configuration, customSecurityManager));
+      server.start();
+
+      final ServerLocator locator = createInVMNonHALocator();
+      locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true);
+      final ClientSessionFactory factory = createSessionFactory(locator);
+      ClientSession adminSession = factory.createSession("all", "frobnicate", 
false, true, true, false, -1);
+
+      final String queueName = "test.queue";
+      adminSession.createQueue(queueName, queueName, false);
+
+      final String otherQueueName = "other.queue";
+      adminSession.createQueue(otherQueueName, otherQueueName, false);
+
+      // Wrong user name
+      try {
+         factory.createSession("baz", "frobnicate", false, true, true, false, 
-1);
+         Assert.fail("should throw exception");
+      }
+      catch (ActiveMQSecurityException se) {
+         //ok
+      }
+      catch (ActiveMQException e) {
+         fail("Invalid Exception type:" + e.getType());
+      }
+
+      // Wrong password
+      try {
+         factory.createSession("foo", "xxx", false, true, true, false, -1);
+         Assert.fail("should throw exception");
+      }
+      catch (ActiveMQSecurityException se) {
+         //ok
+      }
+      catch (ActiveMQException e) {
+         fail("Invalid Exception type:" + e.getType());
+      }
+
+      // Correct user and password, wrong queue for sending
+      try {
+         final ClientSession session = factory.createSession("foo", 
"frobnicate", false, true, true, false, -1);
+         checkUserReceiveNoSend(otherQueueName, session, adminSession);
+         Assert.fail("should throw exception");
+      }
+      catch (ActiveMQSecurityException se) {
+         //ok
+      }
+      catch (ActiveMQException e) {
+         fail("Invalid Exception type:" + e.getType());
+      }
+
+      // Correct user and password, wrong queue for receiving
+      try {
+         final ClientSession session = factory.createSession("foo", 
"frobnicate", false, true, true, false, -1);
+         checkUserReceiveNoSend(otherQueueName, session, adminSession);
+         Assert.fail("should throw exception");
+      }
+      catch (ActiveMQSecurityException se) {
+         //ok
+      }
+      catch (ActiveMQException e) {
+         fail("Invalid Exception type:" + e.getType());
+      }
+
+      // Correct user and password, allowed to send but not receive
+      {
+         final ClientSession session = factory.createSession("foo", 
"frobnicate", false, true, true, false, -1);
+         checkUserReceiveNoSend(queueName, session, adminSession);
+      }
+
+      // Correct user and password, allowed to receive but not send
+      {
+         final ClientSession session = factory.createSession("bar", 
"frobnicate", false, true, true, false, -1);
+         checkUserSendNoReceive(queueName, session);
+      }
+   }
+
    // Check the user connection has both send and receive permissions on the 
queue
    private void checkUserSendAndReceive(final String genericQueueName,
                                         final ClientSession connection) throws 
Exception {

Reply via email to