Rewrite FilterChainProxy to separate functionality from FilterToBeanProxy and properly implement filter chaining issues.

This commit is contained in:
Ben Alex
2005-02-20 05:40:18 +00:00
parent 57842d4ba8
commit a5ea6f5436
4 changed files with 397 additions and 393 deletions

View File

@@ -1,4 +1,4 @@
/* Copyright 2004 Acegi Technology Pty Limited
/* Copyright 2004, 2005 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,9 +17,15 @@ package net.sf.acegisecurity.util;
import junit.framework.TestCase;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.MockApplicationContext;
import net.sf.acegisecurity.MockFilterConfig;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
import net.sf.acegisecurity.intercept.web.MockFilterInvocationDefinitionSource;
import net.sf.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -33,229 +39,138 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Tests {@link FilterChainProxy}.
*
*
* @author Carlos Sanchez
* @author Ben Alex
* @version $Id$
*/
public class FilterChainProxyTests
extends TestCase
{
//~ Constructors
// ===========================================================
public class FilterChainProxyTests extends TestCase {
//~ Constructors ===========================================================
public FilterChainProxyTests()
{
// ===========================================================
public FilterChainProxyTests() {
super();
}
public FilterChainProxyTests( String arg0 )
{
super( arg0 );
public FilterChainProxyTests(String arg0) {
super(arg0);
}
//~ Methods
//~ Methods ================================================================
// ================================================================
public final void setUp() throws Exception
{
super.setUp();
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
// "net/sf/acegisecurity/util/filtertest-valid.xml" );
// FilterChainProxy filterChainProxy = (FilterChainProxy)applicationContext.getBean("filterChain");
// System.out.println(filterChainProxy);
public static void main(String[] args) {
junit.textui.TestRunner.run(FilterChainProxyTests.class);
}
public static void main( String[] args )
{
junit.textui.TestRunner.run( FilterChainProxyTests.class );
}
public void testDetectsFilterInvocationDefinitionSourceThatDoesNotReturnAllConfigAttributes()
throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext
.getContext());
filterChainProxy.setFilterInvocationDefinitionSource(new MockFilterInvocationDefinitionSource(
false, false));
public void testDetectsTargetBeanIsNotAFilter() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetClass", "net.sf.acegisecurity.util.MockNotAFilter" );
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
try
{
filter.init( config );
fail( "Should have thrown ServletException" );
}
catch ( ServletException expected )
{
assertEquals( "Bean 'mockNotAFilter' does not implement javax.servlet.Filter", expected.getMessage() );
try {
filterChainProxy.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("FilterChainProxy requires the FitlerInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()",
expected.getMessage());
}
}
public void testDetectsTargetBeanNotInBeanContext() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetBean", "WRONG_NAME" );
public void testDetectsIfConfigAttributeDoesNotReturnValueForGetAttributeMethod()
throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext
.getContext());
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
ConfigAttributeDefinition cad = new ConfigAttributeDefinition();
cad.addConfigAttribute(new MockConfigAttribute());
try
{
filter.init( config );
fail( "Should have thrown ServletException" );
}
catch ( ServletException expected )
{
assertEquals( "targetBean 'WRONG_NAME' not found in context", expected.getMessage() );
PathBasedFilterInvocationDefinitionMap fids = new PathBasedFilterInvocationDefinitionMap();
fids.addSecureUrl("/**", cad);
filterChainProxy.setFilterInvocationDefinitionSource(fids);
filterChainProxy.afterPropertiesSet();
try {
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"));
}
}
public void testIgnoresEmptyTargetBean() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetClass", "net.sf.acegisecurity.util.FilterChainProxy" );
config.setInitParmeter( "targetBean", "" );
public void testDetectsMissingFilterInvocationDefinitionSource()
throws Exception {
FilterChainProxy filterChainProxy = new FilterChainProxy();
filterChainProxy.setApplicationContext(MockApplicationContext
.getContext());
// Setup our expectation that the filter chain will be invoked
MockFilterChain chain = new MockFilterChain( true );
try {
filterChainProxy.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("filterInvocationDefinitionSource must be specified",
expected.getMessage());
}
}
public void testGettersSetters() {
FilterChainProxy filterChainProxy = new FilterChainProxy();
FilterInvocationDefinitionSource fids = new MockFilterInvocationDefinitionSource(false,
false);
filterChainProxy.setFilterInvocationDefinitionSource(fids);
assertEquals(fids,
filterChainProxy.getFilterInvocationDefinitionSource());
}
public void testNormalOperation() throws Exception {
ApplicationContext appCtx = new ClassPathXmlApplicationContext(
"net/sf/acegisecurity/util/filtertest-valid.xml");
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain",
FilterChainProxy.class);
MockFilter filter = (MockFilter) appCtx.getBean("mockFilter",
MockFilter.class);
assertFalse(filter.isWasInitialized());
assertFalse(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
filterChainProxy.init(new MockFilterConfig());
assertTrue(filter.isWasInitialized());
assertFalse(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
MockHttpServletRequest request = new MockHttpServletRequest(null);
request.setServletPath("/foo/secure/super/somefile.html");
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest( "/go" );
MockFilterChain chain = new MockFilterChain(true);
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
filterChainProxy.doFilter(request, response, chain);
assertTrue(filter.isWasInitialized());
assertTrue(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
executeFilterInContainerSimulator( config, filter, request, response, chain );
request.setServletPath("/a/path/which/doesnt/match/any/filter.html");
filterChainProxy.doFilter(request, response, chain);
filterChainProxy.destroy();
assertTrue(filter.isWasInitialized());
assertTrue(filter.isWasDoFiltered());
assertTrue(filter.isWasDestroyed());
}
public void testNormalOperationWithLazyTrue() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetBean", "filterChain" );
config.setInitParmeter( "init", "lazy" );
//~ Inner Classes ==========================================================
// Setup our expectation that the filter chain will be invoked
MockFilterChain chain = new MockFilterChain( true );
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest( "/go" );
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
executeFilterInContainerSimulator( config, filter, request, response, chain );
}
public void testNormalOperationWithSpecificBeanName() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetBean", "filterChain" );
// Setup our expectation that the filter chain will be invoked
MockFilterChain chain = new MockFilterChain( true );
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest( "/go" );
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
executeFilterInContainerSimulator( config, filter, request, response, chain );
}
public void testNormalOperationWithTargetClass() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetClass", "net.sf.acegisecurity.util.FilterChainProxy" );
// Setup our expectation that the filter chain will be invoked
MockFilterChain chain = new MockFilterChain( true );
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest( "/go" );
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
executeFilterInContainerSimulator( config, filter, request, response, chain );
}
public void testNullDelegateDoesNotCauseNullPointerException() throws Exception
{
// Setup our filter
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter( "targetBean", "aFilterThatDoesntExist" );
config.setInitParmeter( "init", "lazy" );
// Setup our expectation that the filter chain will be invoked
MockFilterChain chain = new MockFilterChain( true );
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest( "/go" );
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" );
// do not init (which would hapen if called .doFilter)
filter.destroy();
}
private void executeFilterInContainerSimulator( FilterConfig filterConfig, Filter filter, ServletRequest request,
ServletResponse response, FilterChain filterChain ) throws ServletException, IOException
{
filter.init( filterConfig );
filter.doFilter( request, response, filterChain );
filter.destroy();
}
//~ Inner Classes
// ==========================================================
private class MockFilterChain
implements FilterChain
{
private boolean expectToProceed;
public MockFilterChain( boolean expectToProceed )
{
this.expectToProceed = expectToProceed;
}
private MockFilterChain()
{
super();
}
public void doFilter( ServletRequest request, ServletResponse response ) throws IOException, ServletException
{
if ( expectToProceed )
{
assertTrue( true );
}
else
{
fail( "Did not expect filter chain to proceed" );
}
private class MockConfigAttribute implements ConfigAttribute {
public String getAttribute() {
return null;
}
}
private class MockFilterToBeanProxy
extends FilterToBeanProxy
{
private String appContextLocation;
public MockFilterToBeanProxy( String appContextLocation )
{
this.appContextLocation = appContextLocation;
}
private MockFilterToBeanProxy()
{
super();
}
protected ApplicationContext getContext( FilterConfig filterConfig )
{
return new ClassPathXmlApplicationContext( appContextLocation );
}
}
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2004 Acegi Technology Pty Limited
/* Copyright 2004, 2005 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.
@@ -32,14 +32,37 @@ import javax.servlet.ServletResponse;
* @version $Id$
*/
public class MockFilter implements Filter {
//~ Instance fields ========================================================
private boolean wasDestroyed = false;
private boolean wasDoFiltered = false;
private boolean wasInitialized = false;
//~ Methods ================================================================
public void destroy() {}
public boolean isWasDestroyed() {
return wasDestroyed;
}
public boolean isWasDoFiltered() {
return wasDoFiltered;
}
public boolean isWasInitialized() {
return wasInitialized;
}
public void destroy() {
wasDestroyed = true;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
wasDoFiltered = true;
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {}
public void init(FilterConfig config) throws ServletException {
wasInitialized = true;
}
}

View File

@@ -23,21 +23,19 @@
<bean id="mockFilter" class="net.sf.acegisecurity.util.MockFilter"/>
<bean id="mockFilter2" class="net.sf.acegisecurity.util.MockFilter"/>
<bean id="mockNotAFilter" class="net.sf.acegisecurity.util.MockNotAFilter"/>
<bean id="filterChain" class="net.sf.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
/*=mockFilter
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/foo/**=mockFilter
/some/other/path/**=mockFilter
</value>
</property>
<!--
<property name="filters">
<value>
/*=mockFilter
</value>
</property>
-->
</bean>
</beans>