druvu-lib-jmxmp

JMX over one plain TCP socket, with the security a current JVM expects. JMXMP is the JSR-160 “optional” connector: no RMI, no dynamic ports, one port to tunnel. This build runs on JDK 21 to 25 without the Security Manager, and it fails closed.

The public javax.management.remote.* API is the OpenDMK surface, byte for byte, so existing JMXConnectorFactory code recompiles unchanged. The wire security is a deliberate break: the server speaks TLS with SASL/PLAIN and nothing else.

View on GitHub Maven Central


Try it

A server needs one thing, an authenticator. TLS is on without configuration:

import com.druvu.jmxmp.shared.JmxmpServerSecurity;

Map<String, Object> env = JmxmpServerSecurity.builder()
        .tls(sslContext)                 // recommended real cert (omit ⇒ ephemeral self-signed)
        .authenticator(myAuthenticator)  // REQUIRED
        .build();                        // IllegalStateException if the authenticator is missing

var url = new JMXServiceURL("jmxmp", "0.0.0.0", 5555);
var server = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbeanServer);
server.start();

A client:

Map<String, Object> env = new HashMap<>();
env.put("jmx.remote.tls.socket.factory", sslContext.getSocketFactory());
env.put(JMXConnector.CREDENTIALS, new String[] {"alice", "s3cr3t"});

try (JMXConnector c = JMXConnectorFactory.connect(new JMXServiceURL("jmxmp", host, 5555), env)) {
    c.getMBeanServerConnection().getAttribute(name, "Message");
}

What you get

  • Runs on current Java. No SecurityManager, no AccessController, no --enable-… flags. Identity travels through the JDK’s own Subject.current().
  • Fails closed. The original file access controller treats a missing subject as “allow everything”, and on JDK 24 and later the subject is always missing. Here no authenticated subject means access denied, pinned by a regression test on JDK 21 and 25.
  • Encrypted by default. With no keystore configured the server makes an ephemeral self-signed certificate at startup, so the listener is never plaintext. Supply your own certificate for server identity. TLS 1.3 unless you say otherwise.
  • Who may do what. A default-deny authorization SPI with a role and ObjectName-pattern policy: READ, WRITE, INVOKE, NOTIFY, per target.
  • A default-deny deserialization filter on every wire stream. The well-known gadget sinks never resolve.
  • Three real JPMS modules. client → common, server → common, no split packages.

What it refuses

  • plaintext, TLS-only, SASL-only, and every SASL mechanism other than PLAIN
  • a server without a JMXAuthenticator
  • remote MBean lifecycle from a client: create, register, unregister, instantiate. Permanently. There is no verb to grant it.
  • an opt-out by system property or command line. The client can reach a legacy plaintext endpoint, but only through a policy written in code.

Install

On Maven Central. Java 21 or newer. Pick the side you are on; each brings druvu-lib-jmxmp-common with it.

<dependency>
    <groupId>com.druvu</groupId>
    <artifactId>druvu-lib-jmxmp-client</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>com.druvu</groupId>
    <artifactId>druvu-lib-jmxmp-server</artifactId>
    <version>2.0.0</version>
</dependency>

Where it comes from

The lineage is OpenDMK jmx-optional, shipped for years as jmxremote_optional and unmaintained since 2007. The API is kept as it was. The security model is rebuilt for the platform after JEP 486. The threat model and the support scope are in SECURITY.md; reports through GitHub’s private vulnerability reporting are welcome.

License: GPL v2 with the Classpath exception, or CDDL 1.0. Your choice.


Something it almost does?

Open an issue, or write to me. If it is small and useful to more than you, I will often just build it.


Back to top

Copyright © 2026 druvu.com. All rights reserved.

This site uses Just the Docs, a documentation theme for Jekyll.