【问题标题】:How to make the JMX encrypted password authentication work?如何使 JMX 加密密码认证起作用?
【发布时间】:2014-01-22 09:40:40
【问题描述】:

我正在使用 JMX 远程监控我的服务器。但是,jmx-access 和 jmx-password 存储了我不想要的明文密码。

How to encrypt passwords for JConsole's password fileHow to make the JMX custom authentication work?How do I create a Login Module?之后,我编写了一个自定义登录模块。

我的登录模块:

public class EncryptedFileLoginModule implements LoginModule {
        private Subject subject;
        private CallbackHandler callbackHandler;
        private Map sharedState;
        private Map options;

        private String name;
        private String password;

        private boolean succeeded = false;

        public EncryptedFileLoginModule() {
            System.out.println("Login Module - constructor called");
        }

        public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
                Map<String, ?> options) {

            System.out.println("Login Module - initialize called");
            this.subject = subject;
            this.callbackHandler = callbackHandler;
            this.sharedState = sharedState;
            this.options = options;

            System.out.println("testOption value: " + (String) options.get("testOption"));

            succeeded = false;
        }

        public boolean login() throws LoginException {
            System.out.println("Login Module - login called");
            if (callbackHandler == null) {
                throw new LoginException("Oops, callbackHandler is null");
            }

            Callback[] callbacks = new Callback[2];
            callbacks[0] = new NameCallback("name:");
            callbacks[1] = new PasswordCallback("password:", false);

            try {
                callbackHandler.handle(callbacks);
            } catch (IOException e) {
                throw new LoginException("Oops, IOException calling handle on callbackHandler");
            } catch (UnsupportedCallbackException e) {
                throw new LoginException("Oops, UnsupportedCallbackException calling handle on callbackHandler");
            }

            NameCallback nameCallback = (NameCallback) callbacks[0];
            PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];

            name = nameCallback.getName();
            password = new String(passwordCallback.getPassword());

            if ("a".equals(name) && "a".equals(password)) {
                System.out.println("Success! You get to log in!");
                succeeded = true;
                return succeeded;
            } else {
                System.out.println("Failure! You don't get to log in");
                succeeded = false;
                throw new FailedLoginException("Sorry! No login for you.");
            }
        }

        public boolean abort() throws LoginException {
            System.out.println("Login Module - abort called");
            return false;
        }

        public boolean commit() throws LoginException {
            System.out.println("Login Module - commit called");
            return succeeded;
        }

        public boolean logout() throws LoginException {
            System.out.println("Login Module - logout called");
            return false;
        }

    }

    class UserPrincipal implements Principal, Serializable {

        private static final long serialVersionUID = -4604480892359393296L;
        private String name;

        public UserPrincipal(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public String toString() {
            return name;
        }
        public boolean equals(Object o) {
            return o instanceof UserPrincipal &&
                   ((UserPrincipal)o).name.equals(name);
        }
        public int hashCode() {
            return name.hashCode();
        }
    }

    class StatePrincipal implements Principal, Serializable {
        private static final long serialVersionUID = 8429580270033209093L;
        private String state;

        public StatePrincipal(String state) {
            this.state = state;
        }
        public String getName() {
            return state;
        }
        public String toString() {
            return state;
        }
        public boolean equals(Object o) {
            return o instanceof StatePrincipal && ((StatePrincipal)o).equals(state);
        }
        public int hashCode() {
            return state.hashCode();
        }
    }

这是我的登录模块配置文件(d:/mysecurity.cfg):

MyLoginModule {
    cn.com.singlee.slice.security.EncryptedFileLoginModule REQUIRED 
        testOption=here_is_an_option;
};

启动服务器时,我使用以下参数:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999  
-Dcom.sun.management.jmxremote.ssl=false 
-Djava.security.auth.login.config=d:/mysecurity.cfg
-Dcom.sun.management.jmxremote.login.config=MyLoginModule 

但是,当我尝试使用 JCsonle 连接服务器时,我无法登录。服务器似乎能够使用这些日志输出成功调用自定义身份验证过程:

Login Module - constructor called
Login Module - initialize called
testOption value: here_is_an_option
Login Module - login called
Success! You get to log in!
Login Module - commit called

但是 JConsole 报告错误(我在调试模式下使用“jconsole -debug”启动了 JC​​onsole):

java.lang.SecurityException: Access denied! No entries found in the access file [C:\Program Files\Java\jre7\lib\management\jmxremote.access] for any of the authenticated identities []
    at sun.management.jmxremote.ConnectorBootstrap$AccessFileCheckerAuthenticator.checkAccessFileEntries(Unknown Source)
    at sun.management.jmxremote.ConnectorBootstrap$AccessFileCheckerAuthenticator.authenticate(Unknown Source)
    at javax.management.remote.rmi.RMIServerImpl.doNewClient(Unknown Source)
    at javax.management.remote.rmi.RMIServerImpl.newClient(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:160)
    at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
    at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2370)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:296)
    at sun.tools.jconsole.ProxyClient.tryConnect(ProxyClient.java:366)
    at sun.tools.jconsole.ProxyClient.connect(ProxyClient.java:314)
    at sun.tools.jconsole.VMPanel$2.run(VMPanel.java:295)

此错误提示在 jmxremote.access 中未找到经过身份验证的身份。

既然我使用的是自定义认证登录模块,为什么需要jmxremote.access?

而且,即使我在jmxremote.access中添加了测试用户“a”,错误仍然存​​在。

有什么线索吗?

【问题讨论】:

    标签: java authentication rmi jmx


    【解决方案1】:

    感谢这篇文章 jconsole -debug 是突破

    我相信您缺少的是您没有在 jmxremote.access 中配置“a”,使用上面的示例,当我更改了几行时它对我有用

    注意添加的

    user = new JMXPrincipal(name);
    

    并使用“jmxremote.access”中未注释的行

    controlRole readwrite
    

    我希望这对处于相同情况的其他程序员有所帮助。

        public class EncryptedFileLoginModule implements LoginModule {
        private Subject subject;
        private CallbackHandler callbackHandler;
        private Map sharedState;
        private Map options;
        private JMXPrincipal user;
    
        private String name;
        private String password;
    
        private boolean succeeded = false;
    
        public EncryptedFileLoginModule() {
            System.out.println("Login Module - constructor called");
        }
    
        public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
                               Map<String, ?> options) {
    
            System.out.println("Login Module - initialize called");
            this.subject = subject;
            this.callbackHandler = callbackHandler;
            this.sharedState = sharedState;
            this.options = options;
    
            System.out.println("testOption value: " + (String) options.get("testOption"));
    
            succeeded = false;
        }
    
        public boolean login() throws LoginException {
            System.out.println("Login Module - login called");
            if (callbackHandler == null) {
                throw new LoginException("Oops, callbackHandler is null");
            }
    
            Callback[] callbacks = new Callback[2];
            callbacks[0] = new NameCallback("name:");
            callbacks[1] = new PasswordCallback("password:", false);
    
            try {
                callbackHandler.handle(callbacks);
            } catch (IOException e) {
                throw new LoginException("Oops, IOException calling handle on callbackHandler");
            } catch (UnsupportedCallbackException e) {
                throw new LoginException("Oops, UnsupportedCallbackException calling handle on callbackHandler");
            }
    
            NameCallback nameCallback = (NameCallback) callbacks[0];
            PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];
    
            name = nameCallback.getName();
            password = new String(passwordCallback.getPassword());
    
            if ("controlRole".equals(name) && "a".equals(password)) {
                System.out.println("Success! You get to log in!");
                // Create a new user principal
                user = new JMXPrincipal(name);
                succeeded = true;
                return succeeded;
            } else {
                System.out.println("Failure! You don't get to log in");
                succeeded = false;
                throw new FailedLoginException("Sorry! No login for you.");
            }
        }
    
        public boolean abort() throws LoginException {
            System.out.println("Login Module - abort called");
            return false;
        }
    
        public boolean commit() throws LoginException {
            System.out.println("Login Module - commit called");
            subject.getPrincipals().add(user);
            return succeeded;
        }
    
        public boolean logout() throws LoginException {
            System.out.println("Login Module - logout called");
            user = null;
            succeeded = false;
            return false;
        }
    
    }
    
    class UserPrincipal implements Principal, Serializable {
    
        private static final long serialVersionUID = -4604480892359393296L;
        private String name;
    
        public UserPrincipal(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public String toString() {
            return name;
        }
        public boolean equals(Object o) {
            return o instanceof UserPrincipal &&
                    ((UserPrincipal)o).name.equals(name);
        }
        public int hashCode() {
            return name.hashCode();
        }
    }
    
    class StatePrincipal implements Principal, Serializable {
        private static final long serialVersionUID = 8429580270033209093L;
        private String state;
    
        public StatePrincipal(String state) {
            this.state = state;
        }
        public String getName() {
            return state;
        }
        public String toString() {
            return state;
        }
        public boolean equals(Object o) {
            return o instanceof StatePrincipal && ((StatePrincipal)o).equals(state);
        }
        public int hashCode() {
            return state.hashCode();
        }
    }
    

    【讨论】:

    • 简单明了的答案...您拯救了我的一天,谢谢!
    猜你喜欢
    • 2014-02-14
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多