SEC-247: Allow #NONE# to be used to specify paths that shouldn't have any filters fire.
This commit is contained in:
parent
185d63f23c
commit
4e09777dec
|
@ -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,36 +126,27 @@ 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 (logger.isDebugEnabled()) {
|
if (filters[i] != null) {
|
||||||
logger.debug(
|
if (logger.isDebugEnabled()) {
|
||||||
"Destroying Filter defined in ApplicationContext: '"
|
logger.debug(
|
||||||
+ filters[i].toString() + "'");
|
"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 {
|
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 (logger.isDebugEnabled()) {
|
if (filters[i] != null) {
|
||||||
logger.debug(
|
if (logger.isDebugEnabled()) {
|
||||||
"Initializing Filter defined in ApplicationContext: '"
|
logger.debug(
|
||||||
+ filters[i].toString() + "'");
|
"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
|
* <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 ==========================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue