Web Application InfrastructureThe Security Filter ChainSpring Security's web infrastructure is based entirely on standard servlet filters. It
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC)
internally, so it has no strong links to any particular web technology. It deals in
HttpServletRequests and
HttpServletResponses and doesn't care whether the requests come
from a browser, a web service client, an HttpInvoker or an AJAX
application. Spring Security maintains a filter chain internally where each of the filters has a
particular responsibility and filters are added or removed from the configuration
depending on which services are required. The ordering of the filters is important as
there are dependencies between them. If you have been using namespace configuration, then the filters are
automatically configured for you and you don't have to define any Spring beans
explicitly but here may be times when you want full control over the security filter
chain, either because you are using features which aren't supported in the namespace, or
you are using your own customized versions of classes.DelegatingFilterProxy When using servlet filters, you obviously need to declare them in your
web.xml, or they will be ignored by the servlet container. In
Spring Security, the filter classes are also Spring beans defined in the application
context and thus able to take advantage of Spring's rich dependency-injection
facilities and lifecycle interfaces. Spring's
DelegatingFilterProxy provides the link between
web.xml and the application context. When using DelegatingFilterProxy, you will see something
like this in the web.xml file: myFilterorg.springframework.web.filter.DelegatingFilterProxymyFilter/*]]>
Notice that the filter is actually a
DelegatingFilterProxy, and not the class that will actually
implement the logic of the filter. What DelegatingFilterProxy
does is delegate the Filter's methods through to a
bean which is obtained from the Spring application context. This enables the bean to
benefit from the Spring web application context lifecycle support and configuration
flexibility. The bean must implement
javax.servlet.Filter and it must have the same name
as that in the filter-name element. Read the Javadoc for
DelegatingFilterProxy for more informationFilterChainProxy It should now be clear that you can declare each Spring Security filter bean that
you require in your application context file and add a corresponding
DelegatingFilterProxy entry to web.xml
for each filter, making sure that they are ordered correctly. This is a cumbersome
approach and clutters up the web.xml file quickly if we have a
lot of filters. We would prefer to just add a single entry to
web.xml and deal entirely with the application context file for
managing our web security beans. This is where Spring Secuiryt's
FilterChainProxy comes in. It is wired using a
DelegatingFilterProxy, just like in the example above, but with
the filter-name set to the bean name
filterChainProxy. The filter chain is then declared in the
application context with the same bean name. Here's an example:
]]>
The namespace element filter-chain-map is used to set
up the security filter chain(s) which are required within the applicationNote that you'll need to include the security namespace in your application
context XML file in order to use this syntax.. It maps a particular URL pattern to a chain of filters built up from
the bean names specified in the filters element. Both regular
expressions and Ant Paths are supported, and the most specific URIs appear first. At
runtime the FilterChainProxy will locate the first URI
pattern that matches the current web request and the list of filter beans specified
by the filters attribute will be applied to that request. The
filters will be invoked in the order they are defined, so you have complete control
over the filter chain which is applied to a particular URL.You may have noticed we have declared two
SecurityContextPersistenceFilters in the filter chain
(ASC is short for allowSessionCreation, a
property of SecurityContextPersistenceFilter). As web
services will never present a jsessionid on future requests,
creating HttpSessions for such user agents would be wasteful. If
you had a high-volume application which required maximum scalability, we recommend
you use the approach shown above. For smaller applications, using a single
SecurityContextPersistenceFilter (with its default
allowSessionCreation as true) would likely be
sufficient.In relation to lifecycle issues, the FilterChainProxy will
always delegate init(FilterConfig) and
destroy() methods through to the underlaying
Filters if such methods are called against
FilterChainProxy itself. In this case,
FilterChainProxy guarantees to only initialize and destroy
each Filter bean once, no matter how many times it is declared in
the filter chain(s). You control the overall choice as to whether these methods are
called or not via the targetFilterLifecycle initialization
parameter of DelegatingFilterProxy. By default this property is
false and servlet container lifecycle invocations are not
delegated through DelegatingFilterProxy. When we looked at how to set up web security using namespace configuration, we used a
DelegatingFilterProxy with the name
springSecurityFilterChain. You should now be able to see that this is
the name of the FilterChainProxy which is created by the
namespace. Bypassing the Filter Chain As with the namespace, you can use the attribute filters =
"none" as an alternative to supplying a filter bean list. This will
omit the request pattern from the security filter chain entirely. Note that
anything matching this path will then have no authentication or authorization
services applied and will be freely accessible. If you want to make use of the
contents of the SecurityContext contents during a
request, then it must have passed through the security filter chain. Otherwise
the SecurityContextHolder will not have been populated
and the contents will be null.Filter OrderingThe order that filters are defined in the chain is very important. Irrespective of
which filters you are actually using, the order should be as follows: ChannelProcessingFilter, because it might need to
redirect to a different protocolConcurrentSessionFilter, because it doesn't use any
SecurityContextHolder functionality but needs to
update the SessionRegistry to reflect ongoing
requests from the principalSecurityContextPersistenceFilter, so a
SecurityContext can be set up in the
SecurityContextHolder at the beginning of a web
request, and any changes to the
SecurityContext can be copied to the
HttpSession when the web request ends (ready for use with
the next web request)Authentication processing mechanisms -
UsernamePasswordAuthenticationFilter,
CasProcessingFilter,
BasicProcessingFilter etc - so that the
SecurityContextHolder can be modified to contain a
valid Authentication request tokenThe SecurityContextHolderAwareRequestFilter, if you are
using it to install a Spring Security aware
HttpServletRequestWrapper into your servlet
containerRememberMeProcessingFilter, so that if no earlier
authentication processing mechanism updated the
SecurityContextHolder, and the request presents a
cookie that enables remember-me services to take place, a suitable
remembered Authentication object will be put
thereAnonymousProcessingFilter, so that if no earlier
authentication processing mechanism updated the
SecurityContextHolder, an anonymous
Authentication object will be put
thereExceptionTranslationFilter, to catch any Spring
Security exceptions so that either an HTTP error response can be returned or
an appropriate AuthenticationEntryPoint can
be launchedFilterSecurityInterceptor, to protect web URIs and
raise exceptions when access is deniedUse with other Filter-Based FrameworksIf you're using some other framework that is also filter-based, then you need to
make sure that the Spring Security filters come first. This enables the
SecurityContextHolder to be populated in time for use by the
other filters. Examples are the use of SiteMesh to decorate your web pages or a web
framework like Wicket which uses a filter to handle its requests.