Applies to: JBoss 4.0.5 GA
As I am working on a rather complex application with a lot of dependancy bounded MBeans I found it necessary to have a small application, in a different JVM, invoke a MBean method for administrative purposes. Even if this sounded easy at the begining it seemed that I had to face 2 problems:
- JBoss JMX implementation
- JAAS access to the secured console
Since I both googled and searched JBoss forums without much help I decided, upon succeding, to write this article as it might help someone futher.
The ideea was to get access to a MBean service with the name:
ro.nit.test:service=Test
and to be able to get it’s “Message” attribute and also invoke a remove method called: “printMessage”. The jmx-console was protected with admin/simple
The working code is:
AppCallbackHandler handler = new AppCallbackHandler("admin", "simple".toCharArray());
LoginContext lc = new LoginContext("TestClient", handler);
System.out.println("Created LoginContext");lc.login();
Hashtable env = new Hashtable();
String factory = "org.jnp.interfaces.NamingContextFactory";
env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
String url1 = "jnp://localhost:1099";env.put(Context.PROVIDER_URL, url1);
env.put(Context.SECURITY_CREDENTIALS, "simple");
env.put(Context.SECURITY_PRINCIPAL, "admin");
env.put(Context.SECURITY_PROTOCOL, "testLoginInitialContext");
Context ctx = new InitialContext(env);
MBeanServerConnection mconn = (MBeanServerConnection) ctx.lookup("jmx/invoker/RMIAdaptor");
ObjectName name = new ObjectName("ro.nit.test:service=Test");
Object val = mconn.getAttribute(name, "Message");
System.out.println(name + "\n\tmessage=" + val);
mconn.invoke(name, "printMessage", null, null);
This makes use of the following CallbackHandler implementation:
static class AppCallbackHandler implements CallbackHandler {
private String username;
private char[] password;
public AppCallbackHandler(String username, char[] password) {
this.username = username;
this.password = password;
}
public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
NameCallback nc = (NameCallback) callbacks[i];
nc.setName(username);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) callbacks[i];
pc.setPassword(password);
} else {
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
}
}
}
}
The “auth.conf” file required by JAAS:
other {
// jBoss LoginModule org.jboss.security.ClientLoginModule required ;
// Put your login modules that need jBoss here};
The JVM parameters:
-Djava.security.auth.login.config=file:${path to file}/auth.conf
Links with helped me found the solution:
- http://www.jboss.com/index.html?module=bb&op=viewtopic&t=95530&view=previous
- http://www.jboss.org/index.html?module=bb&op=viewtopic&t=84303
- http://www.jboss.org/index.html?module=bb&op=viewtopic&t=83861
Some errors which I got on the way:
- Exception in thread “main” java.lang.SecurityException: Failed to authenticate principal=null, securityDomain=jmx-console
The original code (according to JSR160):
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8080/<span class="highlightedSearchTerm">jmx-console</span>");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName stdMBeanName = new ObjectName("ro.nit.test:service=Test");
mbsc.setAttribute(stdMBeanName, new Attribute("Message", "New message set from remote"));
// TODO, will not work with JBOSS since it does not implement the
// JMX properly
// http://www.jboss.com/index.html?module=bb&op=viewtopic&t=95530&view=previous
Comments:
Buttigieg Luc -
Hi, following your advices and some other from the resources that you are explaining, I succeeded to get a remote connection with a secured JBoss with the following code:
Hashtable env = new Hashtable();
String factory = “org.jboss.security.jndi.JndiLoginInitialContextFactory”;
env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
String url = “jnp://localhost:1099”;
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_CREDENTIALS, “simple”);
env.put(Context.SECURITY_PRINCIPAL, “admin”);
Context ctx = new InitialContext(env);
…
Thanks,
Luc
Sid -
thanks for this post. it has been extremely helpful!
r -
Saved me a bunch of time
Len -
Glad I could help.
nicolae -
Thanks for the content. It was really helpful
Torsten -
Thanks from me too - helped me as well!
Pat -
Did you run this as a Standalone client or from within a Jboss server ? I can run something similar from a standalone client but it failes with a principal=null, when I run the *same* class from within a servlet. I think the JBoss server expects security credentials passed in a different way ? One more thing : You auth.conf has *both* the lines commented out. Is that how you wanted ? thanks Pat
len -
Hello Pat, I think it’s possible things have changed a lot since I wrote this article. Surely they don’t work in JBoss 5. Unfortunately with each new jboss you have to retest and re-find many things. I wish you luck. Len