diff --git a/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java b/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java index aa4ac642e5..35c2dae4b7 100644 --- a/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java +++ b/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java @@ -15,12 +15,8 @@ package org.acegisecurity.context; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.InitializingBean; - import java.io.IOException; +import java.lang.reflect.Method; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -31,6 +27,12 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + /** *
Populates the {@link SecurityContextHolder} with information obtained from the HttpSession.
SecurityContext will be cloned from the HttpSession. The
+ * default is to simply reference (ie the default is false). The default may cause issues if
+ * concurrent threads need to have a different security identity from other threads being concurrently processed
+ * that share the same HttpSession. In most normal environments this does not represent an issue,
+ * as changes to the security identity in one thread is allowed to affect the security identitiy in other
+ * threads associated with the same HttpSession. For unusual cases where this is not permitted,
+ * change this value to true and ensure the {@link #context} is set to a SecurityContext
+ * that implements {@link Cloneable} and overrides the clone() method.
+ */
+ private boolean cloneFromHttpSession = false;
+
+ public boolean isCloneFromHttpSession() {
+ return cloneFromHttpSession;
+ }
- public HttpSessionContextIntegrationFilter() throws ServletException {
+ public void setCloneFromHttpSession(boolean cloneFromHttpSession) {
+ this.cloneFromHttpSession = cloneFromHttpSession;
+ }
+
+ public HttpSessionContextIntegrationFilter() throws ServletException {
this.contextObject = generateNewContext();
}
@@ -145,7 +167,21 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
httpSessionExistedAtStartOfRequest = true;
Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
-
+
+ // Clone if required (see SEC-356)
+ if (cloneFromHttpSession) {
+ Assert.isInstanceOf(Cloneable.class, contextFromSessionObject, "Context must implement Clonable and provide a Object.clone() method");
+ try {
+ Method m = contextFromSessionObject.getClass().getMethod("clone", new Class[] {});
+ if (!m.isAccessible()) {
+ m.setAccessible(true);
+ }
+ contextFromSessionObject = m.invoke(contextFromSessionObject, new Object[] {});
+ } catch (Exception ex) {
+ ReflectionUtils.handleReflectionException(ex);
+ }
+ }
+
if (contextFromSessionObject != null) {
if (contextFromSessionObject instanceof SecurityContext) {
if (logger.isDebugEnabled()) {