[Mc4j-cvs] SF.net SVN: mc4j:[599] trunk/mc4j/modules/ems
Brought to you by:
ghinkl
From: <ian...@us...> - 2009-07-10 21:35:31
|
Revision: 599 http://mc4j.svn.sourceforge.net/mc4j/?rev=599&view=rev Author: ianpspringer Date: 2009-07-10 21:35:14 +0000 (Fri, 10 Jul 2009) Log Message: ----------- use JAAS to authenticate rather than JndiLoginInitialContextFactory+SecurityAssociation (part of fix for https://jira.jboss.org/jira/browse/JOPR-263); bump version up to 1.2.8 in preparation for a release Modified Paths: -------------- trunk/mc4j/modules/ems/build.xml trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/JBossConnectionProvider.java trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/LocalVMProvider.java trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/proxy/GenericMBeanServerProxy.java Added Paths: ----------- trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/ trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossCallbackHandler.java trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossConfiguration.java Modified: trunk/mc4j/modules/ems/build.xml =================================================================== --- trunk/mc4j/modules/ems/build.xml 2009-06-15 19:54:11 UTC (rev 598) +++ trunk/mc4j/modules/ems/build.xml 2009-07-10 21:35:14 UTC (rev 599) @@ -30,7 +30,7 @@ <property name="module.jar" value="org-mc4j-ems.jar"/> - <property name="release.version" value="1.2.7"/> + <property name="release.version" value="1.2.8"/> <target Modified: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/JBossConnectionProvider.java =================================================================== --- trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/JBossConnectionProvider.java 2009-06-15 19:54:11 UTC (rev 598) +++ trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/JBossConnectionProvider.java 2009-07-10 21:35:14 UTC (rev 599) @@ -1,5 +1,5 @@ /* - * Copyright 2002-2004 Greg Hinkle + * Copyright 2002-2009 Greg Hinkle * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,46 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.mc4j.ems.impl.jmx.connection.support.providers; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mc4j.ems.connection.ConnectionException; import org.mc4j.ems.impl.jmx.connection.support.providers.proxy.GenericMBeanServerProxy; +import org.mc4j.ems.impl.jmx.connection.support.providers.jaas.JBossCallbackHandler; +import org.mc4j.ems.impl.jmx.connection.support.providers.jaas.JBossConfiguration; import javax.management.MBeanServer; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.naming.NoInitialContextException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.security.AccessController; -import java.security.Principal; -import java.security.PrivilegedAction; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; +import javax.security.auth.login.Configuration; import java.util.Properties; /** * Represents a Connection to a JBoss JMX Server. This connection - * works against the JBoss RMI connector. + * works against the JBoss RMI connector. If a principal and + * credentials are specified in the connection settings, JAAS is + * used to authenticate prior to each call. * * @author Greg Hinkle (gh...@us...), January 2002 + * @author Ian Springer * @version $Revision$($Author$ / $Date$) */ public class JBossConnectionProvider extends AbstractConnectionProvider { + private static final String NAMING_CONTEXT_FACTORY_CLASS_NAME = "org.jnp.interfaces.NamingContextFactory"; +// private static final String MEJB_JNDI = "ejb/mgmt/MEJB"; private MBeanServer mbeanServer; private GenericMBeanServerProxy proxy; - + private LoginContext loginContext; // private Management mejb; - private static final String MEJB_JNDI = "ejb/mgmt/MEJB"; - private static Log log = LogFactory.getLog(JBossConnectionProvider.class); - protected void doConnect() throws Exception { ClassLoader currentLoader = Thread.currentThread().getContextClassLoader(); @@ -68,8 +68,12 @@ InitialContext context = getInitialContext(); - Object rmiAdaptor = context.lookup(connectionSettings.getJndiName()); + if (getConnectionSettings().getPrincipal() != null) { + initJaasLoginContext(); + } + Object rmiAdaptor = context.lookup(this.connectionSettings.getJndiName()); + // GH: Works around a real strange "LinkageError: Duplicate class found" // by loading these classes in the main connection classloader //Class foo = RMINotificationListener.class; @@ -80,7 +84,7 @@ if (this.proxy != null) { // This is a reconnect - proxy.setRemoteServer(rmiAdaptor); + this.proxy.setRemoteServer(rmiAdaptor); } else { this.proxy = new GenericMBeanServerProxy(rmiAdaptor); this.proxy.setProvider(this); @@ -88,52 +92,28 @@ this.mbeanServer = proxy.buildServerProxy(); } //this.mgmt = retrieveMEJB(); - - // Set the context classloader back to what it was } finally { + // Set the context classloader back to what it was. Thread.currentThread().setContextClassLoader(currentLoader); - } } - public static final String JNDI_LOGIN_CONTEXT_FACTORY_CLASS = "org.jboss.security.jndi.JndiLoginInitialContextFactory"; - private InitialContext getInitialContext() throws NamingException { - Properties props = connectionSettings.getAdvancedProperties(); - - if (connectionSettings.getPrincipal() != null && connectionSettings.getPrincipal().length() != 0) { - try { - Class.forName(JNDI_LOGIN_CONTEXT_FACTORY_CLASS); - log.debug("Utilizing JNDI Login Context Factory for secured access [" + JNDI_LOGIN_CONTEXT_FACTORY_CLASS + "]"); - - props.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_LOGIN_CONTEXT_FACTORY_CLASS); - props.put(Context.SECURITY_PRINCIPAL, connectionSettings.getPrincipal()); - props.put(Context.SECURITY_CREDENTIALS, connectionSettings.getCredentials()); - - } catch (ClassNotFoundException e) { - log.debug("JNDI Login Context Factory not available, directly utilizing SecurityAssociation"); - try { - props.put(Context.INITIAL_CONTEXT_FACTORY, connectionSettings.getInitialContextName()); - resetPrincipalInfo(); - } catch (ClassNotFoundException e1) { - throw new ConnectionException("Secured connection not available with this version of JBoss " + e1.toString(),e1); - } catch (Exception e1) { - throw new ConnectionException("Unable to make secured connection to JBoss due to missing or unexpected security classes",e1); - } - } - - } else { - props.put(Context.INITIAL_CONTEXT_FACTORY, connectionSettings.getInitialContextName()); + Properties props = this.connectionSettings.getAdvancedProperties(); + if (!NAMING_CONTEXT_FACTORY_CLASS_NAME.equals(this.connectionSettings.getInitialContextName())) { + log.warn("Unsupported initial context factory [" + this.connectionSettings.getInitialContextName() + + "] - only " + NAMING_CONTEXT_FACTORY_CLASS_NAME + + " is supported for JBoss connections; using that instead..."); } + props.put(Context.INITIAL_CONTEXT_FACTORY, NAMING_CONTEXT_FACTORY_CLASS_NAME); + props.put(Context.PROVIDER_URL, this.connectionSettings.getServerUrl()); - props.put(Context.PROVIDER_URL, connectionSettings.getServerUrl()); - try { InitialContext context = new InitialContext(props); return context; } catch(NoInitialContextException e) { // Try to be more helpful, indicating the reason we couldn't make the connection in this - // common case of missing libraries + // common case of missing libraries. if (e.getCause() instanceof ClassNotFoundException) { throw new ConnectionException("Necessary classes not found for remote connection, check installation path configuration.",e.getCause()); } @@ -142,49 +122,6 @@ } - private static class SetPrincipalInfoAction implements PrivilegedAction { - Principal principal; - Object credential; - - public SetPrincipalInfoAction(Principal principal, Object credential) { - this.principal = principal; - this.credential = credential; - } - - public Object run() { - try { - Class saClass = Class.forName("org.jboss.security.SecurityAssociation"); - Method setCredentialMethod = saClass.getMethod("setCredential", Object.class); - - setCredentialMethod.invoke(null, credential); - credential = null; - - Method setPrincipleMethod = saClass.getMethod("setPrincipal", Principal.class); - - setPrincipleMethod.invoke(null, principal); - principal = null; - - return null; - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - return null; - } - static void setPrincipalInfo(Principal principal, Object credential) { - SetPrincipalInfoAction action = new SetPrincipalInfoAction(principal, credential); - //noinspection unchecked - AccessController.doPrivileged(action); - } - } - - - /* GH: an aborted attempt at manually changing the polling type public class RMIAdaptorExtension extends RMIConnectorImpl { public RMIAdaptorExtension(RMIAdaptor rmiAdaptor) { @@ -237,17 +174,25 @@ return this.mbeanServer; } - public void resetPrincipalInfo() throws Exception { - // We need to tell the SecurityAssociation class to clear its internal ThreadLocal stack of authenticated - // subjects. Otherwise, every time we set the princiapl info, this stack will grow and will eventually cause the - // heap to max out. For more on this issue, see https://jira.jboss.org/jira/browse/EJBTHREE-558. - Class securityAssociationClass = Class.forName("org.jboss.security.SecurityAssociation"); - Method clearMethod = securityAssociationClass.getMethod("clear"); - clearMethod.invoke(null); + public void login() throws LoginException + { + if (this.loginContext != null) { + this.loginContext.login(); + } + } - Class simplePrincipalClass = Class.forName("org.jboss.security.SimplePrincipal"); - Constructor simplePrincipalConstructor = simplePrincipalClass.getConstructor(String.class); - Principal principal = (Principal) simplePrincipalConstructor.newInstance(getConnectionSettings().getPrincipal()); - SetPrincipalInfoAction.setPrincipalInfo(principal, getConnectionSettings().getCredentials()); + public void logout() throws LoginException + { + if (this.loginContext != null) { + this.loginContext.logout(); + } } + + private void initJaasLoginContext() throws LoginException { + Configuration jaasConfig = new JBossConfiguration(); + Configuration.setConfiguration(jaasConfig); + JBossCallbackHandler jaasCallbackHandler = new JBossCallbackHandler( + this.connectionSettings.getPrincipal(), this.connectionSettings.getCredentials()); + this.loginContext = new LoginContext(JBossConfiguration.JBOSS_ENTRY_NAME, jaasCallbackHandler); + } } Modified: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/LocalVMProvider.java =================================================================== --- trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/LocalVMProvider.java 2009-06-15 19:54:11 UTC (rev 598) +++ trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/LocalVMProvider.java 2009-07-10 21:35:14 UTC (rev 599) @@ -16,7 +16,6 @@ package org.mc4j.ems.impl.jmx.connection.support.providers; -import org.mc4j.ems.connection.EmsException; import org.mc4j.ems.connection.EmsConnectException; import org.mc4j.ems.impl.jmx.connection.support.providers.local.LocalVMConnector; import org.mc4j.ems.connection.local.LocalVirtualMachine; Added: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossCallbackHandler.java =================================================================== --- trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossCallbackHandler.java (rev 0) +++ trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossCallbackHandler.java 2009-07-10 21:35:14 UTC (rev 599) @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2009 Greg Hinkle + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mc4j.ems.impl.jmx.connection.support.providers.jaas; + +import javax.security.auth.callback.*; +import java.io.IOException; + +/** + * @author Ian Springer + */ +public class JBossCallbackHandler implements CallbackHandler { + private String username; + private char[] password; + + public JBossCallbackHandler(String username, String password) + { + this.username = username; + this.password = password.toCharArray(); + } + + public void handle(Callback[] callbacks) throws + IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) { + Callback callback = callbacks[i]; + //System.out.println("Handling Callback [" + callback + "]..."); + if (callback instanceof NameCallback) { + + NameCallback nameCallback = (NameCallback) callback; + nameCallback.setName(this.username); + } else if (callback instanceof PasswordCallback) { + PasswordCallback passwordCallback = (PasswordCallback) callback; + passwordCallback.setPassword(this.password); + } else { + throw new UnsupportedCallbackException(callback, "Unrecognized Callback: " + callback); + } + } + } +} Property changes on: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossCallbackHandler.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Date Author Id Revision HeadURL Added: svn:eol-style + LF Added: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossConfiguration.java =================================================================== --- trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossConfiguration.java (rev 0) +++ trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossConfiguration.java 2009-07-10 21:35:14 UTC (rev 599) @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2009 Greg Hinkle + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mc4j.ems.impl.jmx.connection.support.providers.jaas; + +import javax.security.auth.login.Configuration; +import javax.security.auth.login.AppConfigurationEntry; +import java.util.HashMap; +import java.util.Map; + +/** + * A JAAS configuration for a JBoss client. This is the programmatic equivalent of the following auth.conf file: + * + * <code> + * jboss + * { + * org.jboss.security.ClientLoginModule required + * multi-threaded=true; + * }; + * </code> + * + * @author Ian Springer + */ +public class JBossConfiguration extends Configuration { + public static final String JBOSS_ENTRY_NAME = "jboss"; + + private static final String JBOSS_LOGIN_MODULE_CLASS_NAME = "org.jboss.security.ClientLoginModule"; + private static final String MULTI_THREADED_OPTION = "multi-threaded"; + + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + if (JBOSS_ENTRY_NAME.equals(name)) { + Map options = new HashMap(1); + options.put(MULTI_THREADED_OPTION, Boolean.TRUE.toString()); + AppConfigurationEntry appConfigurationEntry = + new AppConfigurationEntry(JBOSS_LOGIN_MODULE_CLASS_NAME, + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options); + return new AppConfigurationEntry[] {appConfigurationEntry}; + } else { + throw new IllegalArgumentException("Unknown entry name: " + name); + } + } + + public void refresh() { + return; + } +} Property changes on: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/jaas/JBossConfiguration.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Date Author Id Revision HeadURL Added: svn:eol-style + LF Modified: trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/proxy/GenericMBeanServerProxy.java =================================================================== --- trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/proxy/GenericMBeanServerProxy.java 2009-06-15 19:54:11 UTC (rev 598) +++ trunk/mc4j/modules/ems/src/ems-impl/org/mc4j/ems/impl/jmx/connection/support/providers/proxy/GenericMBeanServerProxy.java 2009-07-10 21:35:14 UTC (rev 599) @@ -1,5 +1,5 @@ /* - * Copyright 2002-2004 Greg Hinkle + * Copyright 2002-2009 Greg Hinkle * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.mc4j.ems.impl.jmx.connection.support.providers.proxy; import org.apache.commons.logging.Log; @@ -25,19 +24,17 @@ import org.mc4j.ems.impl.jmx.connection.support.providers.JBossConnectionProvider; import javax.management.MBeanServer; -import javax.naming.Context; import java.io.NotSerializableException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.NoSuchObjectException; -import java.security.Principal; - /** * * @author Greg Hinkle (gh...@us...), January 2002 + * @author Ian Springer * @version $Revision$($Author$ / $Date$) */ public class GenericMBeanServerProxy implements InvocationHandler, StatsProxy { @@ -76,7 +73,6 @@ this.remoteServer = remoteServer; } - public Object invoke( Object proxy, Method m, Object[] args) throws Throwable { @@ -85,12 +81,10 @@ // // ConnectionInfoAction.addHit(); - Class serverClass = this.remoteServer.getClass(); //org.openide.windows.IOProvider.getDefault().getStdOut().println("Looking at object: " + serverClass.getName()); - - // TODO GH: This is horribly inneficient + // TODO GH: This is horribly inefficient Method[] ms = serverClass.getMethods(); Method queryMethod = null; for (int i = 0; i < ms.length; i++) { @@ -99,7 +93,7 @@ if (ms[i].getName().equals("queryMBeans")) queryMethod = ms[i]; } - Method method = null; + Method method; if ("queryMBeans".equals(m.getName())) { method = queryMethod; //method = serverClass.getMethod(m.getName(), new Class[] { ObjectName.class, QueryExp.class }); @@ -115,13 +109,26 @@ try { roundTrips++; // Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); - if (this.provider instanceof JBossConnectionProvider) { + boolean isJBossConnection = (this.provider instanceof JBossConnectionProvider); + if (isJBossConnection) { JBossConnectionProvider jbossProvider = (JBossConnectionProvider) this.provider; // See https://jira.jboss.org/jira/browse/JOPR-9 for an explanation of why we have to re-set the // PrincipalInfo prior to every JBoss JMX call. - jbossProvider.resetPrincipalInfo(); + //jbossProvider.resetPrincipalInfo(); + // Login via JAAS before making the call... + jbossProvider.login(); } - return method.invoke(this.remoteServer, args); + Object returnValue; + try { + returnValue = method.invoke(this.remoteServer, args); + } finally { + if (isJBossConnection) { + JBossConnectionProvider jbossProvider = (JBossConnectionProvider) this.provider; + // Logout via JAAS before returning... + jbossProvider.logout(); + } + } + return returnValue; } catch(InvocationTargetException e) { failures++; if (e.getCause() != null) { @@ -164,7 +171,6 @@ } } - public long getRoundTrips() { return roundTrips; } @@ -185,6 +191,4 @@ throw new LoadException("Unable to find JMX Classes", e); } } - - } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |