Java JMX Client Example – JMX Authentication

Filed Under: Java

In last tutorial we learned about JMX Basics and how can we use JConsole to manage MBeans. Today we will look into java jmx client example and role based authentication through config files.

Java JMX Client

Although JConsole provides a graphical view but it requires human effort to work with MBean and not suitable where you want to invoke some features of MBean periodically. For example, you have a MBean that provides the current state of application and you want to invoke it to check the state every 10 minutes. In this case, having a java program that can work as JMX Client to connect to JMX MBean server and invoke MBean operations are very useful.
java jmx client example

JMX Client Example

Here we will write a java program that can connect to MBean server and create a proxy application to invoke MBean operations. I will use the MBean application created in JMX Tutorial and use our client program to connect to MBean. Later on we will check how to make our MBean server secure using JMX Configuration files for role based access and how we can use credentials in the JMX Client to connect to MBean server with correct role.

Before writing JMX Client application, we need to know the port where MBean server is running. Also for starter, we will disable all the authentication. We can do all these by passing correct java options.

So I will start my MBean with following command. Notice the java options specified for MBean server port and disabling SSL and authentication.


pankaj@JD:~/CODE/JavaProject/bin$ java -cp . -Dcom.sun.management.jmxremote.port=1234 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false com.journaldev.jmx.SystemConfigManagement
Thread Count=10:::Schema Name=default
Thread Count=10:::Schema Name=default
Thread Count=10:::Schema Name=default
...

JMX URL

For client application to get the MBean proxy, first we need to create JMXServiceURL by passing the RMI host and port.


JMXServiceURL url =
            new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi");

After that we have to get the JMXConnector instance using it’s factory class.


JMXConnector jmxConnector = JMXConnectorFactory.connect(url);

After that we get MBeanServerConnection from the JMXConnector instance.


MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();

After that we get MBean proxy instance using MBeanServerInvocationHandler.


//ObjectName should be same as your MBean name
ObjectName mbeanName = new ObjectName("com.journaldev.jmx:type=SystemConfig");

//Get MBean proxy instance that will be used to make calls to registered MBean
SystemConfigMBean mbeanProxy =
    (SystemConfigMBean) MBeanServerInvocationHandler.newProxyInstance(
        mbeanServerConnection, mbeanName, SystemConfigMBean.class, true);

Once we get the proxy instance, we can invoke any operation exposed by the MBean.

Java JMX Client Example Program

Here is the complete JMX Client program that connects to the MBean server and get the SystemConfig MBean proxy instance and invoke exposed methods.


package com.journaldev.jmx;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class SystemConfigClient {

    public static final String HOST = "localhost";
    public static final String PORT = "1234";

    public static void main(String[] args) throws IOException, MalformedObjectNameException {
        JMXServiceURL url =
            new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi");
        
        JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
        MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
        //ObjectName should be same as your MBean name
        ObjectName mbeanName = new ObjectName("com.journaldev.jmx:type=SystemConfig");

        //Get MBean proxy instance that will be used to make calls to registered MBean
        SystemConfigMBean mbeanProxy =
            (SystemConfigMBean) MBeanServerInvocationHandler.newProxyInstance(
                mbeanServerConnection, mbeanName, SystemConfigMBean.class, true);

        //let's make some calls to mbean through proxy and see the results.
        System.out.println("Current SystemConfig::" + mbeanProxy.doConfig());
        
        mbeanProxy.setSchemaName("NewSchema");
        mbeanProxy.setThreadCount(5);
        
        System.out.println("New SystemConfig::" + mbeanProxy.doConfig());
        
        //let's terminate the mbean by making thread count as 0
        mbeanProxy.setThreadCount(0);

        //close the connection
        jmxConnector.close();
    }
}

Before running the client application, make sure our MBean application is started with command given at start of the post.
When we will execute client application, it will print following to console.


Current SystemConfig::No of Threads=10 and DB Schema Name=default
New SystemConfig::No of Threads=5 and DB Schema Name=NewSchema

If you will check terminal where our MBean application is running, you will find following output before program terminates.


Thread Count=10:::Schema Name=default
Thread Count=10:::Schema Name=default
Thread Count=0:::Schema Name=NewSchema

So now we know how to write JMX Client program that can connect to remote MBean server and create MBean proxy to use attributes and operations exposed by MBean.

JMX Role Based Authentication

Let’s start configuring our MBean for role based authentication. For this we need to create three files.

  1. JMX Access File: This file contains the roles and access associated with the roles. The access types are readonly or readwrite. For our purpose, create jmxremote.access file with following content.

    jmxremote.access

    
    myrole readwrite
    

    So the role is “myrole” and it has readwrite access to the MBeans.

  2. JMX Password File: This file contains the password of the different roles we have, the password are cleartext, so Java adds a restriction that only application owner should have read-write access on the file.

    Create a file jmxremote.password with following content.

    jmxremote.password

    
    myrole MYP@SSWORD
    

    After file is created change permission using command chmod 600 jmxremote.password.

  3. JMX Management Config File: This file contains the JMX properties like port, authentication rules, SSL etc. Create a file management.properties with following content.

    management.properties

    
    #enable remote management of MBean
    com.sun.management.jmxremote=true
    com.sun.management.jmxremote.port=1234
    com.sun.management.jmxremote.local.only=false
    
    #enable authentication
    com.sun.management.jmxremote.authenticate=true
    com.sun.management.jmxremote.password.file=/Users/pankaj/CODE/JavaProject/bin/jmxremote.password
    com.sun.management.jmxremote.access.file=/Users/pankaj/CODE/JavaProject/bin/jmxremote.access
    
    #disable SSL authentication
    com.sun.management.jmxremote.ssl=false
    

    Notice the file path given for access file and password file.

Once all the required files are we will start our JMX MBean application with following command.


java -cp . -Dcom.sun.management.config.file=management.properties com.journaldev.jmx.SystemConfigManagement

Now if you will try to run our JMX Client application, it will throw following exception.


Exception in thread "main" java.lang.SecurityException: Authentication failed! Credentials required
	at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticationFailure(JMXPluggableAuthenticator.java:211)
	at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticate(JMXPluggableAuthenticator.java:163)
	at sun.management.jmxremote.ConnectorBootstrap$AccessFileCheckerAuthenticator.authenticate(ConnectorBootstrap.java:219)
	at javax.management.remote.rmi.RMIServerImpl.doNewClient(RMIServerImpl.java:232)

The exception message clearly shows that we need to provide credentials to access the JMX MBean. To provide credentials we need to add following code to our client program.


//for passing credentials for password 
Map<String, String[]> env = new HashMap<>();
String[] credentials = {"myrole", "MYP@SSWORD"};
env.put(JMXConnector.CREDENTIALS, credentials);
        
JMXConnector jmxConnector = JMXConnectorFactory.connect(url, env);

Notice the constructor is changed to provide credentials while connecting to JMX MBean server. Now the program will run fine and produce same output as earlier.

That’s all for Java JMX Client example and JMX authentication for role based access.

Comments

  1. Sudhakar Sharma says:

    I am very much new to jmx. I tried the same and able to connect to the osgi container with the simple java application. But getting connection error in web application deployed in jboss application server. Could you please guide me on this? I want to show all the bundles information deployed in the osgi container from a separate web application running on the same jvm and in different container.

  2. Chintan Patel says:

    Simple and straightforward as always. I always try to find your tutorial for any new point I want to learn. And this time also it fulfilled my expectations. Keep it up. Thanks again 🙂

  3. Srinivas says:

    Hi,

    With this JMX client I can see system related mbeans but not those which I created. And I can see my mbeans in JConsole.
    Using below code to get the registered mbeans but not able to find my mbeans
    Set queryNames = mbeanServerConnection.queryNames(null, null);

    It would be very helpful if anybody can help me.

    Thanks
    Srinivas T

  4. rohan says:

    Thanks Pankaj, this article is surely going to help a lot of beginners like me. Keep up the good work. Would appreciate to have few more advance examples on JMX.

  5. Patrice MOREAUX says:

    Dear Pankaj

    Thanks a lot for these two very well written tutorials on JMX.
    I am professor at University Savoie Mont Blanc (France) on Computer Science and I will use them for my students (master 1 and 2).
    I espially aprreciated the progressive presentation of the technical points.
    I only rewrote the various classes (and changed their names) to discrad the threaCount variable which could introduuce some confusion since in fact, the example application doesn’t use threads.
    Best regards,
    Patrice.

    1. Pankaj says:

      Hi Patrice,

      Thanks for liking the articles and sharing with your students, is it a digital publication or you are using it in the class?

  6. nitin says:

    i dont want to see all the mbeans while i connect using jconsole

  7. rasel says:

    Hello Pankaj,
    i am new to Java and I am given a task for JMX. Your article was quite nice and I have created an mbean server. I can access it by jconsole.
    Now I am strugling to make it secure with username and passwrod invocation from remote access.
    I dont need to create any client program. Just i need to ensure that my mbeans methods are not accesible without authentication.
    my locla servre runs on localhos:8080.
    My question is what is the url ? is it localhost:8080 ?
    I have prepared att the password, acess, properties files. I just need to check by using jconsole whether i can access my mbean with proper credential.
    Please suggest me.

    1. rasel says:

      System.setProperty(“com.sun.management.jmxremote”, “true”);
      System.setProperty(“java.rmi.server.randomIDs”, “true”);
      System.setProperty(“com.sun.management.jmxremote.port”, “6789”);

      System.setProperty(“com.sun.management.jmxremote.ssl”, “false”);
      System.setProperty(“com.sun.management.jmxremote.ssl.need.client.auth”, “true”);
      System.setProperty(“com.sun.management.jmxremote.authenticate”, “true”);
      System.setProperty(“com.sun.management.jmxremote.password.file”,”C:/Program Files/Java/jdk1.7.0_25/jre/lib/management/jmxremote.password”);
      System.setProperty(“com.sun.management.jmxremote.access.file”,”C:/Program Files/Java/jdk1.7.0_25/jre/lib/management/jmxremote.access”);

  8. Vasanth T says:

    Thank you so much Pankaj. I really like your way of explanation and simple example.

  9. Binita Bharati says:

    I was having trouble making a JMXConnector with authentication enabled work. Thank you for the lovely working snippets !

    1. Pankaj says:

      You are welcome Binita.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages