From 6651a240de5a95e32203384d1232659830375775 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Tue, 28 Aug 2007 18:26:04 +0000 Subject: [PATCH] Replaced massive if/else with guard clause to reduce nesting. Moved declaration of filterApplied boolean to where it is actually set. It is only used when removing the attribute from the request at the end of the invocation, so should probably not be needed at all. request.removeAttribute() can be called regardless of whether the attribute is set or not. --- .../HttpSessionContextIntegrationFilter.java | 541 +++++++++--------- 1 file changed, 268 insertions(+), 273 deletions(-) diff --git a/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java b/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java index 4b459227b9..4e489a6cd1 100644 --- a/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java +++ b/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java @@ -36,8 +36,8 @@ import org.springframework.util.ReflectionUtils; /** * Populates the {@link SecurityContextHolder} with information obtained from * the HttpSession. - * - *

+ *

+ *

* The HttpSession will be queried to retrieve the * SecurityContext that should be stored against the * SecurityContextHolder for the duration of the web request. At @@ -45,7 +45,7 @@ import org.springframework.util.ReflectionUtils; * SecurityContextHolder will be persisted back to the * HttpSession by this filter. *

- *

+ *

* If a valid SecurityContext cannot be obtained from the * HttpSession for whatever reason, a fresh * SecurityContext will be created and used instead. The created @@ -53,7 +53,7 @@ import org.springframework.util.ReflectionUtils; * method (which defaults to {@link * org.acegisecurity.context.SecurityContextImpl}. *

- *

+ *

* No HttpSession will be created by this filter if one does not * already exist. If at the end of the web request the HttpSession * does not exist, a HttpSession will only be created if @@ -67,11 +67,11 @@ import org.springframework.util.ReflectionUtils; * irrespective of normal session-minimisation logic (the default is * false, as this is resource intensive and not recommended). *

- *

+ *

* This filter will only execute once per request, to resolve servlet container * (specifically Weblogic) incompatibilities. *

- *

+ *

* If for whatever reason no HttpSession should ever be * created (eg this filter is only being used with Basic authentication or * similar clients that will never present the same jsessionid @@ -84,7 +84,7 @@ import org.springframework.util.ReflectionUtils; * true (setting it to false will cause a startup * time error). *

- *

+ *

* This filter MUST be executed BEFORE any authentication processing mechanisms. * Authentication processing mechanisms (eg BASIC, CAS processing filters etc) * expect the SecurityContextHolder to contain a valid @@ -94,317 +94,312 @@ import org.springframework.util.ReflectionUtils; * @author Ben Alex * @author Patrick Burleson * @version $Id: HttpSessionContextIntegrationFilter.java 1784 2007-02-24 - * 21:00:24Z luke_t $ + * 21:00:24Z luke_t $ */ public class HttpSessionContextIntegrationFilter implements InitializingBean, Filter { - // ~ Static fields/initializers - // ===================================================================================== + // ~ Static fields/initializers + // ===================================================================================== - protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class); + protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class); - static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied"; + static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied"; - public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT"; + public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT"; - // ~ Instance fields - // ================================================================================================ + // ~ Instance fields + // ================================================================================================ - private Class context = SecurityContextImpl.class; + private Class context = SecurityContextImpl.class; - private Object contextObject; + private Object contextObject; - /** - * Indicates if this filter can create a HttpSession if - * needed (sessions are always created sparingly, but setting this value to - * false will prohibit sessions from ever being created). - * Defaults to true. Do not set to false if - * you are have set {@link #forceEagerSessionCreation} to true, - * as the properties would be in conflict. - */ - private boolean allowSessionCreation = true; + /** + * Indicates if this filter can create a HttpSession if + * needed (sessions are always created sparingly, but setting this value to + * false will prohibit sessions from ever being created). + * Defaults to true. Do not set to false if + * you are have set {@link #forceEagerSessionCreation} to true, + * as the properties would be in conflict. + */ + private boolean allowSessionCreation = true; - /** - * Indicates if this filter is required to create a HttpSession - * for every request before proceeding through the filter chain, even if the - * HttpSession would not ordinarily have been created. By - * default this is false, which is entirely appropriate for - * most circumstances as you do not want a HttpSession - * created unless the filter actually needs one. It is envisaged the main - * situation in which this property would be set to true is - * if using other filters that depend on a HttpSession - * already existing, such as those which need to obtain a session ID. This - * is only required in specialised cases, so leave it set to - * false unless you have an actual requirement and are - * conscious of the session creation overhead. - */ - private boolean forceEagerSessionCreation = false; + /** + * Indicates if this filter is required to create a HttpSession + * for every request before proceeding through the filter chain, even if the + * HttpSession would not ordinarily have been created. By + * default this is false, which is entirely appropriate for + * most circumstances as you do not want a HttpSession + * created unless the filter actually needs one. It is envisaged the main + * situation in which this property would be set to true is + * if using other filters that depend on a HttpSession + * already existing, such as those which need to obtain a session ID. This + * is only required in specialised cases, so leave it set to + * false unless you have an actual requirement and are + * conscious of the session creation overhead. + */ + private boolean forceEagerSessionCreation = false; - /** - * Indicates whether the 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; + /** + * Indicates whether the 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 boolean isCloneFromHttpSession() { + return cloneFromHttpSession; + } - public void setCloneFromHttpSession(boolean cloneFromHttpSession) { - this.cloneFromHttpSession = cloneFromHttpSession; - } + public void setCloneFromHttpSession(boolean cloneFromHttpSession) { + this.cloneFromHttpSession = cloneFromHttpSession; + } - public HttpSessionContextIntegrationFilter() throws ServletException { - this.contextObject = generateNewContext(); - } + public HttpSessionContextIntegrationFilter() throws ServletException { + this.contextObject = generateNewContext(); + } - // ~ Methods - // ======================================================================================================== + // ~ Methods + // ======================================================================================================== - public void afterPropertiesSet() throws Exception { - if ((this.context == null) || (!SecurityContext.class.isAssignableFrom(this.context))) { - throw new IllegalArgumentException("context must be defined and implement SecurityContext " - + "(typically use org.acegisecurity.context.SecurityContextImpl; existing class is " + this.context - + ")"); - } + public void afterPropertiesSet() throws Exception { + if ((this.context == null) || (!SecurityContext.class.isAssignableFrom(this.context))) { + throw new IllegalArgumentException("context must be defined and implement SecurityContext " + + "(typically use org.acegisecurity.context.SecurityContextImpl; existing class is " + this.context + + ")"); + } - if ((forceEagerSessionCreation == true) && (allowSessionCreation == false)) { - throw new IllegalArgumentException( - "If using forceEagerSessionCreation, you must set allowSessionCreation to also be true"); - } - } + if ((forceEagerSessionCreation == true) && (allowSessionCreation == false)) { + throw new IllegalArgumentException( + "If using forceEagerSessionCreation, you must set allowSessionCreation to also be true"); + } + } - /** - * Does nothing. We use IoC container lifecycle services instead. - */ - public void destroy() { - } + /** + * Does nothing. We use IoC container lifecycle services instead. + */ + public void destroy() { + } - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, - ServletException { - boolean filterApplied = false; - if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) { - // ensure that filter is only applied once per request - chain.doFilter(request, response); - } - else { - HttpSession httpSession = null; - boolean httpSessionExistedAtStartOfRequest = false; + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException { + if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) { + // ensure that filter is only applied once per request + chain.doFilter(request, response); - try { - httpSession = ((HttpServletRequest) request).getSession(forceEagerSessionCreation); - } - catch (IllegalStateException ignored) { - } + return; + } - if (httpSession != null) { - httpSessionExistedAtStartOfRequest = true; + HttpSession httpSession = null; + boolean httpSessionExistedAtStartOfRequest = false; - Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY); + try { + httpSession = ((HttpServletRequest) request).getSession(forceEagerSessionCreation); + } + catch (IllegalStateException ignored) { + } - if (contextFromSessionObject != null) { - // 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 (httpSession != null) { + httpSessionExistedAtStartOfRequest = true; - if (contextFromSessionObject instanceof SecurityContext) { - if (logger.isDebugEnabled()) { - logger.debug("Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and " - + "set to SecurityContextHolder: '" + contextFromSessionObject + "'"); - } + Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY); - SecurityContextHolder.setContext((SecurityContext) contextFromSessionObject); - } - else { - if (logger.isWarnEnabled()) { - logger - .warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '" - + contextFromSessionObject - + "'; are you improperly modifying the HttpSession directly " - + "(you should always use SecurityContextHolder) or using the HttpSession attribute " - + "reserved for this class? - new SecurityContext instance associated with " - + "SecurityContextHolder"); - } + if (contextFromSessionObject != null) { + // 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); + } + } - SecurityContextHolder.setContext(generateNewContext()); - } - } - else { - if (logger.isDebugEnabled()) { - logger.debug("HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new " - + "SecurityContext instance associated with SecurityContextHolder"); - } + if (contextFromSessionObject instanceof SecurityContext) { + if (logger.isDebugEnabled()) { + logger.debug("Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and " + + "set to SecurityContextHolder: '" + contextFromSessionObject + "'"); + } - SecurityContextHolder.setContext(generateNewContext()); - } - } - else { - if (logger.isDebugEnabled()) { - logger.debug("No HttpSession currently exists - new SecurityContext instance " - + "associated with SecurityContextHolder"); - } + SecurityContextHolder.setContext((SecurityContext) contextFromSessionObject); + } else { + if (logger.isWarnEnabled()) { + logger + .warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '" + + contextFromSessionObject + + "'; are you improperly modifying the HttpSession directly " + + "(you should always use SecurityContextHolder) or using the HttpSession attribute " + + "reserved for this class? - new SecurityContext instance associated with " + + "SecurityContextHolder"); + } - SecurityContextHolder.setContext(generateNewContext()); - } + SecurityContextHolder.setContext(generateNewContext()); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new " + + "SecurityContext instance associated with SecurityContextHolder"); + } - // Make the HttpSession null, as we want to ensure we don't keep - // a reference to the HttpSession laying around in case the - // chain.doFilter() invalidates it. - httpSession = null; - - // Proceed with chain - int contextWhenChainProceeded = SecurityContextHolder.getContext().hashCode(); - - try { - filterApplied = true; - request.setAttribute(FILTER_APPLIED, Boolean.TRUE); - chain.doFilter(request, response); - } catch (IOException ioe) { - throw ioe; - } catch (ServletException se) { - throw se; + SecurityContextHolder.setContext(generateNewContext()); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("No HttpSession currently exists - new SecurityContext instance " + + "associated with SecurityContextHolder"); } - finally { - // do clean up, even if there was an exception - // Store context back to HttpSession - try { - httpSession = ((HttpServletRequest) request).getSession(false); - } - catch (IllegalStateException ignored) { - } - if ((httpSession == null) && httpSessionExistedAtStartOfRequest) { - if (logger.isDebugEnabled()) { - logger.debug("HttpSession is now null, but was not null at start of request; " - + "session was invalidated, so do not create a new session"); - } - } + SecurityContextHolder.setContext(generateNewContext()); + } - // Generate a HttpSession only if we need to - if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) { - if (!allowSessionCreation) { - if (logger.isDebugEnabled()) { - logger - .debug("The HttpSession is currently null, and the " - + "HttpSessionContextIntegrationFilter is prohibited from creating an HttpSession " - + "(because the allowSessionCreation property is false) - SecurityContext thus not " - + "stored for next request"); - } - } - else if (!contextObject.equals(SecurityContextHolder.getContext())) { - if (logger.isDebugEnabled()) { - logger.debug("HttpSession being created as SecurityContextHolder contents are non-default"); - } + // Make the HttpSession null, as we want to ensure we don't keep + // a reference to the HttpSession laying around in case the + // chain.doFilter() invalidates it. + httpSession = null; - try { - httpSession = ((HttpServletRequest) request).getSession(true); - } - catch (IllegalStateException ignored) { - } - } - else { - if (logger.isDebugEnabled()) { - logger - .debug("HttpSession is null, but SecurityContextHolder has not changed from default: ' " - + SecurityContextHolder.getContext() - + "'; not creating HttpSession or storing SecurityContextHolder contents"); - } - } - } + // Proceed with chain + int contextWhenChainProceeded = SecurityContextHolder.getContext().hashCode(); + boolean filterApplied = true; - // If HttpSession exists, store current - // SecurityContextHolder contents but only if - // SecurityContext has - // actually changed (see JIRA SEC-37) - if ((httpSession != null) - && (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) { - httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); + request.setAttribute(FILTER_APPLIED, Boolean.TRUE); - if (logger.isDebugEnabled()) { - logger.debug("SecurityContext stored to HttpSession: '" + SecurityContextHolder.getContext() - + "'"); - } - } + try { + chain.doFilter(request, response); + } catch (IOException ioe) { + throw ioe; + } catch (ServletException se) { + throw se; + } + finally { + // do clean up, even if there was an exception + // Store context back to HttpSession + try { + httpSession = ((HttpServletRequest) request).getSession(false); + } + catch (IllegalStateException ignored) { + } - if (filterApplied) { - request.removeAttribute(FILTER_APPLIED); - } + if ((httpSession == null) && httpSessionExistedAtStartOfRequest) { + if (logger.isDebugEnabled()) { + logger.debug("HttpSession is now null, but was not null at start of request; " + + "session was invalidated, so do not create a new session"); + } + } - // Remove SecurityContextHolder contents - SecurityContextHolder.clearContext(); + // Generate a HttpSession only if we need to + if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) { + if (!allowSessionCreation) { + if (logger.isDebugEnabled()) { + logger + .debug("The HttpSession is currently null, and the " + + "HttpSessionContextIntegrationFilter is prohibited from creating an HttpSession " + + "(because the allowSessionCreation property is false) - SecurityContext thus not " + + "stored for next request"); + } + } else if (!contextObject.equals(SecurityContextHolder.getContext())) { + if (logger.isDebugEnabled()) { + logger.debug("HttpSession being created as SecurityContextHolder contents are non-default"); + } - if (logger.isDebugEnabled()) { - logger.debug("SecurityContextHolder set to new context, as request processing completed"); - } - } - } - } + try { + httpSession = ((HttpServletRequest) request).getSession(true); + } + catch (IllegalStateException ignored) { + } + } else { + if (logger.isDebugEnabled()) { + logger + .debug("HttpSession is null, but SecurityContextHolder has not changed from default: ' " + + SecurityContextHolder.getContext() + + "'; not creating HttpSession or storing SecurityContextHolder contents"); + } + } + } - public SecurityContext generateNewContext() throws ServletException { - try { - return (SecurityContext) this.context.newInstance(); - } - catch (InstantiationException ie) { - throw new ServletException(ie); - } - catch (IllegalAccessException iae) { - throw new ServletException(iae); - } - } + // If HttpSession exists, store current + // SecurityContextHolder contents but only if + // SecurityContext has + // actually changed (see JIRA SEC-37) + if ((httpSession != null) + && (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) { + httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); - public Class getContext() { - return context; - } + if (logger.isDebugEnabled()) { + logger.debug("SecurityContext stored to HttpSession: '" + SecurityContextHolder.getContext() + + "'"); + } + } - /** - * Does nothing. We use IoC container lifecycle services instead. - * - * @param filterConfig ignored - * - * @throws ServletException ignored - */ - public void init(FilterConfig filterConfig) throws ServletException { - } + if (filterApplied) { + request.removeAttribute(FILTER_APPLIED); + } - public boolean isAllowSessionCreation() { - return allowSessionCreation; - } + // Remove SecurityContextHolder contents + SecurityContextHolder.clearContext(); - public boolean isForceEagerSessionCreation() { - return forceEagerSessionCreation; - } + if (logger.isDebugEnabled()) { + logger.debug("SecurityContextHolder set to new context, as request processing completed"); + } + } + } - public void setAllowSessionCreation(boolean allowSessionCreation) { - this.allowSessionCreation = allowSessionCreation; - } + public SecurityContext generateNewContext() throws ServletException { + try { + return (SecurityContext) this.context.newInstance(); + } + catch (InstantiationException ie) { + throw new ServletException(ie); + } + catch (IllegalAccessException iae) { + throw new ServletException(iae); + } + } - public void setContext(Class secureContext) { - this.context = secureContext; - } + public Class getContext() { + return context; + } - public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) { - this.forceEagerSessionCreation = forceEagerSessionCreation; + /** + * Does nothing. We use IoC container lifecycle services instead. + * + * @param filterConfig ignored + * @throws ServletException ignored + */ + public void init(FilterConfig filterConfig) throws ServletException { + } + + public boolean isAllowSessionCreation() { + return allowSessionCreation; + } + + public boolean isForceEagerSessionCreation() { + return forceEagerSessionCreation; + } + + public void setAllowSessionCreation(boolean allowSessionCreation) { + this.allowSessionCreation = allowSessionCreation; + } + + public void setContext(Class secureContext) { + this.context = secureContext; + } + + public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) { + this.forceEagerSessionCreation = forceEagerSessionCreation; } }