3 changed files with 525 additions and 0 deletions
@ -0,0 +1,248 @@
@@ -0,0 +1,248 @@
|
||||
/* Copyright 2004 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package net.sf.acegisecurity.util; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.HashSet; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import javax.servlet.Filter; |
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.FilterConfig; |
||||
import javax.servlet.ServletContext; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.ServletRequest; |
||||
import javax.servlet.ServletResponse; |
||||
|
||||
import net.sf.acegisecurity.ConfigAttribute; |
||||
import net.sf.acegisecurity.ConfigAttributeDefinition; |
||||
import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.springframework.beans.factory.BeanFactoryUtils; |
||||
import org.springframework.beans.factory.InitializingBean; |
||||
import org.springframework.beans.factory.config.BeanPostProcessor; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.web.context.support.WebApplicationContextUtils; |
||||
|
||||
/** |
||||
* Delegates <code>Filter</code> requests to a Spring-managed bean. |
||||
* <p> |
||||
* This class acts as a proxy on behalf of a target <code>Filter</code> that |
||||
* is defined in the Spring bean context. It is necessary to specify which |
||||
* target <code>Filter</code> should be proxied as a filter initialization |
||||
* parameter. |
||||
* </p> |
||||
* <p> |
||||
* On filter initialisation, the class will use Spring's {@link |
||||
* WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)} |
||||
* method to obtain an <code>ApplicationContext</code> instance. It will |
||||
* expect to find the target <code>Filter</code> in this |
||||
* <code>ApplicationContext</code>. |
||||
* </p> |
||||
* <p> |
||||
* To use this filter, it is necessary to specify <b>one </b> of the following |
||||
* filter initialization parameters: |
||||
* </p> |
||||
* <ul> |
||||
* <li><code>targetClass</code> indicates the class of the target |
||||
* <code>Filter</code> defined in the bean context. The only requirements are |
||||
* that this target class implements the <code>javax.servlet.Filter</code> |
||||
* interface and at least one instance is available in the |
||||
* <code>ApplicationContext</code>.</li> |
||||
* <li><code>targetBean</code> indicates the bean name of the target class. |
||||
* </li> |
||||
* </ul> |
||||
* If both initialization parameters are specified, <code>targetBean</code> |
||||
* takes priority. |
||||
* <P> |
||||
* An additional initialization parameter, <code>init</code>, is also |
||||
* supported. If set to "<code>lazy</code>" the initialization will take |
||||
* place on the first HTTP request, rather than at filter creation time. This |
||||
* makes it possible to use <code>FilterToBeanProxy</code> with the Spring |
||||
* <code>ContextLoaderServlet</code>. Where possible you should not use this |
||||
* initialization parameter, instead using <code>ContextLoaderListener</code>. |
||||
* </p> |
||||
* |
||||
// * <pre>
|
||||
// * <bean id="filterChain" class="net.sf.acegisecurity.FilterChain">
|
||||
// * <property name="filters">
|
||||
// * <value>
|
||||
// * channelProcessingFilter=/*
|
||||
// * authenticationProcessingFilter=/*
|
||||
// * basicProcessingFilter=/*
|
||||
// * sessionIntegrationFilter=/*
|
||||
// * securityEnforcementFilter=/*
|
||||
// * </value>
|
||||
// * </property>
|
||||
// * </bean>
|
||||
// * </pre>
|
||||
* |
||||
* @author Carlos Sanchez |
||||
* @version $Id$ |
||||
*/ |
||||
public class FilterChainProxy |
||||
implements Filter, InitializingBean |
||||
{ |
||||
//~ Static fields/initializers =============================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(FilterChainProxy.class); |
||||
|
||||
//~ Instance fields
|
||||
// ========================================================
|
||||
|
||||
private Filter delegate; |
||||
|
||||
private List filters; |
||||
|
||||
private FilterConfig filterConfig; |
||||
|
||||
private boolean initialized = false; |
||||
|
||||
private FilterInvocationDefinitionSource filterInvocationDefinitionSource; |
||||
|
||||
//~ Methods
|
||||
// ================================================================
|
||||
|
||||
public void setFilterInvocationDefinitionSource( |
||||
FilterInvocationDefinitionSource filterInvocationDefinitionSource) { |
||||
this.filterInvocationDefinitionSource = filterInvocationDefinitionSource; |
||||
} |
||||
|
||||
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() { |
||||
return filterInvocationDefinitionSource; |
||||
} |
||||
|
||||
public void destroy() |
||||
{ |
||||
Iterator it = filters.iterator(); |
||||
while ( it.hasNext() ) |
||||
{ |
||||
Filter filter = (Filter) it.next(); |
||||
if ( filter != null ) |
||||
{ |
||||
filter.destroy(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, |
||||
ServletException |
||||
{ |
||||
if ( !initialized ) |
||||
{ |
||||
doInit(); |
||||
} |
||||
|
||||
Iterator it = filters.iterator(); |
||||
while ( it.hasNext() ) |
||||
{ |
||||
Filter filter = (Filter) it.next(); |
||||
filter.doFilter( request, response, chain ); |
||||
} |
||||
} |
||||
|
||||
public void init( FilterConfig filterConfig ) throws ServletException |
||||
{ |
||||
this.filterConfig = filterConfig; |
||||
|
||||
String strategy = filterConfig.getInitParameter( "init" ); |
||||
|
||||
if ( (strategy != null) && strategy.toLowerCase().equals( "lazy" ) ) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
doInit(); |
||||
} |
||||
|
||||
/** |
||||
* Allows test cases to override where application context obtained from. |
||||
* |
||||
* @param filterConfig |
||||
* which can be used to find the <code>ServletContext</code> |
||||
* @return the Spring application context |
||||
*/ |
||||
protected ApplicationContext getContext( FilterConfig filterConfig ) |
||||
{ |
||||
return WebApplicationContextUtils.getRequiredWebApplicationContext( filterConfig.getServletContext() ); |
||||
} |
||||
|
||||
private void doInit() throws ServletException |
||||
{ |
||||
initialized = true; |
||||
|
||||
Iterator it = filters.iterator(); |
||||
while ( it.hasNext() ) |
||||
{ |
||||
Filter filter = (Filter) it.next(); |
||||
filter.init( filterConfig ); |
||||
} |
||||
|
||||
} |
||||
|
||||
public void afterPropertiesSet() throws Exception { |
||||
if (filterInvocationDefinitionSource == null) { |
||||
throw new IllegalArgumentException( |
||||
"filterInvocationDefinitionSource must be specified"); |
||||
} |
||||
|
||||
Iterator iter = this.filterInvocationDefinitionSource |
||||
.getConfigAttributeDefinitions(); |
||||
|
||||
if (iter == null) { |
||||
if (logger.isWarnEnabled()) { |
||||
logger.warn( |
||||
"Could not validate configuration attributes as the FilterInvocationDefinitionSource did not return a ConfigAttributeDefinition Iterator"); |
||||
} |
||||
|
||||
return; |
||||
} |
||||
|
||||
Set set = new HashSet(); |
||||
|
||||
while (iter.hasNext()) { |
||||
ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter |
||||
.next(); |
||||
Iterator attributes = def.getConfigAttributes(); |
||||
|
||||
while (attributes.hasNext()) { |
||||
ConfigAttribute attr = (ConfigAttribute) attributes.next(); |
||||
} |
||||
} |
||||
|
||||
if (set.size() == 0) { |
||||
if (logger.isInfoEnabled()) { |
||||
logger.info("Validated configuration attributes"); |
||||
} |
||||
} else { |
||||
throw new IllegalArgumentException( |
||||
"Unsupported configuration attributes: " + set.toString()); |
||||
} |
||||
|
||||
iter = filterInvocationDefinitionSource.getConfigAttributeDefinitions(); |
||||
while ( iter.hasNext() ) |
||||
{ |
||||
ConfigAttributeDefinition element = (ConfigAttributeDefinition) iter.next(); |
||||
Iterator configAttributes = element.getConfigAttributes(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,261 @@
@@ -0,0 +1,261 @@
|
||||
/* Copyright 2004 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package net.sf.acegisecurity.util; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import net.sf.acegisecurity.MockFilterConfig; |
||||
import net.sf.acegisecurity.MockHttpServletRequest; |
||||
import net.sf.acegisecurity.MockHttpServletResponse; |
||||
|
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.support.ClassPathXmlApplicationContext; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import javax.servlet.Filter; |
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.FilterConfig; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.ServletRequest; |
||||
import javax.servlet.ServletResponse; |
||||
|
||||
/** |
||||
* Tests {@link FilterChainProxy}. |
||||
* |
||||
* @author Carlos Sanchez |
||||
* @version $Id$ |
||||
*/ |
||||
public class FilterChainProxyTests |
||||
extends TestCase |
||||
{ |
||||
//~ Constructors
|
||||
// ===========================================================
|
||||
|
||||
public FilterChainProxyTests() |
||||
{ |
||||
super(); |
||||
} |
||||
|
||||
public FilterChainProxyTests( String arg0 ) |
||||
{ |
||||
super( arg0 ); |
||||
} |
||||
|
||||
//~ 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 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() ); |
||||
} |
||||
} |
||||
|
||||
public void testDetectsTargetBeanNotInBeanContext() throws Exception |
||||
{ |
||||
// Setup our filter
|
||||
MockFilterConfig config = new MockFilterConfig(); |
||||
config.setInitParmeter( "targetBean", "WRONG_NAME" ); |
||||
|
||||
FilterToBeanProxy filter = new MockFilterToBeanProxy( "net/sf/acegisecurity/util/filtertest-valid.xml" ); |
||||
|
||||
try |
||||
{ |
||||
filter.init( config ); |
||||
fail( "Should have thrown ServletException" ); |
||||
} |
||||
catch ( ServletException expected ) |
||||
{ |
||||
assertEquals( "targetBean 'WRONG_NAME' not found in context", expected.getMessage() ); |
||||
} |
||||
} |
||||
|
||||
public void testIgnoresEmptyTargetBean() throws Exception |
||||
{ |
||||
// Setup our filter
|
||||
MockFilterConfig config = new MockFilterConfig(); |
||||
config.setInitParmeter( "targetClass", "net.sf.acegisecurity.util.FilterChainProxy" ); |
||||
config.setInitParmeter( "targetBean", "" ); |
||||
|
||||
// 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 testNormalOperationWithLazyTrue() throws Exception |
||||
{ |
||||
// Setup our filter
|
||||
MockFilterConfig config = new MockFilterConfig(); |
||||
config.setInitParmeter( "targetBean", "filterChain" ); |
||||
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" ); |
||||
|
||||
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 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 ); |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue