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");
* 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.ConfigAttributeDefinition;
import org.acegisecurity.intercept.web.FilterInvocation;
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.ApplicationContextAware;
import org.springframework.util.Assert;
import java.io.IOException;
@ -90,16 +92,20 @@ import javax.servlet.ServletResponse;
* <p>
* It is particularly noted the <code>Filter</code> lifecycle mismatch between
* the servlet container and IoC container. As per {@link
* org.acegisecurity.util.FilterToBeanProxy} JavaDocs, we recommend you
* allow the IoC container to manage lifecycle instead of the servlet
* container. By default the <code>FilterToBeanProxy</code> will never call
* this class' {@link #init(FilterConfig)} and {@link #destroy()} methods,
* meaning each of the filters defined against
* <code>FilterInvocationDefinitionSource</code> will not be called. If you do
* need your filters to be initialized and destroyed, please set the
* <code>lifecycle</code> initialization parameter against the
* <code>FilterToBeanProxy</code> to specify servlet container lifecycle
* management.
* org.acegisecurity.util.FilterToBeanProxy} JavaDocs, we recommend you allow
* the IoC container to manage lifecycle instead of the servlet container. By
* default the <code>FilterToBeanProxy</code> will never call this class'
* {@link #init(FilterConfig)} and {@link #destroy()} methods, meaning each of
* the filters defined against <code>FilterInvocationDefinitionSource</code>
* will not be called. If you do need your filters to be initialized and
* destroyed, please set the <code>lifecycle</code> initialization parameter
* against the <code>FilterToBeanProxy</code> to specify servlet container
* lifecycle 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>
*
* @author Carlos Sanchez
@ -111,6 +117,7 @@ public class FilterChainProxy implements Filter, InitializingBean,
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
public static final String TOKEN_NONE = "#NONE#";
//~ Instance fields ========================================================
@ -119,36 +126,27 @@ public class FilterChainProxy implements Filter, InitializingBean,
//~ 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 {
Assert.notNull(filterInvocationDefinitionSource, "filterInvocationDefinitionSource must be specified");
Assert.notNull(this.filterInvocationDefinitionSource.getConfigAttributeDefinitions(), "FilterChainProxy requires the FilterInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()");
Assert.notNull(filterInvocationDefinitionSource,
"filterInvocationDefinitionSource must be specified");
Assert.notNull(this.filterInvocationDefinitionSource
.getConfigAttributeDefinitions(),
"FilterChainProxy requires the FilterInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()");
}
public void destroy() {
Filter[] filters = obtainAllDefinedFilters();
for (int i = 0; i < filters.length; i++) {
if (logger.isDebugEnabled()) {
logger.debug(
"Destroying Filter defined in ApplicationContext: '"
+ filters[i].toString() + "'");
}
if (filters[i] != null) {
if (logger.isDebugEnabled()) {
logger.debug(
"Destroying Filter defined in ApplicationContext: '"
+ filters[i].toString() + "'");
}
filters[i].destroy();
filters[i].destroy();
}
}
}
@ -174,17 +172,23 @@ public class FilterChainProxy implements Filter, InitializingBean,
}
}
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
return filterInvocationDefinitionSource;
}
public void init(FilterConfig filterConfig) throws ServletException {
Filter[] filters = obtainAllDefinedFilters();
for (int i = 0; i < filters.length; i++) {
if (logger.isDebugEnabled()) {
logger.debug(
"Initializing Filter defined in ApplicationContext: '"
+ filters[i].toString() + "'");
}
if (filters[i] != null) {
if (logger.isDebugEnabled()) {
logger.debug(
"Initializing Filter defined in ApplicationContext: '"
+ filters[i].toString() + "'");
}
filters[i].init(filterConfig);
filters[i].init(filterConfig);
}
}
}
@ -231,11 +235,8 @@ public class FilterChainProxy implements Filter, InitializingBean,
* <code>Filter</code>s
*
* @return the <code>Filter</code>s against the specified
* <code>ConfigAttributeDefinition</code>
*
* @throws IllegalArgumentException if a configuration attribute provides a
* <code>null</code> return value from the {@link
* ConfigAttribute#getAttribute()} method
* <code>ConfigAttributeDefinition</code> (never
* <code>null</code>)
*/
private Filter[] obtainAllDefinedFilters(
ConfigAttributeDefinition configAttributeDefinition) {
@ -246,16 +247,29 @@ public class FilterChainProxy implements Filter, InitializingBean,
ConfigAttribute attr = (ConfigAttribute) attributes.next();
String filterName = attr.getAttribute();
Assert.notNull(filterName, "Configuration attribute: '"
+ attr
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
Assert.notNull(filterName,
"Configuration attribute: '" + attr
+ "' 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});
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public void setFilterInvocationDefinitionSource(
FilterInvocationDefinitionSource filterInvocationDefinitionSource) {
this.filterInvocationDefinitionSource = filterInvocationDefinitionSource;
}
//~ 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");
* 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.MockApplicationContext;
import org.acegisecurity.MockFilterConfig;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.MockFilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@ -60,8 +62,7 @@ public class FilterChainProxyTests extends TestCase {
public void testDetectsFilterInvocationDefinitionSourceThatDoesNotReturnAllConfigAttributes()
throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext
.getContext());
filterChainProxy.setApplicationContext(MockApplicationContext.getContext());
filterChainProxy.setFilterInvocationDefinitionSource(new MockFilterInvocationDefinitionSource(
false, false));
@ -77,8 +78,7 @@ public class FilterChainProxyTests extends TestCase {
public void testDetectsIfConfigAttributeDoesNotReturnValueForGetAttributeMethod()
throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext
.getContext());
filterChainProxy.setApplicationContext(MockApplicationContext.getContext());
ConfigAttributeDefinition cad = new ConfigAttributeDefinition();
cad.addConfigAttribute(new MockConfigAttribute());
@ -93,15 +93,15 @@ public class FilterChainProxyTests extends TestCase {
filterChainProxy.init(new MockFilterConfig());
fail("Should have thrown IllegalArgumentException");
} 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()
throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext
.getContext());
filterChainProxy.setApplicationContext(MockApplicationContext.getContext());
try {
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() {
FilterChainProxy filterChainProxy = new FilterChainProxy();
FilterInvocationDefinitionSource fids = new MockFilterInvocationDefinitionSource(false,

View File

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