SEC-247: Allow #NONE# to be used to specify paths that shouldn't have any filters fire.

This commit is contained in:
Ben Alex 2006-04-26 03:55:39 +00:00
parent 185d63f23c
commit 4e09777dec
3 changed files with 91 additions and 56 deletions

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@ package org.acegisecurity.util;
import org.acegisecurity.ConfigAttribute; import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition; import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.intercept.web.FilterInvocation; import org.acegisecurity.intercept.web.FilterInvocation;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource; import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
@ -28,6 +29,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import java.io.IOException; import java.io.IOException;
@ -90,16 +92,20 @@ import javax.servlet.ServletResponse;
* <p> * <p>
* It is particularly noted the <code>Filter</code> lifecycle mismatch between * It is particularly noted the <code>Filter</code> lifecycle mismatch between
* the servlet container and IoC container. As per {@link * the servlet container and IoC container. As per {@link
* org.acegisecurity.util.FilterToBeanProxy} JavaDocs, we recommend you * org.acegisecurity.util.FilterToBeanProxy} JavaDocs, we recommend you allow
* allow the IoC container to manage lifecycle instead of the servlet * the IoC container to manage lifecycle instead of the servlet container. By
* container. By default the <code>FilterToBeanProxy</code> will never call * default the <code>FilterToBeanProxy</code> will never call this class'
* this class' {@link #init(FilterConfig)} and {@link #destroy()} methods, * {@link #init(FilterConfig)} and {@link #destroy()} methods, meaning each of
* meaning each of the filters defined against * the filters defined against <code>FilterInvocationDefinitionSource</code>
* <code>FilterInvocationDefinitionSource</code> will not be called. If you do * will not be called. If you do need your filters to be initialized and
* need your filters to be initialized and destroyed, please set the * destroyed, please set the <code>lifecycle</code> initialization parameter
* <code>lifecycle</code> initialization parameter against the * against the <code>FilterToBeanProxy</code> to specify servlet container
* <code>FilterToBeanProxy</code> to specify servlet container lifecycle * lifecycle management.
* management. * </p>
*
* <p>
* If a filter name of {@link #TOKEN_NONE} is used, this allows specification
* of a filter pattern which should never cause any filters to fire.
* </p> * </p>
* *
* @author Carlos Sanchez * @author Carlos Sanchez
@ -111,6 +117,7 @@ public class FilterChainProxy implements Filter, InitializingBean,
//~ Static fields/initializers ============================================= //~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(FilterChainProxy.class); private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
public static final String TOKEN_NONE = "#NONE#";
//~ Instance fields ======================================================== //~ Instance fields ========================================================
@ -119,29 +126,19 @@ public class FilterChainProxy implements Filter, InitializingBean,
//~ Methods ================================================================ //~ Methods ================================================================
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public void setFilterInvocationDefinitionSource(
FilterInvocationDefinitionSource filterInvocationDefinitionSource) {
this.filterInvocationDefinitionSource = filterInvocationDefinitionSource;
}
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
return filterInvocationDefinitionSource;
}
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
Assert.notNull(filterInvocationDefinitionSource, "filterInvocationDefinitionSource must be specified"); Assert.notNull(filterInvocationDefinitionSource,
Assert.notNull(this.filterInvocationDefinitionSource.getConfigAttributeDefinitions(), "FilterChainProxy requires the FilterInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()"); "filterInvocationDefinitionSource must be specified");
Assert.notNull(this.filterInvocationDefinitionSource
.getConfigAttributeDefinitions(),
"FilterChainProxy requires the FilterInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()");
} }
public void destroy() { public void destroy() {
Filter[] filters = obtainAllDefinedFilters(); Filter[] filters = obtainAllDefinedFilters();
for (int i = 0; i < filters.length; i++) { for (int i = 0; i < filters.length; i++) {
if (filters[i] != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug( logger.debug(
"Destroying Filter defined in ApplicationContext: '" "Destroying Filter defined in ApplicationContext: '"
@ -151,6 +148,7 @@ public class FilterChainProxy implements Filter, InitializingBean,
filters[i].destroy(); filters[i].destroy();
} }
} }
}
public void doFilter(ServletRequest request, ServletResponse response, public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException { FilterChain chain) throws IOException, ServletException {
@ -174,10 +172,15 @@ public class FilterChainProxy implements Filter, InitializingBean,
} }
} }
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
return filterInvocationDefinitionSource;
}
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
Filter[] filters = obtainAllDefinedFilters(); Filter[] filters = obtainAllDefinedFilters();
for (int i = 0; i < filters.length; i++) { for (int i = 0; i < filters.length; i++) {
if (filters[i] != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug( logger.debug(
"Initializing Filter defined in ApplicationContext: '" "Initializing Filter defined in ApplicationContext: '"
@ -187,6 +190,7 @@ public class FilterChainProxy implements Filter, InitializingBean,
filters[i].init(filterConfig); filters[i].init(filterConfig);
} }
} }
}
/** /**
* Obtains all of the <b>unique</b><code>Filter</code> instances registered * Obtains all of the <b>unique</b><code>Filter</code> instances registered
@ -231,11 +235,8 @@ public class FilterChainProxy implements Filter, InitializingBean,
* <code>Filter</code>s * <code>Filter</code>s
* *
* @return the <code>Filter</code>s against the specified * @return the <code>Filter</code>s against the specified
* <code>ConfigAttributeDefinition</code> * <code>ConfigAttributeDefinition</code> (never
* * <code>null</code>)
* @throws IllegalArgumentException if a configuration attribute provides a
* <code>null</code> return value from the {@link
* ConfigAttribute#getAttribute()} method
*/ */
private Filter[] obtainAllDefinedFilters( private Filter[] obtainAllDefinedFilters(
ConfigAttributeDefinition configAttributeDefinition) { ConfigAttributeDefinition configAttributeDefinition) {
@ -246,16 +247,29 @@ public class FilterChainProxy implements Filter, InitializingBean,
ConfigAttribute attr = (ConfigAttribute) attributes.next(); ConfigAttribute attr = (ConfigAttribute) attributes.next();
String filterName = attr.getAttribute(); String filterName = attr.getAttribute();
Assert.notNull(filterName, "Configuration attribute: '" Assert.notNull(filterName,
+ attr "Configuration attribute: '" + attr
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy"); + "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
list.add(this.applicationContext.getBean(filterName, Filter.class)); if (!filterName.equals(TOKEN_NONE)) {
list.add(this.applicationContext.getBean(filterName,
Filter.class));
}
} }
return (Filter[]) list.toArray(new Filter[] {null}); return (Filter[]) list.toArray(new Filter[] {null});
} }
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public void setFilterInvocationDefinitionSource(
FilterInvocationDefinitionSource filterInvocationDefinitionSource) {
this.filterInvocationDefinitionSource = filterInvocationDefinitionSource;
}
//~ Inner Classes ========================================================== //~ Inner Classes ==========================================================
/** /**

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,12 +21,14 @@ import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition; import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.MockApplicationContext; import org.acegisecurity.MockApplicationContext;
import org.acegisecurity.MockFilterConfig; import org.acegisecurity.MockFilterConfig;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource; import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.MockFilterInvocationDefinitionSource; import org.acegisecurity.intercept.web.MockFilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap; import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
@ -60,8 +62,7 @@ public class FilterChainProxyTests extends TestCase {
public void testDetectsFilterInvocationDefinitionSourceThatDoesNotReturnAllConfigAttributes() public void testDetectsFilterInvocationDefinitionSourceThatDoesNotReturnAllConfigAttributes()
throws Exception { throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy(); FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext filterChainProxy.setApplicationContext(MockApplicationContext.getContext());
.getContext());
filterChainProxy.setFilterInvocationDefinitionSource(new MockFilterInvocationDefinitionSource( filterChainProxy.setFilterInvocationDefinitionSource(new MockFilterInvocationDefinitionSource(
false, false)); false, false));
@ -77,8 +78,7 @@ public class FilterChainProxyTests extends TestCase {
public void testDetectsIfConfigAttributeDoesNotReturnValueForGetAttributeMethod() public void testDetectsIfConfigAttributeDoesNotReturnValueForGetAttributeMethod()
throws Exception { throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy(); FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext filterChainProxy.setApplicationContext(MockApplicationContext.getContext());
.getContext());
ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); ConfigAttributeDefinition cad = new ConfigAttributeDefinition();
cad.addConfigAttribute(new MockConfigAttribute()); cad.addConfigAttribute(new MockConfigAttribute());
@ -93,15 +93,15 @@ public class FilterChainProxyTests extends TestCase {
filterChainProxy.init(new MockFilterConfig()); filterChainProxy.init(new MockFilterConfig());
fail("Should have thrown IllegalArgumentException"); fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().endsWith("returned null to the getAttribute() method, which is invalid when used with FilterChainProxy")); assertTrue(expected.getMessage()
.endsWith("returned null to the getAttribute() method, which is invalid when used with FilterChainProxy"));
} }
} }
public void testDetectsMissingFilterInvocationDefinitionSource() public void testDetectsMissingFilterInvocationDefinitionSource()
throws Exception { throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy(); FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext filterChainProxy.setApplicationContext(MockApplicationContext.getContext());
.getContext());
try { try {
filterChainProxy.afterPropertiesSet(); filterChainProxy.afterPropertiesSet();
@ -112,6 +112,26 @@ public class FilterChainProxyTests extends TestCase {
} }
} }
public void testDoNotFilter() throws Exception {
ApplicationContext appCtx = new ClassPathXmlApplicationContext(
"org/acegisecurity/util/filtertest-valid.xml");
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain",
FilterChainProxy.class);
MockFilter filter = (MockFilter) appCtx.getBean("mockFilter",
MockFilter.class);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServletPath("/do/not/filter/somefile.html");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain(true);
filterChainProxy.doFilter(request, response, chain);
assertFalse(filter.isWasInitialized());
assertFalse(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
}
public void testGettersSetters() { public void testGettersSetters() {
FilterChainProxy filterChainProxy = new FilterChainProxy(); FilterChainProxy filterChainProxy = new FilterChainProxy();
FilterInvocationDefinitionSource fids = new MockFilterInvocationDefinitionSource(false, FilterInvocationDefinitionSource fids = new MockFilterInvocationDefinitionSource(false,

View File

@ -34,6 +34,7 @@
PATTERN_TYPE_APACHE_ANT PATTERN_TYPE_APACHE_ANT
/foo/**=mockFilter /foo/**=mockFilter
/some/other/path/**=mockFilter /some/other/path/**=mockFilter
/do/not/filter=#NONE#
</value> </value>
</property> </property>
</bean> </bean>