Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8242947

SSL configuration file on a JMX client command lines gives JRMP error

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Ubuntu 18.04 and JDK 1.8.0_221

      A DESCRIPTION OF THE PROBLEM :
      JMX client throws error when SSL configuration information(truststore and its password) is put in a property file and the file name with path is supplied on Java command line used for the JMX client. The client works fine if I directly supply the truststore and password on its command line. Usage of configuration files is very clear as per JDK documentation (management.properties) but it does not work for me for JMX clients.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1) Setup shell environment variable PROJ_HOME as following:
           export PROJ_HOME=/mnt/vol3/projects/eclipse_ws_monitor/TestJMXSSLCfg
           Change path to suit your environment.

      2) Create keystore and truststore as following:
      2.1) Create a key pair/certificate
      keytool -storetype PKCS12 -keystore keystore.pkcs12 -storepass keystore123 -genkeypair -alias CERT -keyalg RSA -validity 2000
      Press Enter key for all prompts except last question for which you need to say “yes”.
      2.2) Export certificate
      keytool -storetype PKCS12 -keystore keystore.pkcs12 -storepass keystore123 -alias CERT -exportcert -file SCERT.cer
      2.3) Import already created server side certificate into truststore
      keytool -storetype PKCS12 -keystore truststore.pkcs12 -storepass truststore123 -alias CERT -file SCERT.cer -importcert -trustcacerts
      Enter “yes” when prompted.

      3) Create JMX server SSL configuration file jmx_server_ssl.cfg with the following contents(modify keystore file path if needed):
      javax.net.ssl.keyStore=/mnt/vol3/projects/eclipse_ws_monitor/TestJMXSSLCfg/keystore.pkcs12
      javax.net.ssl.keyStorePassword=keystore123

      4) Create JMX client SSL configuration file jmx_client_ssl.cfg with the following contents (modify truststore file path if needed):
      javax.net.ssl.trustStore=/mnt/vol3/projects/eclipse_ws_monitor/TestJMXSSLCfg/truststore.pkcs12
      javax.net.ssl.trustStorePassword=truststore123

      5) Invoke the server program as following:
      java -Dcom.sun.management.jmxremote.port=9999 \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=true \
      -Dcom.sun.management.jmxremote.registry.ssl=false \
      -Dcom.sun.management.jmxremote.ssl.need.client.auth=false \
      -Dcom.sun.management.jmxremote.ssl.config.file=${PROJ_HOME}/jmx_server_ssl.cfg \
      com.example.server.JMXServer

      6) Invoke client program as following:
      java -Dcom.sun.management.jmxremote.ssl.config.file=${PROJ_HOME}/jmx_client_ssl.cfg \
          com.example.client.JMXClient

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      JMX client should connect to JMX server successfully and display the following message:
      Response from server for sayHello() = Hi hello, this is agent!
      ACTUAL -
      java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
      javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
      at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:307)
      at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
      at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:129)
      at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:227)
      at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:179)
      at com.sun.proxy.$Proxy0.newClient(Unknown Source)
      at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2430)
      at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:308)
      at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270)
      at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:229)
      at com.example.client.JMXClient.main(JMXClient.java:18)

      ---------- BEGIN SOURCE ----------
      JMX Server
      =========
      1) JMXServer.java
      package com.example.server;

      import java.io.IOException;
      import java.lang.management.ManagementFactory;
      import javax.management.InstanceAlreadyExistsException;
      import javax.management.MBeanRegistrationException;
      import javax.management.MBeanServer;
      import javax.management.MalformedObjectNameException;
      import javax.management.NotCompliantMBeanException;
      import javax.management.ObjectName;

      public class JMXServer {
      public static void main(String[] args)
      throws MalformedObjectNameException, InstanceAlreadyExistsException
      , MBeanRegistrationException, NotCompliantMBeanException
      , InterruptedException, IOException
      {
      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
      ObjectName name = new ObjectName("com.example:type=Hello");
      Hello mbean = new Hello();
      mbs.registerMBean(mbean, name);
      System.out.println("Waiting for invoke");
      Thread.sleep(Long.MAX_VALUE);
      }
      }

      2) HelloMXBean.java
      package com.example.server;

      public interface HelloMXBean {
      public String sayHello();

      }

      3) Hello.java
      package com.example.server;


      public class Hello implements HelloMXBean{

      @Override
      public String sayHello() {
      return "Hi hello, this is agent!";
      }
      }

      JMX Client
      =========
      1) JMXClient.java
      package com.example.client;

      import java.util.HashMap;
      import java.util.Map;

      import javax.management.JMX;
      import javax.management.MBeanServerConnection;
      import javax.management.ObjectName;
      import javax.management.remote.JMXConnector;
      import javax.management.remote.JMXConnectorFactory;
      import javax.management.remote.JMXServiceURL;
      import com.example.server.HelloMXBean;

      public class JMXClient {
      public static void main(String[] args) {
      try {
      JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://192.168.0.191:9999/jmxrmi");
      JMXConnector jmxc = JMXConnectorFactory.connect(url);

      MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
      ObjectName mbeanname = new ObjectName("com.example:type=Hello");
      HelloMXBean mbeanproxy = JMX.newMXBeanProxy(mbsc, mbeanname, HelloMXBean.class,false);

      String str = mbeanproxy.sayHello();
      System.out.println("Response from server for sayHello() = " + str);

      jmxc.close();
      }
      catch (Exception e) {
      e.printStackTrace();
      }
      }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Invoke JMX client without configuration file as following:
      java -Djavax.net.ssl.trustStore=${PROJ_HOME}/truststore.pkcs12 \
      -Djavax.net.ssl.trustStorePassword=truststore123 \
      com.example.client.JMXClient

      Issue is, this command exposes truststore password when user issues Linux ps command.

      FREQUENCY : always


        1. Hello.java
          0.1 kB
          Andrew Wang
        2. HelloMXBean.java
          0.1 kB
          Andrew Wang
        3. jmx_client_ssl.cfg
          0.1 kB
          Andrew Wang
        4. jmx_server_ssl.cfg
          0.1 kB
          Andrew Wang
        5. JMXClient.java
          0.9 kB
          Andrew Wang
        6. JMXServer.java
          0.8 kB
          Andrew Wang

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: