You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2020/02/20 10:26:53 UTC

[cxf] 01/02: Prevent RMI registry rebind (#641)

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

coheigea pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 98ec361acd390483005de12ca3b10cf49cbdcf8a
Author: Jonathan Gallimore <jo...@jrg.me.uk>
AuthorDate: Thu Feb 20 10:25:11 2020 +0000

    Prevent RMI registry rebind (#641)
    
    * Prevent registry rebind
    
    * Add the RMI server when not running threaded
    
    * Update MBServerConnectorFactory.java
    
    * Add compiler option for Java 11. Will look to see if there's a way to avoid the use of sun.rmi.registry altogether
    
    * Identify the lookup name from the JMX URL
    
    * Adding unit test for getBindingName()
    
    * Re-instating test removed by mistake
    
    Co-authored-by: Colm O hEigeartaigh <co...@users.noreply.github.com>
    (cherry picked from commit 543de65106515538ecaef8b57c554e88a7bda0d1)
---
 parent/pom.xml                                     |   5 +-
 rt/management/pom.xml                              |   3 +-
 .../management/jmx/MBServerConnectorFactory.java   | 102 ++++++++++++++++++---
 .../jmx/MBServerConnectorFactoryTest.java          |  55 +++++++++++
 4 files changed, 149 insertions(+), 16 deletions(-)

diff --git a/parent/pom.xml b/parent/pom.xml
index b035441..400d332 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2813,7 +2813,10 @@
                         <configuration>
                             <showDeprecation>${cxf.compile.show.deprecation}</showDeprecation>
                             <showWarnings>true</showWarnings>
-                            <compilerArgument>${cxf.compile.flags}</compilerArgument>
+                            <compilerArgs>
+                                <arg>${cxf.compile.flags}</arg>
+                                <arg>--add-exports</arg><arg>java.rmi/sun.rmi.registry=ALL-UNNAMED</arg>
+                            </compilerArgs>
                         </configuration>
                     </plugin>
                     <plugin>
diff --git a/rt/management/pom.xml b/rt/management/pom.xml
index cc042e3..faff4a7 100644
--- a/rt/management/pom.xml
+++ b/rt/management/pom.xml
@@ -34,7 +34,8 @@
         <cxf.module.name>org.apache.cxf.management</cxf.module.name>
         <cxf.osgi.import>
             javax.xml.bind*;version="${cxf.osgi.javax.bind.version}",
-            javax.annotation*;version="${cxf.osgi.javax.annotation.version}"
+            javax.annotation*;version="${cxf.osgi.javax.annotation.version}",
+            sun.rmi*;resolution:=optional
         </cxf.osgi.import>
     </properties>
     <dependencies>
diff --git a/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java b/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java
index 6906333..5eb7059 100644
--- a/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java
+++ b/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java
@@ -20,7 +20,13 @@
 package org.apache.cxf.management.jmx;
 
 import java.io.IOException;
-import java.rmi.registry.LocateRegistry;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -28,8 +34,9 @@ import java.util.logging.Logger;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerFactory;
 import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.management.remote.rmi.RMIJRMPServerImpl;
 
 import org.apache.cxf.common.logging.LogUtils;
 
@@ -57,6 +64,10 @@ public final class MBServerConnectorFactory {
 
     private static JMXConnectorServer connectorServer;
 
+    private static Remote remoteServerStub;
+
+    private static RMIJRMPServerImpl rmiServer;
+
     private static class MBServerConnectorFactoryHolder {
         private static final MBServerConnectorFactory INSTANCE =
             new MBServerConnectorFactory();
@@ -71,7 +82,7 @@ public final class MBServerConnectorFactory {
 
     }
 
-    private int getURLLocalHostPort(String url) {
+    static int getServerPort(final String url) {
         int portStart = url.indexOf("localhost") + 10;
         int portEnd;
         int port = 0;
@@ -127,29 +138,24 @@ public final class MBServerConnectorFactory {
         }
 
         // Create the JMX service URL.
-        JMXServiceURL url = new JMXServiceURL(serviceUrl);
+        final JMXServiceURL url = new JMXServiceURL(serviceUrl);
 
         // if the URL is localhost, start up an Registry
         if (serviceUrl.indexOf("localhost") > -1
             && url.getProtocol().compareToIgnoreCase("rmi") == 0) {
             try {
-                int port = getURLLocalHostPort(serviceUrl);
-                try {
-                    LocateRegistry.createRegistry(port);
-                } catch (Exception ex) {
-                    // the registry may had been created
-                    LocateRegistry.getRegistry(port);
-                }
+                int port = getRegistryPort(serviceUrl);
+                new JmxRegistry(port, getBindingName(url));
 
             } catch (Exception ex) {
                 LOG.log(Level.SEVERE, "CREATE_REGISTRY_FAULT_MSG", new Object[]{ex});
             }
         }
 
-        // Create the connector server now.
-        connectorServer =
-            JMXConnectorServerFactory.newJMXConnectorServer(url, environment, server);
+        rmiServer = new RMIJRMPServerImpl(getServerPort(serviceUrl), null, null, environment);
 
+        // Create the connector server now.
+        connectorServer = new RMIConnectorServer(url, environment, rmiServer, server);
 
         if (threaded) {
              // Start the connector server asynchronously (in a separate thread).
@@ -157,6 +163,7 @@ public final class MBServerConnectorFactory {
                 public void run() {
                     try {
                         connectorServer.start();
+                        remoteServerStub = rmiServer.toStub();
                     } catch (IOException ex) {
                         LOG.log(Level.SEVERE, "START_CONNECTOR_FAILURE_MSG", new Object[]{ex});
                     }
@@ -169,6 +176,7 @@ public final class MBServerConnectorFactory {
         } else {
              // Start the connector server in the same thread.
             connectorServer.start();
+            remoteServerStub = rmiServer.toStub();
         }
 
         if (LOG.isLoggable(Level.INFO)) {
@@ -176,6 +184,38 @@ public final class MBServerConnectorFactory {
         }
     }
 
+    static int getRegistryPort(final String url) {
+        int serverStart = url.indexOf("/jndi/rmi://");
+        final String serverPart = url.substring(serverStart + 12);
+        int portStart = serverPart.indexOf(':') + 1;
+
+        int portEnd;
+        int port = 0;
+        if (portStart > 0) {
+            portEnd = indexNotOfNumber(serverPart, portStart);
+            if (portEnd > portStart) {
+                final String portString = serverPart.substring(portStart, portEnd);
+                port = Integer.parseInt(portString);
+            }
+        }
+        return port;
+    }
+
+    protected static String getBindingName(final JMXServiceURL jmxServiceURL) {
+        final String urlPath = jmxServiceURL.getURLPath();
+
+        try {
+            if (urlPath.startsWith("/jndi/")) {
+                return new URI(urlPath.substring(6)).getPath()
+                        .replaceAll("^/+", "").replaceAll("/+$", "");
+            }
+        } catch (URISyntaxException e) {
+            // ignore
+        }
+
+        return "jmxrmi"; // use the default
+    }
+
     public void destroy() throws IOException {
         connectorServer.stop();
         if (LOG.isLoggable(Level.INFO)) {
@@ -183,4 +223,38 @@ public final class MBServerConnectorFactory {
         }
     }
 
+    /*
+     * Better to use the internal API than re-invent the wheel.
+     */
+    @SuppressWarnings("restriction")
+    private class JmxRegistry extends sun.rmi.registry.RegistryImpl {
+        private final String lookupName;
+
+        JmxRegistry(final int port, final String lookupName) throws RemoteException {
+            super(port);
+            this.lookupName = lookupName;
+        }
+
+        @Override
+        public Remote lookup(String s) throws RemoteException, NotBoundException {
+            return lookupName.equals(s) ? remoteServerStub : null;
+        }
+
+        @Override
+        public void bind(String s, Remote remote) throws RemoteException, AlreadyBoundException, AccessException {
+        }
+
+        @Override
+        public void unbind(String s) throws RemoteException, NotBoundException, AccessException {
+        }
+
+        @Override
+        public void rebind(String s, Remote remote) throws RemoteException, AccessException {
+        }
+
+        @Override
+        public String[] list() throws RemoteException {
+            return new String[] {lookupName};
+        }
+    }
 }
diff --git a/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.java b/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.java
new file mode 100644
index 0000000..468ec0c
--- /dev/null
+++ b/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.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.cxf.management.jmx;
+
+import javax.management.remote.JMXServiceURL;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class MBServerConnectorFactoryTest {
+
+    @Test
+    public void testGetServerPort() throws Exception {
+        Assert.assertEquals(9914, MBServerConnectorFactory.getServerPort(
+                "service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"));
+
+        Assert.assertEquals(10002, MBServerConnectorFactory.getServerPort(
+                "service:jmx:rmi://localhost:10002/jndi/rmi://localhost:10001/jmxrmi"));
+    }
+
+    @Test
+    public void testGetRegistryPort() throws Exception {
+        Assert.assertEquals(9914, MBServerConnectorFactory.getRegistryPort(
+                "service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"));
+
+        Assert.assertEquals(10001, MBServerConnectorFactory.getRegistryPort(
+                        "service:jmx:rmi://localhost:10002/jndi/rmi://localhost:10001/jmxrmi"));
+    }
+
+    @Test
+    public void testGetBindingName() throws Exception {
+        Assert.assertEquals("jmxrmi", MBServerConnectorFactory.getBindingName(
+                new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi")));
+
+        Assert.assertEquals("cxf-jmxrmi", MBServerConnectorFactory.getBindingName(
+                new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9913/cxf-jmxrmi")));
+    }
+}
\ No newline at end of file