I have a program which monitors process performance data from JMX remote agents.
Some of these remote agents are configured to use SSL, setting the JVM arguments com.sun.management.jmxremote.ssl
and com.sun.management.jmxremote.registry.ssl
to true. Others are not SSL secured, setting these JVM arguments to false.
I connect to these remote agents using a JMXConnector with the following method:
private JMXConnector setUpConnection(String server, int jmxPort) {
try {
Registry r = LocateRegistry.getRegistry(server, jmxPort);
HashMap<String, Object> env = new HashMap<String, Object>();
String[] credentials = {"username", "password"};
env.put(JMXConnector.CREDENTIALS, credentials);
env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory()); // uncomment if needed
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + server + ":" + jmxPort + "/jmxrmi");
return JMXConnectorFactory.newJMXConnector(url, env);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
This approach is able to connect to my SSL secured remote agents but not my remote agents that do not use SSL. The error message I get for the latter case is:
java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.CommunicationException [Root exception is java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake]
If I remove the following line:
env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());
Then the opposite occurs, I am now able to connect to the remote agents that are not configured to use SSL but am unable to connect to the SSL remote agents. The error message I get for the SSL configured remote agents in this case is:
java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.CommunicationException [Root exception is java.rmi.ConnectIOException: non-JRMP server at remote endpoint]
If I do not set the JVM argument com.sun.management.jmxremote.registry.ssl
to true then I am able to connect to all of my remote agents when I omit:
env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());
However setting this property to false is not an option.
I want to avoid at all costs having two different connection environments, one for SSL remote agents and another for non-SSL remote agents. I also cannot migrate all of my remote agents to configuring SSL.
One of our project we have used the below code snippet to get JMXConnection.
private String provider = "";
private String jvmPort = "";
private JMXServiceURL jmxService = null;
private JMXConnector jmxConnector = null;
private RMIConnector rmiConnector = null;
private MBeanServerConnection beanServerConn = null;
.........
public boolean connectToJVM(String jvmURL, String user, String pass)
{
boolean flag = false;
beanServerConn = null ;
try
{
jmxService = new JMXServiceURL(jvmURL);
Map environment = new HashMap();
int jmxconnect_timeout = 30000;
environment.put("jmx.remote.protocol.provider.pkgs",provider);
if (jmxconnect_timeout > 0) {
environment.put("jmx.remote.x.request.waiting.timeout", Long.toString(jmxconnect_timeout));
}
boolean registrySSL = false;
if(user.equalsIgnoreCase("none")|| (pass.equalsIgnoreCase("none")))
{
try
{
jmxConnector = JMXConnectorFactory.connect(jmxService,environment);
}
catch(IOException ioe)
{
registrySSL = true;
}
}
else
{
String [] credentials={user,pass};
environment.put(JMXConnector.CREDENTIALS, credentials);
try
{
jmxConnector = JMXConnectorFactory.connect(jmxService,environment);
}
catch(IOException ioe)
{
registrySSL = true;
}
}
if(registrySSL)
{
/*
This if block runs when the "management.properties" file contains
com.sun.management.jmxremote.registry.ssl=true
This block of code is applicable both JDK5.0 & 6.0
Only for JDK6.0
===============
environment.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());
beanServerConn = jmxConnector.getMBeanServerConnection();
*/
try {
MySslRMIClientSocketFactory csf = new MySslRMIClientSocketFactory(targetHost, Integer.parseInt(jvmPort), (int)jmxconnect_timeout);
Registry registry = LocateRegistry.getRegistry(targetHost, Integer.parseInt(jvmPort), csf);
RMIServer stub = (RMIServer) registry.lookup(jndiName);
rmiConnector = new RMIConnector(stub, environment);
rmiConnector.connect(environment);
beanServerConn = rmiConnector.getMBeanServerConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
else{
beanServerConn = jmxConnector.getMBeanServerConnection();
}
if(beanServerConn == null)
{
System.out.println("Connection to JVM is not established for url : " + url);
return false;
}
else
{
flag = true;
}
}
catch(Exception ex)
{
System.out.println("Connection to JVM is not established for url : " + url);
//ex.printStackTrace();
return false;
}
return flag;
}