Reputation: 111
I am using the following code to create a custom JMX server with TLS and JMXMP following the Oracle documentation. It works well and I can connect to the server with no problem, however I would like to add "USER" and "PASSWORD" to the authentication, however specifying the "password.properties" and the "access.properties" is not working, JMX seems to be ignoring these two options. Can somebody shed some light on the correct way to configure USER and PASSWORD and correct this problem? Thanks
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 );
}
}
Upvotes: 1
Views: 1542
Reputation: 111
I was finally able to configure the additional user and password for the JMXMP connection with the following code from the Oracle documentation
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();
I implemented a simple callBackHandler for the password validation
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);
}
}
}
}
Upvotes: 1