Author: remm Date: Thu Jan 16 22:07:28 2014 New Revision: 1558930 URL: http://svn.apache.org/r1558930 Log: - Add dedicated listener for framework and EE integration. - Fix context classloader with SSO session expiration.
Added: tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java Modified: tomcat/trunk/java/org/apache/catalina/Context.java tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java tomcat/trunk/java/org/apache/catalina/core/StandardContext.java tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/Context.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/Context.java (original) +++ tomcat/trunk/java/org/apache/catalina/Context.java Thu Jan 16 22:07:28 2014 @@ -1069,6 +1069,18 @@ public interface Context extends Contain /** + * Get the associated ThreadBindingListener. + */ + public ThreadBindingListener getThreadBindingListener(); + + + /** + * Get the associated ThreadBindingListener. + */ + public void setThreadBindingListener(ThreadBindingListener threadBindingListener); + + + /** * Return the set of watched resources for this Context. If none are * defined, a zero length array will be returned. */ Added: tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java?rev=1558930&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java (added) +++ tomcat/trunk/java/org/apache/catalina/ThreadBindingListener.java Thu Jan 16 22:07:28 2014 @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.catalina; + + +/** + * Callback for establishing naming association when entering the application + * scope. This corresponds to setting the context classloader. + */ +public interface ThreadBindingListener { + + public void bind(); + public void unbind(); + +} Modified: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java (original) +++ tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java Thu Jan 16 22:07:28 2014 @@ -20,17 +20,23 @@ package org.apache.catalina.authenticato import java.io.IOException; +import java.security.AccessController; import java.security.Principal; +import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.Cookie; +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.SessionEvent; import org.apache.catalina.SessionListener; +import org.apache.catalina.ThreadBindingListener; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ValveBase; @@ -415,7 +421,15 @@ public class SingleSignOn extends ValveB reverse.remove(sessions[i]); } // Invalidate this session - sessions[i].expire(); + ClassLoader oldContextClassLoader = null; + try { + oldContextClassLoader = bindThread(sessions[i]); + sessions[i].expire(); + } finally { + if (oldContextClassLoader != null) { + unbindThread(sessions[i], oldContextClassLoader); + } + } } // NOTE: Clients may still possess the old single sign on cookie, @@ -424,6 +438,94 @@ public class SingleSignOn extends ValveB } + protected ClassLoader bindThread(Session session) { + + Manager manager = session.getManager(); + Context context = null; + ClassLoader contextClassLoader = null; + ThreadBindingListener threadBindingListener = null; + if (manager != null) { + context = manager.getContext(); + } + if (context != null) { + if (context.getLoader() != null && context.getLoader().getClassLoader() != null) { + contextClassLoader = context.getLoader().getClassLoader(); + } + threadBindingListener = context.getThreadBindingListener(); + } + if (threadBindingListener == null || contextClassLoader == null) { + return null; + } + + if (Globals.IS_SECURITY_ENABLED) { + return AccessController.doPrivileged(new PrivilegedBind(contextClassLoader, threadBindingListener)); + } else { + ClassLoader oldContextClassLoader = + Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(contextClassLoader); + threadBindingListener.bind(); + return oldContextClassLoader; + } + + } + + protected class PrivilegedBind implements PrivilegedAction<ClassLoader> { + private ClassLoader contextClassLoader; + private ThreadBindingListener threadBindingListener; + + PrivilegedBind(ClassLoader contextClassLoader, ThreadBindingListener threadBindingListener) { + this.contextClassLoader = contextClassLoader; + this.threadBindingListener = threadBindingListener; + } + + public ClassLoader run() { + ClassLoader oldContextClassLoader = + Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(contextClassLoader); + threadBindingListener.bind(); + return oldContextClassLoader; + } + } + + protected void unbindThread(Session session, ClassLoader oldContextClassLoader) { + + Manager manager = session.getManager(); + Context context = null; + ThreadBindingListener threadBindingListener = null; + if (manager != null) { + context = manager.getContext(); + } + if (context != null) { + threadBindingListener = context.getThreadBindingListener(); + } + if (threadBindingListener == null) { + return; + } + + if (Globals.IS_SECURITY_ENABLED) { + AccessController.doPrivileged(new PrivilegedUnbind(oldContextClassLoader, threadBindingListener)); + } else { + threadBindingListener.unbind(); + Thread.currentThread().setContextClassLoader(oldContextClassLoader); + } + + } + + protected class PrivilegedUnbind implements PrivilegedAction<Void> { + private ClassLoader oldContextClassLoader; + private ThreadBindingListener threadBindingListener; + + PrivilegedUnbind(ClassLoader oldContextClassLoader, ThreadBindingListener threadBindingListener) { + this.oldContextClassLoader = oldContextClassLoader; + this.threadBindingListener = threadBindingListener; + } + + public Void run() { + threadBindingListener.unbind(); + Thread.currentThread().setContextClassLoader(oldContextClassLoader); + return null; + } + } /** * Attempts reauthentication to the given <code>Realm</code> using Modified: tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java Thu Jan 16 22:07:28 2014 @@ -670,6 +670,7 @@ final class ApplicationDispatcher implem if (oldCCL != contextClassLoader) { Thread.currentThread().setContextClassLoader(contextClassLoader); + context.getThreadBindingListener().bind(); } else { oldCCL = null; } @@ -795,8 +796,10 @@ final class ApplicationDispatcher implem } // Reset the old context class loader - if (oldCCL != null) + if (oldCCL != null) { + context.getThreadBindingListener().unbind(); Thread.currentThread().setContextClassLoader(oldCCL); + } // Unwrap request/response if needed // See Bugzilla 30949 Modified: tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java Thu Jan 16 22:07:28 2014 @@ -55,6 +55,7 @@ import org.apache.catalina.LifecycleStat import org.apache.catalina.Loader; import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; +import org.apache.catalina.ThreadBindingListener; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Request; @@ -1354,6 +1355,10 @@ public abstract class ContainerBase exte Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader( loader.getClassLoader()); + ThreadBindingListener tbl = ((Context) container).getThreadBindingListener(); + if (tbl != null) { + tbl.bind(); + } } container.backgroundProcess(); Container[] children = container.findChildren(); @@ -1367,9 +1372,15 @@ public abstract class ContainerBase exte log.error("Exception invoking periodic operation: ", t); } finally { if (originalClassLoader != null) { + if (container instanceof Context) { + ThreadBindingListener tbl = ((Context) container).getThreadBindingListener(); + if (tbl != null) { + tbl.unbind(); + } + } Thread.currentThread().setContextClassLoader( originalClassLoader); - } + } } } } Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Thu Jan 16 22:07:28 2014 @@ -92,6 +92,7 @@ import org.apache.catalina.Loader; import org.apache.catalina.Manager; import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; +import org.apache.catalina.ThreadBindingListener; import org.apache.catalina.Valve; import org.apache.catalina.WebResource; import org.apache.catalina.WebResourceRoot; @@ -807,6 +808,11 @@ public class StandardContext extends Con private String containerSciFilter; + protected static final ThreadBindingListener DEFAULT_NAMING_LISTENER = (new ThreadBindingListener() { + public void bind() {} + public void unbind() {} + }); + protected ThreadBindingListener threadBindingListener = DEFAULT_NAMING_LISTENER; // ----------------------------------------------------- Context Properties @@ -2386,6 +2392,17 @@ public class StandardContext extends Con this.jspConfigDescriptor = descriptor; } + @Override + public ThreadBindingListener getThreadBindingListener() { + return threadBindingListener; + } + + @Override + public void setThreadBindingListener(ThreadBindingListener threadBindingListener) { + this.threadBindingListener = threadBindingListener; + } + + // ------------------------------------------------------ Public Properties /** @@ -5712,6 +5729,9 @@ public class StandardContext extends Con Thread.currentThread().setContextClassLoader (getLoader().getClassLoader()); } + if (getThreadBindingListener() != null) { + getThreadBindingListener().bind(); + } if (isUseNaming()) { try { @@ -5735,6 +5755,9 @@ public class StandardContext extends Con ContextBindings.unbindThread(this, this); } + if (getThreadBindingListener() != null) { + getThreadBindingListener().unbind(); + } Thread.currentThread().setContextClassLoader(oldContextClassLoader); } Modified: tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java Thu Jan 16 22:07:28 2014 @@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletRes import org.apache.catalina.Context; import org.apache.catalina.Globals; +import org.apache.catalina.ThreadBindingListener; import org.apache.catalina.Wrapper; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.connector.ClientAbortException; @@ -130,11 +131,14 @@ final class StandardHostValve extends Va // This should eventually move to Engine, it's generic. if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction<Void> pa = new PrivilegedSetTccl( - context.getLoader().getClassLoader()); + context.getLoader().getClassLoader(), + context.getThreadBindingListener(), + true); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); + context.getThreadBindingListener().bind(); } } if (request.isAsyncSupported()) { @@ -201,9 +205,11 @@ final class StandardHostValve extends Va // Restore the context classloader if (Globals.IS_SECURITY_ENABLED) { - PrivilegedAction<Void> pa = new PrivilegedSetTccl(MY_CLASSLOADER); + PrivilegedAction<Void> pa = new PrivilegedSetTccl(MY_CLASSLOADER, + context.getThreadBindingListener(), false); AccessController.doPrivileged(pa); } else { + context.getThreadBindingListener().unbind(); Thread.currentThread().setContextClassLoader(MY_CLASSLOADER); } } @@ -232,6 +238,7 @@ final class StandardHostValve extends Va // This should eventually move to Engine, it's generic. Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); + context.getThreadBindingListener().bind(); } // Ask this Context to process this request @@ -257,6 +264,7 @@ final class StandardHostValve extends Va } // Restore the context classloader + context.getThreadBindingListener().unbind(); Thread.currentThread().setContextClassLoader (StandardHostValve.class.getClassLoader()); @@ -508,14 +516,23 @@ final class StandardHostValve extends Va private static class PrivilegedSetTccl implements PrivilegedAction<Void> { private final ClassLoader cl; + private final ThreadBindingListener tbl; + private final boolean bind; - PrivilegedSetTccl(ClassLoader cl) { + PrivilegedSetTccl(ClassLoader cl, ThreadBindingListener tbl, boolean bind) { this.cl = cl; + this.bind = bind; + this.tbl = tbl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); + if (bind) { + tbl.bind(); + } else { + tbl.unbind(); + } return null; } } Modified: tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java (original) +++ tomcat/trunk/java/org/apache/catalina/security/SecurityClassLoad.java Thu Jan 16 22:07:28 2014 @@ -42,6 +42,7 @@ public final class SecurityClassLoad { return; } + loadAuthenticatorPackage(loader); loadCorePackage(loader); loadCoyotePackage(loader); loadLoaderPackage(loader); @@ -55,6 +56,18 @@ public final class SecurityClassLoad { } + private static final void loadAuthenticatorPackage(ClassLoader loader) + throws Exception { + final String basePackage = "org.apache.catalina.authenticator."; + loader.loadClass + (basePackage + + "SingleSignOn$PrivilegedBind"); + loader.loadClass + (basePackage + + "SingleSignOn$PrivilegedUnbind"); + } + + private static final void loadCorePackage(ClassLoader loader) throws Exception { final String basePackage = "org.apache.catalina.core."; Modified: tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java Thu Jan 16 22:07:28 2014 @@ -43,6 +43,7 @@ import org.apache.catalina.Loader; import org.apache.catalina.Manager; import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; +import org.apache.catalina.ThreadBindingListener; import org.apache.catalina.Valve; import org.apache.catalina.WebResourceRoot; import org.apache.catalina.Wrapper; @@ -730,4 +731,11 @@ public class FailedContext extends Lifec @Override public String getContainerSciFilter() { return null; } + + @Override + public ThreadBindingListener getThreadBindingListener() { return null; } + + @Override + public void setThreadBindingListener(ThreadBindingListener threadBindingListener) { /* NO-OP */ } + } \ No newline at end of file Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1558930&r1=1558929&r2=1558930&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Thu Jan 16 22:07:28 2014 @@ -196,6 +196,9 @@ grouped more logically in JConsole. Generally, components are now grouped by Host and then by Context. (markt) </fix> + <add> + Context listener to allow better EE and framework integration. (remm) + </add> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org