使用相同的连接环境连接启用 SSL 和禁用 SSL 的 JMX 远程代理

Connecting to both SSL enabled and SSL disabled JMX remote agents with the same connection environment

我有一个程序可以监视来自 JMX 远程代理的进程性能数据。

其中一些远程代理配置为使用 SSL,将 JVM 参数 com.sun.management.jmxremote.sslcom.sun.management.jmxremote.registry.ssl 设置为 true。其他不受 SSL 保护,将这些 JVM 参数设置为 false。

我通过以下方法使用 JMXConnector 连接到这些远程代理:

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;

}

这种方法能够连接到我的 SSL 安全远程代理,但不能连接到我不使用 SSL 的远程代理。对于后一种情况,我得到的错误消息是:

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]

如果我删除以下行:

env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());

然后情况正好相反,我现在可以连接到未配置为使用 SSL 但无法连接到 SSL 远程代理的远程代理。在这种情况下,我为 SSL 配置的远程代理收到的错误消息是:

java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.CommunicationException [Root exception is java.rmi.ConnectIOException: non-JRMP server at remote endpoint]

如果我没有将 JVM 参数 com.sun.management.jmxremote.registry.ssl 设置为 true 那么我可以在我省略时连接到我的所有远程代理:

env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());

然而,将此 属性 设置为 false 不是一个选项。

我想不惜一切代价避免使用两种不同的连接环境,一种用于 SSL 远程代理,另一种用于非 SSL 远程代理。我也无法将所有远程代理迁移到配置 SSL。

我们的一个项目使用了下面的代码片段来获取 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;
}