I have some code connecting to JMX and getting mBean by name. Now I'm writing tests with JUnit for it. I have already done some tests without authentication using something like this:
private static void startJmxServer() throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
LocateRegistry.createRegistry(PORT);
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + HOST + ':' + PORT + "/jmxrmi");
JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
Example exampleMBean = new Example();
ObjectName exampleName = new ObjectName(MBEAN_NAME);
mbs.registerMBean(exampleMBean, exampleName);
connectorServer.start();
}
Now I want to do some test with authentication. So I need to specify next JVM properies:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.access.file=/somepath/jmxremote.access
-Dcom.sun.management.jmxremote.password.file=/somepath/jmxremote.password
I've already tried passing this properties in JMXConnectorServer
environment variable. Also I've tried System.setProperty
. But have failed, as connection was available without any credentials.
The only way, that makes it work is:
private static void startJmxServer() throws Exception {
String name = ManagementFactory.getRuntimeMXBean().getName();
VirtualMachine vm = VirtualMachine.attach(name.substring(0, name.indexOf('@')));
String lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
if (lca == null) {
Path p = Paths.get(System.getProperty("java.home")).normalize();
if (!"jre".equals(p.getName(p.getNameCount() - 1).toString()
.toLowerCase())) {
p = p.resolve("jre");
}
File f = p.resolve("lib").resolve("management-agent.jar").toFile();
if (!f.exists()) {
throw new IOException("Management agent not found");
}
String options = String.format("com.sun.management.jmxremote.port=%d, " +
"com.sun.management.jmxremote.authenticate=true, " +
"com.sun.management.jmxremote.ssl=false, " +
"com.sun.management.jmxremote.access.file=/somepath/jmxremote.access, " +
"com.sun.management.jmxremote.password.file=/somepath/jmxremote.password", PORT);
vm.loadAgent(f.getCanonicalPath(), options);
}
vm.detach();
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
Example exampleMBean = new Example();
ObjectName exampleName = new ObjectName(MBEAN_NAME);
mbs.registerMBean(exampleMBean, exampleName);
}
But as agent was loaded I can not change VM properties to run test without authentication.Also I'm want to avoid such sort of thing, because of need in manual defining tools.jar and want to use common JMX tools. Any idea how to manage this?
Authentication configuration is passed in environment
- the second argument to JMXConnectorServerFactory.newJMXConnectorServer
.
HashMap<String, Object> env = new HashMap<>();
env.put("jmx.remote.x.password.file", "/somepath/jmxremote.password");
env.put("jmx.remote.x.access.file", "/somepath/jmxremote.access");
JMXConnectorServer connectorServer =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
Note that the attribute names here differ from property names.
Consult ConnectorBootstrap.java from JDK sources to see how the default JMXConnectorServer is initialized.