@ -15,11 +15,10 @@
@@ -15,11 +15,10 @@
package org.springframework.security.util ;
import org.springframework.security.ConfigAttribute ;
import org.springframework.security.ConfigAttributeDefinition ;
import org.springframework.security.intercept.web.FilterInvocation ;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource ;
import org.springframework.security.intercept.web.FilterChainMap ;
import org.springframework.security.intercept.web.FIDSToFilterChainMapConverter ;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
@ -34,12 +33,6 @@ import org.springframework.util.Assert;
@@ -34,12 +33,6 @@ import org.springframework.util.Assert;
import java.io.IOException ;
import java.util.Iterator ;
import java.util.LinkedHashSet ;
import java.util.List ;
import java.util.Set ;
import java.util.Vector ;
import javax.servlet.Filter ;
import javax.servlet.FilterChain ;
import javax.servlet.FilterConfig ;
@ -49,22 +42,48 @@ import javax.servlet.ServletResponse;
@@ -49,22 +42,48 @@ import javax.servlet.ServletResponse;
/ * *
* Delegates < code > Filter < / code > requests to a list of Spring - managed beans . < p > The < code > FilterChainProxy < / code > is
* loaded via a standard { @link org . springframework . security . util . FilterToBeanProxy } declaration in < code > web . xml < / code > .
* Delegates < code > Filter < / code > requests to a list of Spring - managed beans .
* As of version 2 . 0 , you shouldn ' t need to explicitly configure a < tt > FilterChainProxy < / tt > bean in your application
* context unless you need very fine control over the filter chain contents . Most cases should be adequately covered
* by the default < tt > & lt ; security : http / & gt < / tt > namespace configuration options .
*
* < p > The < code > FilterChainProxy < / code > is loaded via a standard
* { @link org . springframework . security . util . FilterToBeanProxy } declaration in < code > web . xml < / code > .
* < code > FilterChainProxy < / code > will then pass { @link # init ( FilterConfig ) } , { @link # destroy ( ) } and { @link
* # doFilter ( ServletRequest , ServletResponse , FilterChain ) } invocations through to each < code > Filter < / code > defined
* against < code > FilterChainProxy < / code > . < / p >
* < p > < code > FilterChainProxy < / code > is configured using a standard { @link
* org . springframework . security . intercept . web . FilterInvocationDefinitionSource } . Each possible URI pattern that
* < code > FilterChainProxy < / code > should service must be entered . The first matching URI pattern located by
* < code > FilterInvocationDefinitionSource < / code > for a given request will be used to define all of the
*
* < p > As of version 2 . 0 , < tt > FilterChainProxy < / tt > is configured using a { @link FilterChainMap } . In previous
* versions , a { @link FilterInvocationDefinitionSource } was used . This is now deprecated in favour of namespace - based
* configuration which provides a more robust and simplfied syntax . The < tt > FilterChainMap < / tt > instance will be
* created while parsing the namespace configuration , so it doesn ' t require an explicit bean declaration .
* Instead the & lt ; filter - chain - map & gt ; element should be used within the FilterChainProxy bean declaration .
* This in turn should have a list of child & lt ; filter - chain & gt ; elements which each define a URI pattern and the list
* of filters ( as comma - separated bean names ) which should be applied to requests which match the pattern .
* An example configuration might look like this :
*
* < pre >
& lt ; bean id = "myfilterChainProxy" class = "org.springframework.security.util.FilterChainProxy" >
& lt ; security : filter - chain - map pathType = "ant" >
& lt ; security : filter - chain pattern = "/do/not/filter" filters = "none" / >
& lt ; security : filter - chain pattern = "/**" filters = "filter1,filter2,filter3" / >
& lt ; / security : filter - chain - map >
& lt ; / bean >
* < / pre >
*
* The names "filter1" , "filter2" , "filter3" should be the bean names of < tt > Filter < / tt > instances defined in the
* application context . The order of the names defines the order in which the filters will be applied . As shown above ,
* use of the value "none" for the "filters" can be used to exclude
* Please consult the security namespace schema file for a full list of available configuration options .
* < / p >
*
* < p >
* Each possible URI pattern that < code > FilterChainProxy < / code > should service must be entered .
* The first matching URI pattern for a given request will be used to define all of the
* < code > Filter < / code > s that apply to that request . NB : This means you must put most specific URI patterns at the top
* of the list , and ensure all < code > Filter < / code > s that should apply for a given URI pattern are entered against the
* respective entry . The < code > FilterChainProxy < / code > will not iterate the remainder of the URI patterns to locate
* additional < code > Filter < / code > s . The < code > FilterInvocationDefinitionSource < / code > described the applicable URI
* pattern to fire the filter chain , followed by a list of configuration attributes . Each configuration attribute ' s
* { @link org . springframework . security . ConfigAttribute # getAttribute ( ) } corresponds to a bean name that is available from the
* application context . < / p >
* additional < code > Filter < / code > s . < / p >
* < p > < code > FilterChainProxy < / code > respects normal handling of < code > Filter < / code > s that elect not to call { @link
* javax . servlet . Filter # doFilter ( javax . servlet . ServletRequest , javax . servlet . ServletResponse ,
* javax . servlet . FilterChain ) } , in that the remainder of the origial or < code > FilterChainProxy < / code > - declared filter
@ -73,14 +92,14 @@ import javax.servlet.ServletResponse;
@@ -73,14 +92,14 @@ import javax.servlet.ServletResponse;
* container . As per { @link org . springframework . security . 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
* defined in the FilterChainMap 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
* @author Ben Alex
* @author Luke Taylor
*
* @version $Id$
* /
public class FilterChainProxy implements Filter , InitializingBean , ApplicationContextAware {
@ -92,19 +111,22 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -92,19 +111,22 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
//~ Instance fields ================================================================================================
private ApplicationContext applicationContext ;
private FilterInvocationDefinitionSource filterInvocationDefinitionSource ;
private FilterChainMap filterChainMap ;
private FilterInvocationDefinitionSource fids ;
//~ Methods ========================================================================================================
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()" ) ;
// Convert the FilterDefinitionSource to a filterChainMap if set
if ( fids ! = null ) {
Assert . isNull ( filterChainMap , "Set the FilterChainMap or FilterInvocationDefinitionSource but not both" ) ;
setFilterChainMap ( new FIDSToFilterChainMapConverter ( fids , applicationContext ) . getFilterChainMap ( ) ) ;
}
Assert . notNull ( filterChainMap , "A FilterChainMap must be supplied" ) ;
}
public void destroy ( ) {
Filter [ ] filters = obtain AllDefinedFilters( ) ;
Filter [ ] filters = filterChainMap . get AllDefinedFilters( ) ;
for ( int i = 0 ; i < filters . length ; i + + ) {
if ( filters [ i ] ! = null ) {
@ -118,26 +140,16 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -118,26 +140,16 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
}
public void doFilter ( ServletRequest request , ServletResponse response , FilterChain chain )
throws IOException , ServletException {
FilterInvocation fi = new FilterInvocation ( request , response , chain ) ;
ConfigAttributeDefinition cad = this . filterInvocationDefinitionSource . getAttributes ( fi ) ;
if ( cad = = null ) {
if ( logger . isDebugEnabled ( ) ) {
logger . debug ( fi . getRequestUrl ( ) + " has no matching filters" ) ;
}
chain . doFilter ( request , response ) ;
throws IOException , ServletException {
return ;
}
FilterInvocation fi = new FilterInvocation ( request , response , chain ) ;
Filter [ ] filters = obtainAllDefinedFilters ( cad ) ;
Filter [ ] filters = filterChainMap . getFilters ( fi . getRequestUrl ( ) ) ;
if ( filters . length = = 0 ) {
if ( filters = = null | | filters . length = = 0 ) {
if ( logger . isDebugEnabled ( ) ) {
logger . debug ( fi . getRequestUrl ( ) + " has an empty filter list" ) ;
logger . debug ( fi . getRequestUrl ( ) +
filters = = null ? " has no matching filters" : " has an empty filter list" ) ;
}
chain . doFilter ( request , response ) ;
@ -149,12 +161,8 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -149,12 +161,8 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
virtualFilterChain . doFilter ( fi . getRequest ( ) , fi . getResponse ( ) ) ;
}
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource ( ) {
return filterInvocationDefinitionSource ;
}
public void init ( FilterConfig filterConfig ) throws ServletException {
Filter [ ] filters = obtain AllDefinedFilters( ) ;
Filter [ ] filters = filterChainMap . getAllDefinedFilters ( ) ;
for ( int i = 0 ; i < filters . length ; i + + ) {
if ( filters [ i ] ! = null ) {
@ -168,70 +176,39 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -168,70 +176,39 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
}
/ * *
* Obtains all of the < b > unique < / b > < code > Filter < / code > instances registered against the
* < code > FilterInvocationDefinitionSource < / code > . < p > This is useful in ensuring a < code > Filter < / code > is not
* Obtains all of the < b > unique < / b > < code > Filter < / code > instances registered in the
* < code > FilterChainMap < / code > .
* < p > This is useful in ensuring a < code > Filter < / code > is not
* initialized or destroyed twice . < / p >
*
* @return all of the < code > Filter < / code > instances in the application context for which there has been an entry
* against the < code > FilterInvocationDefinitionSource < / code > ( only one entry is included in the array for
* @deprecated
* @return all of the < code > Filter < / code > instances in the application context which have an entry
* in the < code > FilterChainMap < / code > ( only one entry is included in the array for
* each < code > Filter < / code > that actually exists in application context , even if a given
* < code > Filter < / code > is defined multiples times by the < code > FilterInvocationDefinitionSource < / code > )
* < code > Filter < / code > is defined multiples times by the < code > FilterChainMap < / code > )
* /
protected Filter [ ] obtainAllDefinedFilters ( ) {
Iterator cads = this . filterInvocationDefinitionSource . getConfigAttributeDefinitions ( ) ;
Set list = new LinkedHashSet ( ) ;
while ( cads . hasNext ( ) ) {
ConfigAttributeDefinition attribDef = ( ConfigAttributeDefinition ) cads . next ( ) ;
Filter [ ] filters = obtainAllDefinedFilters ( attribDef ) ;
for ( int i = 0 ; i < filters . length ; i + + ) {
list . add ( filters [ i ] ) ;
}
}
return filterChainMap . getAllDefinedFilters ( ) ;
}
return ( Filter [ ] ) list . toArray ( new Filter [ 0 ] ) ;
public void setApplicationContext ( ApplicationContext applicationContext ) throws BeansException {
this . applicationContext = applicationContext ;
}
/ * *
* Obtains all of the < code > Filter < / code > instances registered against the specified
* < code > ConfigAttributeDefinition < / code > .
*
* @param configAttributeDefinition for which we want to obtain associated < code > Filter < / code > s
*
* @return the < code > Filter < / code > s against the specified < code > ConfigAttributeDefinition < / code > ( never
* < code > null < / code > )
*
* @throws IllegalArgumentException DOCUMENT ME !
* @deprecated Use namespace configuration or call setFilterChainMap instead .
* /
private Filter [ ] obtainAllDefinedFilters ( ConfigAttributeDefinition configAttributeDefinition ) {
List list = new Vector ( ) ;
Iterator attributes = configAttributeDefinition . getConfigAttributes ( ) ;
while ( attributes . hasNext ( ) ) {
ConfigAttribute attr = ( ConfigAttribute ) attributes . next ( ) ;
String filterName = attr . getAttribute ( ) ;
if ( filterName = = null ) {
throw new IllegalArgumentException ( "Configuration attribute: '" + attr
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy" ) ;
}
if ( ! filterName . equals ( TOKEN_NONE ) ) {
list . add ( this . applicationContext . getBean ( filterName , Filter . class ) ) ;
}
}
return ( Filter [ ] ) list . toArray ( new Filter [ list . size ( ) ] ) ;
public void setFilterInvocationDefinitionSource ( FilterInvocationDefinitionSource fids ) {
this . fids = fids ;
}
public void setApplicationContext ( ApplicationContext applicationContext )
throws BeansException {
this . applicationContext = applicationContext ;
public void setFilterChainMap ( FilterChainMap filterChainMap ) {
this . filterChainMap = filterChainMap ;
}
public void setFilterInvocationDefinitionSource ( FilterInvocationDefinitionSource filterInvocationDefinitionSource ) {
this . filterInvocationDefinitionSource = filterInvocationDefinitionSource ;
public FilterChainMap getFilterChainMap ( ) {
return filterChainMap ;
}
//~ Inner Classes ==================================================================================================
@ -242,7 +219,7 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -242,7 +219,7 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
* < code > FilterChain < / code > is used by < code > FilterChainProxy < / code > to determine if the next < code > Filter < / code >
* should be called or not . < / p >
* /
private class VirtualFilterChain implements FilterChain {
private static class VirtualFilterChain implements FilterChain {
private FilterInvocation fi ;
private Filter [ ] additionalFilters ;
private int currentPosition = 0 ;
@ -252,8 +229,6 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -252,8 +229,6 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
this . additionalFilters = additionalFilters ;
}
private VirtualFilterChain ( ) { }
public void doFilter ( ServletRequest request , ServletResponse response )
throws IOException , ServletException {
if ( currentPosition = = additionalFilters . length ) {
@ -276,4 +251,5 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
@@ -276,4 +251,5 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
}
}
}
}