如何使用使用 TLS 和 JMXMP 的自定义 JMX 服务器对用户和密码进行身份验证



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

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 );
}
}

我终于能够使用 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();

我实现了一个简单的调用回处理程序用于密码验证

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);
}
}
}
} 

最新更新