1

我正在使用以下代码按照 Oracle 文档创建具有 TLS 和 JMXMP 的自定义 JMX 服务器。它运行良好,我可以毫无问题地连接到服务器,但是我想在身份验证中添加“USER”和“PASSWORD”,但是指定“password.properties”和“access.properties”不起作用, JMX 似乎忽略了这两个选项。有人可以阐明配置 USER 和 PASSWORD 并纠正此问题的正确方法吗?谢谢

     private JMXServiceURL url() {
        final String url = String.format( "service:jmx:jmxmp://%s:%s", host(), port() );
        try {

           return new JMXServiceURL( url );

        } catch( Throwable exception ) {
           throw new RuntimeException( String.format( "Failed to create JMX Service URL: %s", url ), exception );
        }
     }

     private Map<String, Object> env() {
        final Map<String, Object> env = new LinkedHashMap<String, Object>();


         try {

             String keystore = "jmx.keystore";

             char keystorepass[] = "12345678".toCharArray();
             char keypassword[] = "12345678".toCharArray();

             KeyStore ks = KeyStore.getInstance("JKS");
             ks.load(new FileInputStream(keystore), keystorepass);
             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

             kmf.init(ks, keypassword);
             SSLContext ctx = SSLContext.getInstance("TLSv1");
             ctx.init(kmf.getKeyManagers(), null, null);
             SSLSocketFactory ssf = ctx.getSocketFactory();

             env.put("jmx.remote.profiles", "TLS");
             env.put("jmx.remote.tls.socket.factory", ssf);
             env.put("jmx.remote.tls.enabled.protocols", "TLSv1");
             env.put("jmx.remote.tls.enabled.cipher.suites","SSL_RSA_WITH_NULL_MD5");


             env.put("jmx.remote.x.password.file", "password.properties");
             env.put("jmx.remote.x.access.file","access.properties");


         } catch (Exception e) {
             e.printStackTrace();
         }


         return env;
     }

     private MBeanServer server() {
        return ManagementFactory.getPlatformMBeanServer();
     }

     private JMXConnectorServer connector() {
        try {

           ServerProvider.class.getName();
           return JMXConnectorServerFactory.newJMXConnectorServer( url(), env(), server() );

        }catch( Throwable exception ) {
           throw new RuntimeException( "Failed to create JMX connector server factory", exception );
        }
     }
4

1 回答 1

1

我终于能够使用 Oracle 文档中的以下代码为 JMXMP 连接配置额外的用户和密码

MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 
Security.addProvider(new com.sun.jdmk.security.sasl.Provider()); 

HashMap env = new HashMap(); 
env.put("jmx.remote.profiles", "TLS SASL/PLAIN"); 
env.put("jmx.remote.sasl.callback.handler", 
    new PropertiesFileCallbackHandler("password.properties")); 
env.put("jmx.remote.x.access.file",access.properties"); 

JMXServiceURL url = new JMXServiceURL("jmxmp", null, 5555); 
JMXConnectorServer cs = 
   JMXConnectorServerFactory.newJMXConnectorServer(url, 
                                                   env, 
                                                   mbs); 
cs.start();

我为密码验证实现了一个简单的 callBackHandler

public final class PropertiesFileCallbackHandler
    implements CallbackHandler {

    private Properties pwDb;

    /**
     * Contents of files are in the Properties file format.
     *
     * @param pwFile name of file containing name/password 
     */
    public PropertiesFileCallbackHandler(String pwFile) throws IOException {

        if (pwFile != null) {

            File file = new File(pwFile);

            if(file.exists()) {
                pwDb = new Properties();
                pwDb.load(new FileInputStream(file));
            } else {
                throw new IOException("File " + pwFile + " not found");
            }
        }
    }

    public void handle(Callback[] callbacks) 
        throws UnsupportedCallbackException {

        AuthorizeCallback acb = null;
        AuthenticateCallback   aucb = null;

        for (int i = 0; i < callbacks.length; i++) {    
            if (callbacks[i] instanceof AuthorizeCallback) {
                acb = (AuthorizeCallback) callbacks[i];
            } else if (callbacks[i] instanceof AuthenticateCallback) {
                aucb = (AuthenticateCallback)callbacks[i];
            } else {
                throw new UnsupportedCallbackException(callbacks[i]);
            }
        }

        // Process retrieval of password; can get password if
        // username is available
        if (aucb != null) {
            String username = aucb.getAuthenticationID();
            String password = new String(aucb.getPassword());
            String pw = pwDb.getProperty(username);

            if (pw != null) {
                if(pw.equals(password)){
                    aucb.setAuthenticated(true);
                }
            }
        }

        // Check for authorization
        if (acb != null) {
            String authid = acb.getAuthenticationID();
            String authzid = acb.getAuthorizationID();
            if (authid.equals(authzid)) {
                // Self is always authorized
                acb.setAuthorized(true);
            }
        }
    }
} 
于 2017-07-10T18:00:05.163 回答