From 9d718c7e64b4988dc2744ac5fa51675f2eefc09c Mon Sep 17 00:00:00 2001 From: Woden Cafe Date: Wed, 19 Oct 2016 15:24:20 -0500 Subject: [PATCH 1/4] foo --- src/main/java/com/j256/simplejmx/client/ClientUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/j256/simplejmx/client/ClientUtils.java b/src/main/java/com/j256/simplejmx/client/ClientUtils.java index 4214995..b4e1501 100644 --- a/src/main/java/com/j256/simplejmx/client/ClientUtils.java +++ b/src/main/java/com/j256/simplejmx/client/ClientUtils.java @@ -18,7 +18,7 @@ public static Object stringToParam(String string, String typeString) throws Ille return Boolean.parseBoolean(string); } else if (typeString.equals("char") || typeString.equals("java.lang.Character")) { if (string.length() == 0) { - // not sure what to do here + // not sure what to do here ffee return '\0'; } else { return string.toCharArray()[0]; From 1066362e720d2ce1253fdeb651c171037880c571 Mon Sep 17 00:00:00 2001 From: cboyd Date: Wed, 19 Oct 2016 15:26:39 -0500 Subject: [PATCH 2/4] Remove test comment --- src/main/java/com/j256/simplejmx/client/ClientUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/j256/simplejmx/client/ClientUtils.java b/src/main/java/com/j256/simplejmx/client/ClientUtils.java index b4e1501..4214995 100644 --- a/src/main/java/com/j256/simplejmx/client/ClientUtils.java +++ b/src/main/java/com/j256/simplejmx/client/ClientUtils.java @@ -18,7 +18,7 @@ public static Object stringToParam(String string, String typeString) throws Ille return Boolean.parseBoolean(string); } else if (typeString.equals("char") || typeString.equals("java.lang.Character")) { if (string.length() == 0) { - // not sure what to do here ffee + // not sure what to do here return '\0'; } else { return string.toCharArray()[0]; From 6df368a05577dbdd4a3361c194545673bb1e51de Mon Sep 17 00:00:00 2001 From: Woden Cafe Date: Wed, 19 Oct 2016 15:51:57 -0500 Subject: [PATCH 3/4] Allow manually setting the Environment Map --- .../com/j256/simplejmx/server/JmxServer.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/j256/simplejmx/server/JmxServer.java b/src/main/java/com/j256/simplejmx/server/JmxServer.java index 779270a..e351ad6 100644 --- a/src/main/java/com/j256/simplejmx/server/JmxServer.java +++ b/src/main/java/com/j256/simplejmx/server/JmxServer.java @@ -48,6 +48,7 @@ public class JmxServer { private RMIServerSocketFactory serverSocketFactory; private boolean serverHostNamePropertySet = false; private String serviceUrl; + private Map envMap = new HashMap(); /** * Create a JMX server that will be set with the port using setters. Used with spring. You must at least specify the @@ -448,6 +449,23 @@ public void setUsePlatformMBeanServer(boolean usePlatformMBeanServer) { public int getRegisteredCount() { return registeredCount; } + + /** + * Gets the map used with the {@link JMXConnectorServerFactory} + */ + public Map getEnvironmentMap() + { + return envMap; + } + + /** + * Sets the map used with the {@link JMXConnectorServerFactory} + */ + public void setEnvironmentMap( Map environmentMap ) + { + this.envMap = environmentMap; + } + private String getObjectDescription(Object obj) { Class clazz = obj.getClass(); @@ -533,9 +551,10 @@ private void startJmxService() throws JMException { throw createJmException("Malformed service url created " + serviceUrl, e); } - Map envMap = null; + if (serverSocketFactory != null) { - envMap = new HashMap(); + if (envMap == null) + envMap = new HashMap(); envMap.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory); } /* From f44d29f16dabe8520591aec0e66db8652e234119 Mon Sep 17 00:00:00 2001 From: Woden Cafe Date: Fri, 21 Oct 2016 08:51:30 -0500 Subject: [PATCH 4/4] Password Authentication Support --- .../com/j256/simplejmx/client/JmxClient.java | 9 + .../com/j256/simplejmx/server/JmxServer.java | 257 +++++++++++++++--- 2 files changed, 226 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/j256/simplejmx/client/JmxClient.java b/src/main/java/com/j256/simplejmx/client/JmxClient.java index 6eb9e0b..ba36013 100644 --- a/src/main/java/com/j256/simplejmx/client/JmxClient.java +++ b/src/main/java/com/j256/simplejmx/client/JmxClient.java @@ -119,6 +119,15 @@ public JmxClient(int localPort) throws JMException { public JmxClient(String hostName, int port) throws JMException { this(generalJmxUrlForHostNamePort(hostName, port)); } + + + /** + * Connect the client to a host and port combination, with a username and password. + */ + public JmxClient(String hostName, int port, String username, String password) throws JMException { + this(generalJmxUrlForHostNamePort(hostName, port), username, password); + } + /** * Connect the client to an address and port combination. diff --git a/src/main/java/com/j256/simplejmx/server/JmxServer.java b/src/main/java/com/j256/simplejmx/server/JmxServer.java index e351ad6..fb3fba9 100644 --- a/src/main/java/com/j256/simplejmx/server/JmxServer.java +++ b/src/main/java/com/j256/simplejmx/server/JmxServer.java @@ -10,16 +10,23 @@ import java.rmi.registry.Registry; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; +import java.security.Principal; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; +import javax.management.remote.JMXAuthenticator; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXPrincipal; import javax.management.remote.JMXServiceURL; import javax.management.remote.rmi.RMIConnectorServer; +import javax.security.auth.Subject; import com.j256.simplejmx.common.JmxAttributeFieldInfo; import com.j256.simplejmx.common.JmxAttributeMethodInfo; @@ -48,7 +55,118 @@ public class JmxServer { private RMIServerSocketFactory serverSocketFactory; private boolean serverHostNamePropertySet = false; private String serviceUrl; + private JMXAuthenticator authenticator; private Map envMap = new HashMap(); + + public static class JmxServerBuilder + { + + protected Map envMap = new HashMap(); + protected InetAddress inetAddress; + private RMIServerSocketFactory serverSocketFactory; + private JMXAuthenticator authenticator; + private MBeanServer mbeanServer; + private String serviceUrl; + private int serverPort; + private int registryPort; + private boolean usePlatformServer = false; + public static JmxServerBuilder newBuilder() + { + return new JmxServerBuilder(); + } + + private JmxServerBuilder() + { + + } + public JmxServerBuilder withServerSocketFactory(RMIServerSocketFactory serverSocketFactory) + { + this.serverSocketFactory = serverSocketFactory; + return this; + } + public JmxServerBuilder withAuthenticator(JMXAuthenticator authenticator) + { + this.authenticator = authenticator; + return this; + } + public JmxServerBuilder withPasswordAuthenticator(String username, String password) + { + this.authenticator = getPasswordAuthenticator( username, password ); + return this; + } + public JmxServerBuilder withDefaultServiceUrl() + { + this.serviceUrl = null; + return this; + } + public JmxServerBuilder withServerPort(int serverPort) + { + this.serverPort = serverPort; + return this; + } + public JmxServerBuilder withRegistryPort(int registryPort) + { + this.registryPort = registryPort; + return this; + } + public JmxServerBuilder withMBeanServer(MBeanServer mbeanServer) + { + this.mbeanServer = mbeanServer; + this.usePlatformServer = false; + return this; + } + public JmxServerBuilder withPlatformMBeanServer() + { + this.mbeanServer = null; + this.usePlatformServer = true; + return this; + } + public JmxServerBuilder withServiceUrl(String serviceUrl) + { + this.serviceUrl = serviceUrl; + return this; + } + public JmxServerBuilder withAddress(InetAddress inetAddress) + { + this.inetAddress = inetAddress; + return this; + } + public JmxServerBuilder withEnvironmentMap(Map envMap) + { + this.envMap = envMap; + return this; + } + public JmxServer build() + { + JmxServer server; + if (usePlatformServer) + { + server = new JmxServer( true ); + server.setInetAddress( inetAddress ); + server.setRegistryPort( registryPort ); + server.setServerPort( serverPort ); + server.setServerSocketFactory( serverSocketFactory ); + server.setServiceUrl( serviceUrl ); + } + else if (mbeanServer != null ) + { + server = new JmxServer(mbeanServer); + } + else + { + + server = new JmxServer( registryPort ); + server.setInetAddress( inetAddress ); + server.setServerPort( serverPort ); + server.setServerSocketFactory( serverSocketFactory ); + server.setServiceUrl( serviceUrl ); + } + + server.setAuthenticator( authenticator ); + server.setEnvironmentMap( envMap ); + return server; + } + } /** * Create a JMX server that will be set with the port using setters. Used with spring. You must at least specify the @@ -139,7 +257,14 @@ public JmxServer(boolean usePlatformMBeanServer) { this.mbeanServer = ManagementFactory.getPlatformMBeanServer(); } } - + public void setAuthenticator(JMXAuthenticator authenticator) + { + this.authenticator = authenticator; + } + public void setEnvironmentMap(Map envMap) + { + this.envMap = envMap; + } /** * Start our JMX service. The port must have already been called either in the {@link #JmxServer(int)} constructor * or the {@link #setRegistryPort(int)} method before this is called. @@ -458,15 +583,6 @@ public Map getEnvironmentMap() return envMap; } - /** - * Sets the map used with the {@link JMXConnectorServerFactory} - */ - public void setEnvironmentMap( Map environmentMap ) - { - this.envMap = environmentMap; - } - - private String getObjectDescription(Object obj) { Class clazz = obj.getClass(); JmxResource jmxResource = clazz.getAnnotation(JmxResource.class); @@ -524,6 +640,27 @@ private void startJmxService() throws JMException { if (connector != null) { return; } + + configureServerPorts(); + JMXServiceURL url = buildServiceUrl(); + + /* + * NOTE: I tried to inject a client socket factory with RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE + * but I could not get it to work. It seemed to require the client to have the LocalSocketFactory class in the + * classpath. + */ + injectServerSocketFactory(); + + + if (authenticator != null) + { + envMap.put(JMXConnectorServer.AUTHENTICATOR, authenticator); + } + startConnector( url ); + } + + private void configureServerPorts() + { if (serverPort == 0) { /* * If we aren't specifying an address then we can use the registry-port for both the registry call _and_ the @@ -532,37 +669,11 @@ private void startJmxService() throws JMException { */ serverPort = registryPort; } - String serverHost = "localhost"; - String registryHost = ""; - if (inetAddress != null) { - String hostAddr = inetAddress.getHostAddress(); - serverHost = hostAddr; - registryHost = hostAddr; - } - if (serviceUrl == null) { - serviceUrl = - "service:jmx:rmi://" + serverHost + ":" + serverPort + "/jndi/rmi://" + registryHost + ":" - + registryPort + "/jmxrmi"; - } - JMXServiceURL url; - try { - url = new JMXServiceURL(serviceUrl); - } catch (MalformedURLException e) { - throw createJmException("Malformed service url created " + serviceUrl, e); - } - - - if (serverSocketFactory != null) { - if (envMap == null) - envMap = new HashMap(); - envMap.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory); - } - /* - * NOTE: I tried to inject a client socket factory with RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE - * but I could not get it to work. It seemed to require the client to have the LocalSocketFactory class in the - * classpath. - */ + } + private void startConnector( JMXServiceURL url ) + throws JMException + { try { mbeanServer = ManagementFactory.getPlatformMBeanServer(); connector = JMXConnectorServerFactory.newJMXConnectorServer(url, envMap, mbeanServer); @@ -577,6 +688,38 @@ private void startJmxService() throws JMException { } } + private void injectServerSocketFactory() + { + if (serverSocketFactory != null) { + envMap.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory); + } + } + + private JMXServiceURL buildServiceUrl() + throws JMException + { + if (serviceUrl == null) + { + String serverHost = "localhost"; + String registryHost = ""; + if (inetAddress != null) { + String hostAddr = inetAddress.getHostAddress(); + serverHost = hostAddr; + registryHost = hostAddr; + } + serviceUrl = + "service:jmx:rmi://" + serverHost + ":" + serverPort + "/jndi/rmi://" + registryHost + ":" + + registryPort + "/jmxrmi"; + } + JMXServiceURL url; + try { + url = new JMXServiceURL(serviceUrl); + } catch (MalformedURLException e) { + throw createJmException("Malformed service url created " + serviceUrl, e); + } + return url; + } + private JMException createJmException(String message, Exception e) { JMException jmException = new JMException(message); jmException.initCause(e); @@ -617,4 +760,38 @@ public boolean equals(Object obj) { } } } + + static JMXAuthenticator getPasswordAuthenticator(String username, String password) + { + JMXAuthenticator authenticator = new JMXAuthenticator() + { + + public Subject authenticate(Object credentials) + { + if (!(credentials instanceof String[])) + throw new SecurityException("Bad credentials"); + String[] creds = (String[]) credentials; + if (creds.length != 2) + throw new SecurityException("Bad credentials"); + + String dusername = creds[0]; + String dpassword = creds[1]; + + if (dpassword == null) + dpassword = ""; + + if (!username.equals(dusername)) + throw new SecurityException("Unknown user " + username); + if (!password.equals(dpassword)) + throw new SecurityException("Bad password"); + + Set principals = new HashSet<>(); + principals.add(new JMXPrincipal(username)); + return new Subject(true, principals, Collections.EMPTY_SET, Collections.EMPTY_SET); + } + + }; + return authenticator; + } + }