[prev in list] [next in list] [prev in thread] [next in thread] 

List:       activemq-commits
Subject:    [activemq-artemis] branch master updated: ARTEMIS-3014 Fix JMX RBAC guard
From:       jbertram () apache ! org
Date:       2020-11-30 17:12:43
Message-ID: 160675636347.947.17560243313932091087 () gitbox ! apache ! org
[Download RAW message or body]

This is an automated email from the ASF dual-hosted git repository.

jbertram pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/master by this push:
     new 7eb22c1  ARTEMIS-3014 Fix JMX RBAC guard
     new f64dfea  This closes #3364
7eb22c1 is described below

commit 7eb22c18db4bd81ef79c619173579cb54442fa9e
Author: Domenico Francesco Bruscino <brusdev@apache.org>
AuthorDate: Sat Nov 28 23:10:05 2020 +0100

    ARTEMIS-3014 Fix JMX RBAC guard
---
 .../artemis/cli/factory/jmx/ManagementFactory.java |   2 +
 .../apache/activemq/artemis/util/ServerUtil.java   |  12 +-
 .../core/server/management/ManagementContext.java  |  18 +--
 tests/smoke-tests/pom.xml                          |  20 +++
 .../main/resources/servers/jmx-rbac/management.xml |  52 ++++++++
 .../artemis/tests/smoke/jmxrbac/JmxRBACTest.java   | 137 +++++++++++++++++++++
 6 files changed, 231 insertions(+), 10 deletions(-)

diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/jmx/ManagementFactory.java \
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/jmx/ManagementFactory.java
 index 826dc8e..b41a1ef 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/jmx/ManagementFactory.java
                
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/jmx/ManagementFactory.java
 @@ -134,6 +134,8 @@ public class ManagementFactory {
          context.setSecurityManager(securityManager);
       }
 
+      context.init();
+
       return context;
    }
 }
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/util/ServerUtil.java \
b/artemis-cli/src/main/java/org/apache/activemq/artemis/util/ServerUtil.java index \
                7c8675b..6d7cf8f 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/util/ServerUtil.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/util/ServerUtil.java
@@ -105,14 +105,22 @@ public class ServerUtil {
    }
 
    public static boolean waitForServerToStart(int id, int timeout) throws \
                InterruptedException {
-      return waitForServerToStart("tcp://localhost:" + (61616 + id), timeout);
+      return waitForServerToStart(id, null, null, timeout);
+   }
+
+   public static boolean waitForServerToStart(int id, String username, String \
password, int timeout) throws InterruptedException { +      return \
waitForServerToStart("tcp://localhost:" + (61616 + id), username, password, timeout); \
}  
    public static boolean waitForServerToStart(String uri, long timeout) throws \
InterruptedException { +      return waitForServerToStart(uri, null, null, timeout);
+   }
+
+   public static boolean waitForServerToStart(String uri, String username, String \
password, long timeout) throws InterruptedException {  long realTimeout = \
System.currentTimeMillis() + timeout;  while (System.currentTimeMillis() < \
                realTimeout) {
          try (ActiveMQConnectionFactory cf = \
                ActiveMQJMSClient.createConnectionFactory(uri, null)) {
-            cf.createConnection().close();
+            cf.createConnection(username, password).close();
             System.out.println("server " + uri + " started");
          } catch (Exception e) {
             System.out.println("awaiting server " + uri + " start at ");
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java \
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java
 index f518c2d..db308ac 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java
                
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java
 @@ -34,6 +34,16 @@ public class ManagementContext implements ServiceComponent {
    private ArtemisMBeanServerGuard guardHandler;
    private ActiveMQSecurityManager securityManager;
 
+   public void init() {
+      if (accessControlList != null) {
+         //if we are configured then assume we want to use the guard so set the \
system property +         System.setProperty("javax.management.builder.initial", \
ArtemisMBeanServerBuilder.class.getCanonicalName()); +         guardHandler = new \
ArtemisMBeanServerGuard(); +         \
guardHandler.setJMXAccessControlList(accessControlList); +         \
ArtemisMBeanServerBuilder.setGuard(guardHandler); +      }
+   }
+
    @Override
    public void start() throws Exception {
       if (isStarted) {
@@ -44,14 +54,6 @@ public class ManagementContext implements ServiceComponent {
             return;
          }
          isStarted = true;
-         if (accessControlList != null) {
-            //if we are configured then assume we want to use the guard so set the \
                system property
-            System.setProperty("javax.management.builder.initial", \
                ArtemisMBeanServerBuilder.class.getCanonicalName());
-            guardHandler = new ArtemisMBeanServerGuard();
-            guardHandler.setJMXAccessControlList(accessControlList);
-            ArtemisMBeanServerBuilder.setGuard(guardHandler);
-         }
-
          if (jmxConnectorConfiguration != null) {
             mBeanServer = new ManagementConnector(jmxConnectorConfiguration, \
securityManager);  mBeanServer.start();
diff --git a/tests/smoke-tests/pom.xml b/tests/smoke-tests/pom.xml
index 5bf24ce..3c5bd43 100644
--- a/tests/smoke-tests/pom.xml
+++ b/tests/smoke-tests/pom.xml
@@ -406,6 +406,26 @@
                </execution>
                <execution>
                   <phase>test-compile</phase>
+                  <id>create-createJMXRBAC</id>
+                  <goals>
+                     <goal>create</goal>
+                  </goals>
+                  <configuration>
+                     <role>amq</role>
+                     <user>admin</user>
+                     <password>admin</password>
+                     <allowAnonymous>false</allowAnonymous>
+                     <instance>${basedir}/target/jmx-rbac</instance>
+                     \
<configuration>${basedir}/target/classes/servers/jmx-rbac</configuration> +           \
<args> +                        <!-- this is needed to run the server remotely -->
+                        <arg>--java-options</arg>
+                        <arg>-Djava.rmi.server.hostname=localhost</arg>
+                     </args>
+                  </configuration>
+               </execution>
+               <execution>
+                  <phase>test-compile</phase>
                   <id>create-createAuditLogging</id>
                   <goals>
                      <goal>create</goal>
diff --git a/tests/smoke-tests/src/main/resources/servers/jmx-rbac/management.xml \
b/tests/smoke-tests/src/main/resources/servers/jmx-rbac/management.xml new file mode \
100644 index 0000000..44e491e
--- /dev/null
+++ b/tests/smoke-tests/src/main/resources/servers/jmx-rbac/management.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<management-context xmlns="http://activemq.org/schema">
+   <connector connector-port="10099"/>
+   <authorisation>
+      <whitelist>
+         <entry domain="hawtio"/>
+      </whitelist>
+      <default-access>
+         <access method="list*" roles="amq"/>
+         <access method="get*" roles="amq"/>
+         <access method="is*" roles="amq"/>
+         <access method="set*" roles="amq"/>
+         <access method="*" roles="amq"/>
+      </default-access>
+      <role-access>
+         <match domain="java.lang" key="type=Memory">
+            <access method="gc" roles="amq-user"/>
+         </match>
+         <match domain="org.apache.activemq.artemis">
+            <access method="list*" roles="amq"/>
+            <access method="get*" roles="amq"/>
+            <access method="is*" roles="amq"/>
+            <access method="set*" roles="amq"/>
+            <access method="*" roles="amq"/>
+         </match>
+         <!--example of how to configure a specific object-->
+         <!--<match domain="org.apache.activemq.artemis" key="subcomponent=queues">
+            <access method="list*" roles="view,update,amq"/>
+            <access method="get*" roles="view,update,amq"/>
+            <access method="is*" roles="view,update,amq"/>
+            <access method="set*" roles="update,amq"/>
+            <access method="*" roles="amq"/>
+         </match>-->
+      </role-access>
+   </authorisation>
+</management-context>
\ No newline at end of file
diff --git a/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java \
b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java
 new file mode 100644
index 0000000..c25eced
--- /dev/null
+++ b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java
 @@ -0,0 +1,137 @@
+/**
+ * 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.tests.smoke.jmxrbac;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import java.util.Collections;
+
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
+import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl;
+import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder;
+import org.apache.activemq.artemis.tests.smoke.common.SmokeTestBase;
+import org.apache.activemq.artemis.util.ServerUtil;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JmxRBACTest extends SmokeTestBase {
+   // This test will use a smoke created by the pom on this project (smoke-tsts)
+
+   private static final String JMX_SERVER_HOSTNAME = "localhost";
+   private static final int JMX_SERVER_PORT = 10099;
+
+   public static final String SERVER_NAME_0 = "jmx-rbac";
+
+   public static final String SERVER_ADMIN = "admin";
+   public static final String SERVER_USER = "user";
+
+
+   @Before
+   public void before() throws Exception {
+      cleanupData(SERVER_NAME_0);
+      disableCheckThread();
+      startServer(SERVER_NAME_0, 0, 0);
+      ServerUtil.waitForServerToStart(0, SERVER_ADMIN, SERVER_ADMIN, 30000);
+   }
+
+   @Test
+   public void testManagementRoleAccess() throws Exception {
+      // Without this, the RMI server would bind to the default interface IP (the \
user's local IP mostly) +      System.setProperty("java.rmi.server.hostname", \
JMX_SERVER_HOSTNAME); +
+      // I don't specify both ports here manually on purpose. See actual RMI \
registry connection port extraction below. +      String urlString = \
"service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + \
"/jmxrmi"; +
+      JMXServiceURL url = new JMXServiceURL(urlString);
+      JMXConnector jmxConnector;
+
+      try {
+         //Connect using the admin.
+         jmxConnector = JMXConnectorFactory.connect(url, Collections.singletonMap(
+            "jmx.remote.credentials", new String[] {SERVER_ADMIN, SERVER_ADMIN}));
+         System.out.println("Successfully connected to: " + urlString);
+      } catch (Exception e) {
+         jmxConnector = null;
+         e.printStackTrace();
+         Assert.fail(e.getMessage());
+      }
+
+      try {
+         //Create an user.
+         MBeanServerConnection mBeanServerConnection = \
jmxConnector.getMBeanServerConnection(); +         String brokerName = "0.0.0.0";  // \
configured e.g. in broker.xml <broker-name> element +         ObjectNameBuilder \
objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), \
brokerName, true); +         ActiveMQServerControl activeMQServerControl = \
MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, \
objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); \
+         ObjectName memoryObjectName = new ObjectName("java.lang:type=Memory"); +
+         try {
+            activeMQServerControl.removeUser(SERVER_USER);
+         } catch (Exception ignore) {
+         }
+         activeMQServerControl.addUser(SERVER_USER, SERVER_USER, "amq-user", true);
+
+         activeMQServerControl.getVersion();
+
+         try {
+            mBeanServerConnection.invoke(memoryObjectName, "gc", null, null);
+            Assert.fail(SERVER_ADMIN + " should not access to " + memoryObjectName);
+         } catch (Exception e) {
+            Assert.assertEquals(SecurityException.class, e.getClass());
+         }
+      } finally {
+         jmxConnector.close();
+      }
+
+      try {
+         //Connect using an user.
+         jmxConnector = JMXConnectorFactory.connect(url, Collections.singletonMap(
+            "jmx.remote.credentials", new String[] {SERVER_USER, SERVER_USER}));
+         System.out.println("Successfully connected to: " + urlString);
+      } catch (Exception e) {
+         jmxConnector = null;
+         e.printStackTrace();
+         Assert.fail(e.getMessage());
+      }
+
+
+      try {
+         MBeanServerConnection mBeanServerConnection = \
jmxConnector.getMBeanServerConnection(); +         String brokerName = "0.0.0.0";  // \
configured e.g. in broker.xml <broker-name> element +         ObjectNameBuilder \
objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), \
brokerName, true); +         ActiveMQServerControl activeMQServerControl = \
MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, \
objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); \
+         ObjectName memoryObjectName = new ObjectName("java.lang:type=Memory"); +
+         mBeanServerConnection.invoke(memoryObjectName, "gc", null, null);
+
+         try {
+            activeMQServerControl.getVersion();
+            Assert.fail(SERVER_USER + " should not access to " + \
objectNameBuilder.getActiveMQServerObjectName()); +         } catch (Exception e) {
+            Assert.assertEquals(SecurityException.class, e.getClass());
+         }
+      } finally {
+         jmxConnector.close();
+      }
+   }
+}


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic