我是JMX的新手,正在尝试使用JMX进行远程监控,并遵循Monitoring and Management Using JMX Technology上的oracle文档并尝试发布Authentication and Authorization in JMX RMI connectors帖子中的示例。我可以使用密码和访问文件创建Hello World MBean示例,现在我想用自定义转发器实现相同的授权(2中的用例2)。
我写的java代码如图所示但是当我登录jConsole时 monitorRole (readOnly) 凭据提供连接失败错误,但适用于 controlRole (readWrite)。
以下是来自自定义转发器的授权的部分代码。请告诉我在monitorRole授权的代码中需要做哪些更改。
// "role1" can perform any operation other than "createMBean" and "unregisterMBean"
if (identity.equals("controlRole")) {
return method.invoke(mbs, args);
}
// "role2" can only call "getAttribute" on the MBeanServerDelegate MBean
if (identity.equals("monitorRole") &&
methodName.equals("getAttribute") &&
MBeanServerDelegate.DELEGATE_NAME.equals(args[0])) {
return method.invoke(mbs, args);
}
完整的代码如下:
public class Agent {
public static class MBSFInvocationHandler implements InvocationHandler {
public static MBeanServerForwarder newProxyInstance() {
final InvocationHandler handler = new MBSFInvocationHandler();
final Class[] interfaces =
new Class[] {MBeanServerForwarder.class};
Object proxy = Proxy.newProxyInstance(
MBeanServerForwarder.class.getClassLoader(),
interfaces,
handler);
return MBeanServerForwarder.class.cast(proxy);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
final String methodName = method.getName();
if (methodName.equals("getMBeanServer")) {
return mbs;
}
if (methodName.equals("setMBeanServer")) {
if (args[0] == null)
throw new IllegalArgumentException("Null MBeanServer");
if (mbs != null)
throw new IllegalArgumentException("MBeanServer object " +
"already initialized");
mbs = (MBeanServer) args[0];
return null;
}
// Retrieve Subject from current AccessControlContext
AccessControlContext acc = AccessController.getContext();
Subject subject = Subject.getSubject(acc);
// Allow operations performed locally on behalf of the connector server itself
if (subject == null) {
return method.invoke(mbs, args);
}
// Restrict access to "createMBean" and "unregisterMBean" to any user
if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) {
throw new SecurityException("Access denied");
}
// Retrieve JMXPrincipal from Subject
Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
if (principals == null || principals.isEmpty()) {
throw new SecurityException("Access denied");
}
Principal principal = principals.iterator().next();
String identity = principal.getName();
// "role1" can perform any operation other than "createMBean" and "unregisterMBean"
if (identity.equals("controlRole")) {
return method.invoke(mbs, args);
}
// "role2" can only call "getAttribute" on the MBeanServerDelegate MBean
if (identity.equals("monitorRole") &&
methodName.equals("getAttribute") &&
MBeanServerDelegate.DELEGATE_NAME.equals(args[0])) {
return method.invoke(mbs, args);
}
throw new SecurityException("Access denied");
}
private MBeanServer mbs;
}
public static void main(String[] args) throws Exception {
// Ensure cryptographically strong random number generator used
// to choose the object number - see java.rmi.server.ObjID
//
System.setProperty("java.rmi.server.randomIDs", "true");
// Start an RMI registry on port 3000.
//
System.out.println("Create RMI registry on port 3000");
LocateRegistry.createRegistry(3000);
// Retrieve the PlatformMBeanServer.
//
System.out.println("Get the platform's MBean server");
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// --------------------------------------------------------------------------
// Construct the ObjectName for the Hello MBean we will register
ObjectName mbeanName = new ObjectName("com.example:type=Hello");
// Create the Hello World MBean
Hello mbean = new Hello();
// Register the Hello World MBean
mbs.registerMBean(mbean, mbeanName);
//------------------------------------------------------------------------------
// Environment map.
System.out.println("Initialize the environment map");
HashMap<String,Object> env = new HashMap<String,Object>();
// Provide SSL-based RMI socket factories.
//
// The protocol and cipher suites to be enabled will be the ones
// defined by the default JSSE implementation and only server
// authentication will be required.
//
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf);
// Provide the password file used by the connector server to
// perform user authentication. The password file is a properties
// based text file specifying username/password pairs.
//
// env.put(JMXConnectorServer.AUTHENTICATOR, new RealmJMXAuthenticator());
// Provide the access level file used by the connector server to
// perform user authorization. The access level file is a properties
// based text file specifying username/access level pairs where
// access level is either "readonly" or "readwrite" access to the
// MBeanServer operations.
//
env.put("jmx.remote.x.password.file", "jmxremote.password");
// Create an RMI connector server.
//
// As specified in the JMXServiceURL the RMIServer stub will be
// registered in the RMI registry running in the local host on
// port 3000 with the name "jmxrmi". This is the same name the
// out-of-the-box management agent uses to register the RMIServer
// stub too.
//
System.out.println("Create an RMI connector server");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:3000/jmxrmi");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
MBeanServerForwarder mbsf = MBSFInvocationHandler.newProxyInstance();
cs.setMBeanServerForwarder(mbsf);
// Start the RMI connector server.
//
System.out.println("Start the RMI connector server");
cs.start();
}
}