我是 JMX 新手,我正在尝试使用 JMX 进行远程监控,并遵循了有关使用 JMX 技术进行监控和管理的 Oracle 文档,并正在尝试来自 JMX RMI 连接器中的 post Authentication and Authorization的示例。我可以使用密码和访问文件创建 Hello World MBean 示例,现在我想使用自定义转发器来实现相同的授权(用例 2 in 2)。
我编写了如图所示的 java 代码,但是当我使用 monitorRole (readOnly) 凭据登录到 jConsole 时,它给出了连接失败错误,但对于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();
}
}