You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2020/04/09 06:30:32 UTC
[karaf] branch karaf-4.2.x updated: KARAF-6634 - Prevent JMX
rebinding
This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch karaf-4.2.x
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/karaf-4.2.x by this push:
new 1827400 KARAF-6634 - Prevent JMX rebinding
1827400 is described below
commit 1827400d242174bd4cd6868ebb7f9196fb3709d2
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Thu Mar 12 16:24:33 2020 +0000
KARAF-6634 - Prevent JMX rebinding
(cherry picked from commit c30ed5d365d564ff96a334dbfa1eb3f0f67a52ea)
---
management/server/pom.xml | 1 +
.../karaf/management/ConnectorServerFactory.java | 214 ++++++++++++++++++++-
.../karaf/management/RmiRegistryFactory.java | 181 -----------------
.../karaf/management/internal/Activator.java | 30 +--
4 files changed, 221 insertions(+), 205 deletions(-)
diff --git a/management/server/pom.xml b/management/server/pom.xml
index 6563fd4..598474d 100644
--- a/management/server/pom.xml
+++ b/management/server/pom.xml
@@ -128,6 +128,7 @@
org.osgi.service.event*;resolution:=optional,
com.sun.jmx.remote.protocol;resolution:=optional,
com.sun.jdmk.security.sasl;resolution:=optional,
+ sun.rmi*;resolution:=optional,
*
</Import-Package>
<Private-Package>
diff --git a/management/server/src/main/java/org/apache/karaf/management/ConnectorServerFactory.java b/management/server/src/main/java/org/apache/karaf/management/ConnectorServerFactory.java
index ed8e248..a8be130 100644
--- a/management/server/src/main/java/org/apache/karaf/management/ConnectorServerFactory.java
+++ b/management/server/src/main/java/org/apache/karaf/management/ConnectorServerFactory.java
@@ -18,8 +18,10 @@ package org.apache.karaf.management;
import org.apache.karaf.jaas.config.KeystoreManager;
import org.apache.karaf.management.internal.MBeanInvocationHandler;
+import org.osgi.framework.BundleContext;
import java.io.IOException;
+import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.net.BindException;
import java.net.InetAddress;
@@ -28,11 +30,23 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.nio.channels.ServerSocketChannel;
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
import java.security.GeneralSecurityException;
import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
import java.util.Map;
import javax.management.JMException;
@@ -42,6 +56,7 @@ 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 javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLParameters;
@@ -66,6 +81,8 @@ public class ConnectorServerFactory {
private boolean threaded = false;
private boolean daemon = false;
private JMXConnectorServer connectorServer;
+ private Remote remoteServerStub;
+ private RMIJRMPServerImpl rmiServer;
private JMXConnectorServer jmxmpConnectorServer;
private long keyStoreAvailabilityTimeout = 5000;
@@ -80,6 +97,14 @@ public class ConnectorServerFactory {
private String trustStore;
private String keyAlias;
+ private int port = Registry.REGISTRY_PORT;
+ private String host;
+ private Registry registry;
+ private boolean locate;
+ private boolean create = true;
+ private boolean locallyCreated;
+ private BundleContext bundleContext;
+
public MBeanServer getServer() {
return server;
}
@@ -269,12 +294,88 @@ public class ConnectorServerFactory {
return this.authenticatorType.equals(AuthenticatorType.CERTIFICATE);
}
+ /**
+ * @return the create
+ */
+ public boolean isCreate() {
+ return create;
+ }
+
+ /**
+ * @param create the create to set
+ */
+ public void setCreate(boolean create) {
+ this.create = create;
+ }
+
+ /**
+ * @return the locate
+ */
+ public boolean isLocate() {
+ return locate;
+ }
+
+ /**
+ * @param locate the locate to set
+ */
+ public void setLocate(boolean locate) {
+ this.locate = locate;
+ }
+
+ /**
+ * @return the port
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * @param port the port to set
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
public void init() throws Exception {
+ JMXServiceURL url = new JMXServiceURL(this.serviceUrl);
+
+ if (registry == null && locate) {
+ try {
+ Registry reg = LocateRegistry.getRegistry(host, getPort());
+ reg.list();
+ registry = reg;
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ if (registry == null && create) {
+ registry = new JmxRegistry(getPort(), getBindingName(url));
+ locallyCreated = true;
+ }
+ if (registry != null) {
+ // register the registry as an OSGi service
+ Hashtable<String, Object> props = new Hashtable<>();
+ props.put("port", getPort());
+ props.put("host", getHost());
+ bundleContext.registerService(Registry.class, registry, props);
+ }
+
if (this.server == null) {
throw new IllegalArgumentException("server must be set");
}
- JMXServiceURL url = new JMXServiceURL(this.serviceUrl);
if ( isClientAuth() ) {
this.secured = true;
}
@@ -291,7 +392,11 @@ public class ConnectorServerFactory {
MBeanInvocationHandler handler = new MBeanInvocationHandler(server, guard);
MBeanServer guardedServer = (MBeanServer) Proxy.newProxyInstance(server.getClass().getClassLoader(), new Class[]{ MBeanServer.class }, handler);
- this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, this.environment, guardedServer);
+
+ rmiServer = new RMIJRMPServerImpl(getServerPort(serviceUrl), null, null, environment);
+
+ // Create the connector server now.
+ this.connectorServer = new RMIConnectorServer(url, environment, rmiServer, guardedServer);
if (this.objectName != null) {
this.server.registerMBean(this.connectorServer, this.objectName);
@@ -311,6 +416,7 @@ public class ConnectorServerFactory {
try {
Thread.currentThread().setContextClassLoader(ConnectorServerFactory.class.getClassLoader());
connectorServer.start();
+ remoteServerStub = rmiServer.toStub();
if (jmxmpEnabled && jmxmpConnectorServer != null) {
jmxmpConnectorServer.start();
}
@@ -334,6 +440,7 @@ public class ConnectorServerFactory {
connectorThread.start();
} else {
this.connectorServer.start();
+ remoteServerStub = rmiServer.toStub();
if (jmxmpEnabled && jmxmpConnectorServer != null) {
jmxmpConnectorServer.start();
}
@@ -349,6 +456,45 @@ public class ConnectorServerFactory {
}
}
+ 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
+ }
+
+ static int getServerPort(final String url) {
+ int portStart = url.indexOf("localhost") + 10;
+ int portEnd;
+ int port = 0;
+ if (portStart > 0) {
+ portEnd = indexNotOfNumber(url, portStart);
+ if (portEnd > portStart) {
+ final String portString = url.substring(portStart, portEnd);
+ port = Integer.parseInt(portString);
+ }
+ }
+ return port;
+ }
+
+ private static int indexNotOfNumber(String str, int index) {
+ int i = 0;
+ for (i = index; i < str.length(); i++) {
+ if (str.charAt(i) < '0' || str.charAt(i) > '9') {
+ return i;
+ }
+ }
+ return -1;
+ }
+
public void destroy() throws Exception {
try {
if (this.connectorServer != null) {
@@ -357,6 +503,33 @@ public class ConnectorServerFactory {
if (this.jmxmpEnabled && this.jmxmpConnectorServer != null) {
this.jmxmpConnectorServer.stop();
}
+
+ if (registry != null && locallyCreated) {
+ Registry reg = registry;
+ registry = null;
+ UnicastRemoteObject.unexportObject(reg, true);
+
+ // clear TCPEndpointCache
+ try {
+ Class<?> cls = getClass().getClassLoader().loadClass("sun.rmi.transport.tcp.TCPEndpoint");
+ Field localEndpointsField = cls.getDeclaredField("localEndpoints");
+ Field ssfField = cls.getDeclaredField("ssf");
+ localEndpointsField.setAccessible(true);
+ ssfField.setAccessible(true);
+ Object localEndpoints = localEndpointsField.get(null);
+ if (localEndpoints != null) {
+ Map<Object, Object> map = (Map<Object, Object>) localEndpoints;
+ for (Iterator<Object> it = map.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object ssf = ssfField.get(key);
+ if (ssf != null && ssf.getClass().getPackage().getName().equals("org.apache.karaf.management")) {
+ it.remove();
+ }
+ }
+ }
+ } catch (Exception ignored) {
+ }
+ }
} finally {
if (this.objectName != null) {
doUnregister(this.objectName);
@@ -403,7 +576,7 @@ public class ConnectorServerFactory {
private String[] enabledProtocols;
private String[] enabledCipherSuites;
- public KarafSslRMIServerSocketFactory(SSLServerSocketFactory sssf, boolean clientAuth, String rmiServerHost,
+ public KarafSslRMIServerSocketFactory(SSLServerSocketFactory sssf, boolean clientAuth, String rmiServerHost,
String[] enabledProtocols,
String[] enabledCipherSuites) {
this.sssf = sssf;
@@ -766,4 +939,39 @@ public class ConnectorServerFactory {
this.enabledCipherSuites = enabledCipherSuites;
}
+ /*
+ * 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/management/server/src/main/java/org/apache/karaf/management/RmiRegistryFactory.java b/management/server/src/main/java/org/apache/karaf/management/RmiRegistryFactory.java
deleted file mode 100644
index a08ef20..0000000
--- a/management/server/src/main/java/org/apache/karaf/management/RmiRegistryFactory.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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.karaf.management;
-
-import org.osgi.framework.BundleContext;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.UnknownHostException;
-import java.rmi.RemoteException;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.registry.Registry;
-import java.rmi.server.RMIClientSocketFactory;
-import java.rmi.server.RMIServerSocketFactory;
-import java.rmi.server.RMISocketFactory;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.Map;
-
-public class RmiRegistryFactory {
-
- private int port = Registry.REGISTRY_PORT;
- private String host;
- private Registry registry;
- private boolean locate;
- private boolean create = true;
- private boolean locallyCreated;
-
- private BundleContext bundleContext;
-
- /**
- * @return the create
- */
- public boolean isCreate() {
- return create;
- }
-
- /**
- * @param create the create to set
- */
- public void setCreate(boolean create) {
- this.create = create;
- }
-
- /**
- * @return the locate
- */
- public boolean isLocate() {
- return locate;
- }
-
- /**
- * @param locate the locate to set
- */
- public void setLocate(boolean locate) {
- this.locate = locate;
- }
-
- /**
- * @return the port
- */
- public int getPort() {
- return port;
- }
-
- /**
- * @param port the port to set
- */
- public void setPort(int port) {
- this.port = port;
- }
-
- public String getHost() {
- return host;
- }
-
- public void setHost(String host) {
- this.host = host;
- }
-
- public Object getObject() throws Exception {
- return registry;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- public void init() throws RemoteException, UnknownHostException {
- if (registry == null && locate) {
- try {
- Registry reg = LocateRegistry.getRegistry(host, getPort());
- reg.list();
- registry = reg;
- } catch (RemoteException e) {
- // ignore
- }
- }
- if (registry == null && create) {
- if (host != null && !host.isEmpty()) {
- RMIClientSocketFactory socketFactory = RMISocketFactory.getDefaultSocketFactory();
- InetAddress addr = InetAddress.getByName(host);
- RMIServerSocketFactory serverSocketFactory = new KarafServerSocketFactory(addr, port);
-
- registry = LocateRegistry.createRegistry(getPort(), socketFactory, serverSocketFactory);
- } else {
- registry = LocateRegistry.createRegistry(getPort());
- }
- locallyCreated = true;
- }
- if (registry != null) {
- // register the registry as an OSGi service
- Hashtable<String, Object> props = new Hashtable<>();
- props.put("port", getPort());
- props.put("host", getHost());
- bundleContext.registerService(Registry.class, registry, props);
- }
- }
-
- public void destroy() throws RemoteException {
- if (registry != null && locallyCreated) {
- Registry reg = registry;
- registry = null;
- UnicastRemoteObject.unexportObject(reg, true);
-
- // clear TCPEndpointCache
- try {
- Class<?> cls = getClass().getClassLoader().loadClass("sun.rmi.transport.tcp.TCPEndpoint");
- Field localEndpointsField = cls.getDeclaredField("localEndpoints");
- Field ssfField = cls.getDeclaredField("ssf");
- localEndpointsField.setAccessible(true);
- ssfField.setAccessible(true);
- Object localEndpoints = localEndpointsField.get(null);
- if (localEndpoints != null) {
- Map<Object, Object> map = (Map<Object, Object>) localEndpoints;
- for (Iterator<Object> it = map.keySet().iterator(); it.hasNext(); ) {
- Object key = it.next();
- Object ssf = ssfField.get(key);
- if (ssf != null && ssf.getClass().getPackage().getName().equals("org.apache.karaf.management")) {
- it.remove();
- }
- }
- }
- } catch (Exception ignored) {
- }
- }
- }
-
- private static class KarafServerSocketFactory implements RMIServerSocketFactory {
- private final int port;
- private final InetAddress addr;
-
- private KarafServerSocketFactory(InetAddress addr, int port) {
- this.addr = addr;
- this.port = port;
- }
-
- @Override
- public ServerSocket createServerSocket(int i) throws IOException {
- return new ServerSocket(port, 0, addr);
- }
- }
-
-}
diff --git a/management/server/src/main/java/org/apache/karaf/management/internal/Activator.java b/management/server/src/main/java/org/apache/karaf/management/internal/Activator.java
index e7ab240..6d34226 100644
--- a/management/server/src/main/java/org/apache/karaf/management/internal/Activator.java
+++ b/management/server/src/main/java/org/apache/karaf/management/internal/Activator.java
@@ -28,7 +28,6 @@ import org.apache.karaf.management.ConnectorServerFactory;
import org.apache.karaf.management.JaasAuthenticator;
import org.apache.karaf.management.KarafMBeanServerGuard;
import org.apache.karaf.management.MBeanServerFactory;
-import org.apache.karaf.management.RmiRegistryFactory;
import org.apache.karaf.util.tracker.BaseActivator;
import org.apache.karaf.util.tracker.annotation.Managed;
import org.apache.karaf.util.tracker.annotation.ProvideService;
@@ -51,13 +50,12 @@ import org.slf4j.LoggerFactory;
)
@Managed("org.apache.karaf.management")
public class Activator extends BaseActivator implements ManagedService {
-
- private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+ private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
private ConnectorServerFactory connectorServerFactory;
- private RmiRegistryFactory rmiRegistryFactory;
private MBeanServerFactory mbeanServerFactory;
-
+
private ServiceTracker<KeystoreInstance, KeystoreInstance> keystoreInstanceServiceTracker;
private EventAdminLogger eventAdminLogger;
@@ -128,14 +126,6 @@ public class Activator extends BaseActivator implements ManagedService {
guard.setLogger(eventAdminLogger);
guard.setConfigAdmin(configurationAdmin);
- rmiRegistryFactory = new RmiRegistryFactory();
- rmiRegistryFactory.setCreate(createRmiRegistry);
- rmiRegistryFactory.setLocate(locateRmiRegistry);
- rmiRegistryFactory.setHost(rmiRegistryHost);
- rmiRegistryFactory.setPort(rmiRegistryPort);
- rmiRegistryFactory.setBundleContext(bundleContext);
- rmiRegistryFactory.init();
-
mbeanServerFactory = new MBeanServerFactory();
mbeanServerFactory.setLocateExistingServerIfPossible(locateExistingMBeanServerIfPossible);
mbeanServerFactory.init();
@@ -147,6 +137,12 @@ public class Activator extends BaseActivator implements ManagedService {
jaasAuthenticator.setRealm(jmxRealm);
connectorServerFactory = new ConnectorServerFactory();
+ connectorServerFactory.setCreate(createRmiRegistry);
+ connectorServerFactory.setLocate(locateRmiRegistry);
+ connectorServerFactory.setHost(rmiRegistryHost);
+ connectorServerFactory.setPort(rmiRegistryPort);
+ connectorServerFactory.setBundleContext(bundleContext);
+
connectorServerFactory.setServer(mbeanServer);
connectorServerFactory.setServiceUrl(serviceUrl);
connectorServerFactory.setGuard(guard);
@@ -236,14 +232,6 @@ public class Activator extends BaseActivator implements ManagedService {
}
mbeanServerFactory = null;
}
- if (rmiRegistryFactory != null) {
- try {
- rmiRegistryFactory.destroy();
- } catch (Exception e) {
- logger.warn("Error destroying RMIRegistryFactory", e);
- }
- rmiRegistryFactory = null;
- }
if (keystoreInstanceServiceTracker != null) {
try {
keystoreInstanceServiceTracker.close();