1

我是 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();
}

}

4

0 回答 0