JMX connection via Nashorn javascript jjs

446 views Asked by At

I am writing a script in JavaScript engine that comes with JDK8. This script will use JMX to connect to a remote Java instance. I am using authentication, but no SSL. The JMX connection is working fine from any JMX client, the problem is in this script

The output of the script is:

[root@testvm ~]# /opt/scripts/jmx-test.jjs
{javax.management.remote.JMXConnector.CREDENTIALS=[Ljava.lang.String;@679b62af}
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)
        at javax.management.remote.rmi.RMIServerImpl.newClient(RMIServerImpl.java:199)
        at sun.reflect.GeneratedMethodAccessor18147.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
        at sun.rmi.transport.Transport$1.run(Transport.java:177)
        at sun.rmi.transport.Transport$1.run(Transport.java:174)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
        at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:162)
        at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
        at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2404)
        at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:308)
        at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270)
        at jdk.nashorn.internal.scripts.Script$jmx_test_jjs.runScript(/opt/scripts/jmx-test.jjs:14)
        at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:535)
        at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:209)
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378)
        at jdk.nashorn.tools.Shell.apply(Shell.java:383)
        at jdk.nashorn.tools.Shell.runScripts(Shell.java:312)
        at jdk.nashorn.tools.Shell.run(Shell.java:168)
        at jdk.nashorn.tools.Shell.main(Shell.java:132)
        at jdk.nashorn.tools.Shell.main(Shell.java:111)

Here is the script:

#! /usr/java/jdk1.8.0_25/bin/jjs
host="remotehost"
port=7091
serviceURL = "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi"
url = new javax.management.remote.JMXServiceURL(serviceURL);
stringArrayType = Java.type("java.lang.String[]")
credentials = new stringArrayType(2)
credentials[0]="user"
credentials[1]="password1"
HashMapType = Java.type("java.util.HashMap")
environment = new HashMapType()
environment.put("javax.management.remote.JMXConnector.CREDENTIALS",credentials)
print(environment)
connector = javax.management.remote.JMXConnectorFactory.connect(url,environment)

It seems that credentials become null. See: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/com/sun/jmx/remote/security/JMXPluggableAuthenticator.java#162

The problem is that I do not know how to properly send the environment to the javax.management.remote.JMXConnectorFactory.connect()

Edit: With the answer of @Nicholas, the script now works. Here is the full example:

#! /usr/java/jdk1.8.0_25/bin/jjs
host="remotehost"
port=7091
serviceURL = "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi"
url = new javax.management.remote.JMXServiceURL(serviceURL);
stringArrayType = Java.type("java.lang.String[]")
credentials = new stringArrayType(2)
credentials[0]="user"
credentials[1]="password1"
HashMapType = Java.type("java.util.HashMap")
environment = new HashMapType()
environment.put("jmx.remote.credentials",credentials)
connector = javax.management.remote.JMXConnectorFactory.connect(url,environment)
mbeanServerConnection=connector.getMBeanServerConnection()
ObjectNameType = Java.type("javax.management.ObjectName")

objectName = new ObjectNameType('Catalina:type=Connector,port=8009,address="tomcat.example.org"')
print(mbeanServerConnection.getAttribute(objectName, "proxyName"))

objectName = new ObjectNameType('java.lang:type=Memory')
#print(mbeanServerConnection.getAttribute(objectName, "HeapMemoryUsage"))
print('HeapMemoryUsage, used = ' + mbeanServerConnection.getAttribute(objectName, "HeapMemoryUsage").get('used'))
1

There are 1 answers

0
Nicholas On BEST ANSWER

Take a look at this line of your script:

environment.put("javax.management.remote.JMXConnector.CREDENTIALS",credentials)

The API defines the key of the map entry as the constant javax.management.remote.JMXConnector.CREDENTIALS but the value of the constant is "jmx.remote.credentials".

Therefore, try changing that line to:

environment.put("jmx.remote.credentials",credentials)