Following my recent post on JMX Secure Connections / Avoiding Java System Properties, I am making another addition to MarkUtils: MarkUtils-JMX.
JMX Management Bean Metadata
My primary inspiration for this library was that JMX provides a generous amount of metadata along with each management bean, attribute, operation, and parameter - including names, descriptions, and impacts
UNKNOWN) for operations.
Parameter names must be provided through metadata, otherwise only the generated defaults of
p1, etc. are displayed.
Unfortunately, associating this data with a management bean is currently a pain, and the only support available for this through the JDK itself is by subclassing
or completely instantiating a
MBeanInfo yourself, and returning from a subclass of
StandardMBean or from a custom
MarkUtils-JMX provides a
MBeanInfoBuilder class that serves as an alternative to the non-public classes used to create
MBeanInfo's within the JDK.
The most significant feature of
MBeanInfoBuilder is support for including names, descriptions, and impacts that are read from Java annotations.
The supported annotations are provided as part of this library in the
Similar functionality is planned for release with Java 7 as part of JMX 2.0 / JSR 255, as detailed by Eamonn McManus in Playing with the JMX 2.0 API (2008-08-06, weblogs.java.net).
Unfortunately, while I'm sure the annotations will not be compatible with my own (even just due to mine being in a
com.ziesemer package), mine are available immediately, and support both Java 1.5 / 5.0 and Java 1.6 / 6.
MBeanInfoBuilder is not intended to be a complete replacement, as it currently doesn't support constructors, notifications, and descriptors, mostly as I currently have no use for them.
However, these limitations are almost completely mitigated by
MBeanInfoCombiner, which allows the metadata from a custom
MBeanInfo built by
MBeanInfoBuilder to supplement the default
MBeanInfo built by the JDK's
- effectively adding support for the custom annotations.
SimpleMBean, also included, is a alternative to the JDK's
StandardMBean (as with
MBeanInfoBuilder, and doesn't depend upon non-public classes.
Along with utilizing
MBeanInfoBuilder by default, this allows for easy extension / customization of the implementation.
SimpleMBean are designed and written with performance as a primary focus.
Performance is more of a concern for the actual MBean implementation than the building of the
MBeanInfo, as the information should only have to be built once, where as the MBean implementation will likely be called repeatedly and often throughout the lifetime of the hosting application.
Authentication and Authorization
Also included in this library are classes to handle most of the work around securing JMX access by providing authentication and authorization.
Authentication is the simpler half, and is provided by
This abstract class handles all the validation and breaking-down of the
Object input parameter.
An implementing class must only implement
Subject authenticate(String username, String password).
The authentication implementation is then registered as a value to the
and passed-in as part of the environment map to
Authorization is a little more complex.
Limited support is built-in to the JDK through Java's security policy and
Unfortunately, the JDK approach seems overly-complex and did not meet several of my requirements.
This library provides a high-performance and flexible alternative,
BaseJmxAuthorizer and the other classes in
com.ziesemer.utils.jmx.server.authorization are based on "Use Case 2" in Luis-Miguel Alventosa's blog post,
Authentication and Authorization in JMX RMI connectors (2006-09-25, blogs.sun.com),
InvocationHandler is used to selectively proxy requests to the management bean.
BaseJmxAuthorizer was designed and written with performance as a primary focus, along with flexibility.
It is based on a
Map (implemented with a
associating incoming method names (e.g.
invoke) with an associated handler.
Map is publicly exposed, allowing for easy customization through modifications made to the map.
Several default handlers, including the simple and unconditional
DenyHandler, are included in the package.
ReadOnlyInvokeHandler is also provided, and allows all calls to operations / methods that are considered to be "read-only".
The request impact (
MBeanOperationInfo.getImpact()) is first consulted, and the request is allowed if
INFO is returned.
The request is otherwise denied, unless the impact returned is
UNKNOWN, in which case an attempt to determine if the method has a "read-only" name is made,
which checks for if the method name starts with "
query", or is equal to "
By default, it also allows for calls to
These allowances allow for full and easy use of all "read-only" functionality provided by JConsole by default, without compromising on security.
Unfortunately, under Java 1.5 / 5.0, this currently denies access to
get* methods on
LoggingMXBean, as these operations are marked as
ACTION_INFO rather than
UNKNOWN (or more preferably / correctly,
This appears to have been somewhat fixed in Java 1.6 / 6, as per Sun Bug 6320104, it seems that
UNKNOWN was simply not supported by the infrastructure in 1.5 / 5.0 at the time.
ReadOnlyJavaFixInvokeHandler is provided in the package as a work-around for use under Java 1.5 / 5.0.
I reported Sun Bug 6933325 to address that these operations should now return
INFO instead of
ACTION_INFO, now that it is possible.
Please view the Javadocs and/or source for additional details.
BaseJmxAuthorizer handles basic logging of method invocations through SLF4J by default.
BaseJmxAuthorizer also simplifies authentication and improves performance by associating permissions with a subclass of
This allows permissions to be obtained for a user once during authorization, without having to re-check permissions on each JMX call.
Just be sure that this caching is accounted for, such that a user doesn't maintain unattended access if / once a permission is removed by the underlying security directory.
A few options could be implementing a session timeout, or adding a call to a customized implementation to also remove the permissions from the runtime if / once removed from the user.
JmxPermissionPrincipal maintains an instance of a subclass of
which contains one or more
JmxPermission (subclass of
Other subclasses may be created and used, but should be kept as singletons.
Please view the Javadocs and/or source for additional details.
Packaging with Apache Maven, Java versions
As with all my other MarkUtils libraries, MarkUtils-JMX is configured, compiled, tested, and packaged using Apache Maven. This library posed a little bit of a challenge, however, as I wanted to provide 2 versions, one built for Java 1.5 / 5.0, and one for Java 1.6 / 6. This is one of the few times I wish that Java had standard support for conditional compilation directives, such as those supported by the C preprocessor.
The primary reason for requiring dual versions is for Java 6's support of
MXBean's, which were not supported in Java 5.
This includes use of the additional 2-arg constructor added to
which as far as I can see, is impossible to implement without being available at compile-time - even if considering reflection tricks.
The solution I decided on for now is to offer dual packages / builds:
The Java 6 version includes the source paths from the Java 5 version.
To clarify, only the Java 5 or the Java 6 version is required, as the Java 6 version is a superset of the Java 5 version.
The Java 5 version includes a
StandardMBeanInfoCombiner5 class that is a subclass of
StandardMBean and utilizes
The Java 6 version includes a
StandardMBeanInfoCombiner6, which is the same as the Java 5 version, but exposes the added constructor and allows use of MXBeans.
This setup actually worked with Maven fairly well, including the ability to automatically run Maven builds against both versions in one operation, and including packaging the build outputs together into the final distribution.
The Java 6 version also includes a
DefaultRegistration class, which registers a few additional custom MXBeans that I found helpful and that provide functionality not currently offered by the MXBeans provided by the JDK (
These include my custom
(As these custom beans themselves don't require any Java 6-specific features or calls at compile time, they are actually included in the Java 5 package.
They just require Java 6 to be registered as MXBeans rather than regular MBeans.)
com.ziesemer.utils.jmx is available on ziesemer.dev.java.net under the GPL license, complete with source code, a compiled .jar, generated JavaDocs, and a suite of 40+ JUnit tests.
com.ziesemer.utils.jmx-*.zip distribution from here.
Please report any bugs or feature requests on the java.net Issue Tracker.