Developing a JMX Java client for Liberty

You can develop a Java™ Management Extensions (JMX) client application to access the secured REST connector of Liberty.

Open Liberty The latest documentation about developing a JMX Java client for Liberty is available on the Open Liberty website.

About this task

Using a JMX remote client application, you can administer Liberty through JMX programming.

In this configuration, administrative role mapping on Liberty must be performed for all users that require access.

If user authentication is performed with single sign-on technologies (for example SAML, OpenID Connect, or JWT), the user must be in a configured user registry. If there is no user registry that is configured, or the user is not in the configured user registry, you cannot use client side of the REST connector. The client side of the REST connector is in the wlp/clients/restConnector.jar file. Instead, you can access the REST connector directly through an HTTPS call.

Procedure

  1. Start with the following sample application code. Add the Liberty REST connector client library to the application classpath liberty_home/clients/restConnector.jar.
    import javax.management.remote.JMXServiceURL;
    import javax.management.MBeanServerConnection;
    import javax.management.remote.JMXConnector;
    import javax.management.remote.JMXConnectorFactory;
    import java.util.HashMap;
    
    
    public class Test { 
    
      public static void main(String[] args) {
        System.setProperty("javax.net.ssl.trustStore", <truststore location>);
        System.setProperty("javax.net.ssl.trustStorePassword", <truststore password>);
    
        //If the type of the trustStore is not jks, which is default, 
        //set the type by using the following line.
        System.setProperty("javax.net.ssl.trustStoreType", <truststore type>);
       
       try {
          HashMap<String, Object> environment = new HashMap<String, Object>();
          environment.put("jmx.remote.protocol.provider.pkgs", "com.ibm.ws.jmx.connector.client");
          environment.put(JMXConnector.CREDENTIALS, new String[] { "userid", "password" });
    
          JMXServiceURL url = new JMXServiceURL("service:jmx:rest://localhost:9443/IBMJMXConnectorREST");
          JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, environment);
          connector.connect();
          MBeanServerConnection mbsc = connector.getMBeanServerConnection();
        } catch(Throwable t) {
             ...
        }
      }
    }
    
  2. If the server generates the server keystore for a non-production environment, use the keystore as the application client truststore.

    The keystore that the server generates for a non-production environment contains the client certificate.

    By default, the application client truststore file is ${server.output.dir}/resources/security/key.p12.

    Through 9.0.0.2, by default, the application client truststore file is ${server.output.dir}/resources/security/key.jks.

  3. Set the javax.net.ssl.trustStoreType property.

    If you use the default key.p12 keystore file, set the javax.net.ssl.trustStoreType property to PKCS12. If you do not use the default keystore file, set the property to the appropriate keystore type.

    Through 19.0.0.2, if you use the default Java keystore (JKS) type, remove this line for setting the property.

  4. Replace the userid and password values for the JMXConnector.CREDENTIALS property. Use the administrator user ID and password for the server.
  5. Set the host name and port number for the server in the JMXServiceURL constructor by using one of the following methods:
    1. Use the HTTPS port number. The default number is 9443.
    2. Use the contents of the file ${server.output.dir}/logs/state/com.ibm.ws.jmx.rest.address as the JMXServiceURLconstructor parameter. The program writes this file when a server starts with the restConnector-2.0 feature that is configured and contains the REST endpoint, such as service:jmx:rest://localhost:9443/IBMJMXConnectorREST.
  6. To run the client application on a different host machine, configure the server HTTP endpoint to accept connections from remote hosts.
    For example, use an asterisk (*) as the host attribute of the defaultHttpEndpoint endpoint.
    <httpEndpoint id="defaultHttpEndpoint"
         httpPort="9080"
         httpsPort="9443"
         host="*" />
  7. Optional: Disable host name verification for Secure Sockets Layer (SSL) certificates. The certificates that are installed with Liberty might not contain the host name of where the server is running. If you want to disable host name verification of SSL certificates, you can set the system property com.ibm.ws.jmx.connector.client.disableURLHostnameVerification to true, which disables host name verification for all connections. To disable host name verification on a per-connection basis, pass the property as a new environment when you create the JMX connection:
    HashMap<String, Object> environment = new HashMap<String, Object>();
    environment.put("jmx.remote.protocol.provider.pkgs", "com.ibm.ws.jmx.connector.client");
    environment.put("com.ibm.ws.jmx.connector.client.disableURLHostnameVerification", Boolean.TRUE);
    environment.put(JMXConnector.CREDENTIALS, new String[] { "userid", "password" });
    ...
    
  8. Optional: Configure JMX REST connector settings by using the environment Map.
    ...
    HashMap<String, Object> environment = new HashMap<String, Object>();
    environment.put("com.ibm.ws.jmx.connector.client.rest.maxServerWaitTime", 0);
    environment.put("com.ibm.ws.jmx.connector.client.rest.notificationDeliveryInterval", 65000);
    ...
  9. Optional: The Liberty REST connector allows a specific custom SSL socket factory to be used to obtain sockets. If the javax.net.ssl.SSLHandshakeException: com.ibm.jsse2.util.j: PKIX path building failed: java.security.cert.CertPathBuilderException: unable to find valid certification path to requested target exception is displayed, you can create your own SSLContext from your own keystores and then use the SocketFactory from that context with the REST connector.
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream inputStream = new FileInputStream("myTrustStore.jks");
    trustStore.load(inputStream, "password".toCharArray());
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(trustStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustManagers, null);
     
    Map<String, Object> environment = new HashMap<String, Object>(); 
    environment.put(ConnectorSettings.CUSTOM_SSLSOCKETFACTORY, sslContext.getSocketFactory()); 
    environment.put(ConnectorSettings.DISABLE_HOSTNAME_VERIFICATION, true); 
    environment.put("jmx.remote.protocol.provider.pkgs", "com.ibm.ws.jmx.connector.client"); 
    environment.put(JMXConnector.CREDENTIALS, new String[] { "userid", "password" });          
    JMXServiceURL url = new JMXServiceURL("REST", "localhost", 9443, "/IBMJMXConnectorREST"); 
    jmxConn = JMXConnectorFactory.connect(url, environment);

What to do next

To access JMX MBeans in your application, see Examples of accessing MBean attributes and operations.