Supporting Infrastructure
This chapter introduces some of the supplementary and supporting
infrastructure used by Spring Security. If a capability is not directly
related to security, yet included in the Spring Security project, we
will discuss it in this chapter.
Localization
Spring Security supports localization of exception messages that
end users are likely to see. If your application is designed for
English users, you don't need to do anything as by default all
Security Security messages are in English. If you need to support
other locales, everything you need to know is contained in this
section.
All exception messages can be localized, including messages
related to authentication failures and access being denied
(authorization failures). Exceptions and logging that is focused on
developers or system deployers (including incorrect attributes,
interface contract violations, using incorrect constructors, startup
time validation, debug-level logging) etc are not localized and
instead are hard-coded in English within Spring Security's
code.
Shipping in the acegi-security-xx.jar you
will find an org.springframework.security package
that in turn contains a messages.properties file.
This should be referred to by your
ApplicationContext, as Acegi Security classes
implement Spring's MessageSourceAware interface and
expect the message resolver to be dependency injected at application
context startup time. Usually all you need to do is register a bean
inside your application context to refer to the messages. An example
is shown below:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename"><value>org/acegisecurity/messages</value></property>
</bean>
The messages.properties is named in
accordance with standard resource bundles and represents the default
language supported by Spring Security messages. This default file is
in English. If you do not register a message source, Spring Security
will still work correctly and fallback to hard-coded English versions
of the messages.
If you wish to customize the
messages.properties file, or support other
languages, you should copy the file, rename it accordingly, and
register it inside the above bean definition. There are not a large
number of message keys inside this file, so localization should not be
considered a major initiative. If you do perform localization of this
file, please consider sharing your work with the community by logging
a JIRA task and attaching your appropriately-named localized version
of messages.properties.
Rounding out the discussion on localization is the Spring
ThreadLocal known as
org.springframework.context.i18n.LocaleContextHolder.
You should set the LocaleContextHolder to represent
the preferred Locale of each user. Spring Security
will attempt to locate a message from the message source using the
Locale obtained from this
ThreadLocal. Please refer to Spring documentation
for further details on using LocaleContextHolder
and the helper classes that can automatically set it for you (eg
AcceptHeaderLocaleResolver,
CookieLocaleResolver,
FixedLocaleResolver,
SessionLocaleResolver etc)
Filters
Spring Security uses many filters, as referred to throughout the
remainder of this reference guide. You have a choice in how these
filters are added to your web application, in that you can use either
FilterToBeanProxy or
FilterChainProxy. We'll look at both below.
Most filters are configured using the
FilterToBeanProxy. An example configuration from
web.xml follows:
<filter>
<filter-name>Spring Security HTTP Request Security Filter</filter-name>
<filter-class>org.springframework.security.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.springframework.security.ClassThatImplementsFilter</param-value>
</init-param>
</filter>
Notice that the filter in web.xml is actually
a FilterToBeanProxy, and not the filter that will
actually implement the logic of the filter. What
FilterToBeanProxy 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 application context lifecycle support and
configuration flexibility. The bean must implement
javax.servlet.Filter.
The FilterToBeanProxy only requires a single
initialization parameter, targetClass or
targetBean. The targetClass
parameter locates the first object in the application context of the
specified class, whilst targetBean locates the
object by bean name. Like standard Spring web applications, the
FilterToBeanProxy accesses the application context
via
WebApplicationContextUtils.getWebApplicationContext(ServletContext),
so you should configure a ContextLoaderListener in
web.xml.
There is a lifecycle issue to consider when hosting
Filters in an IoC container instead of a servlet
container. Specifically, which container should be responsible for
calling the Filter's "startup" and "shutdown"
methods? It is noted that the order of initialization and destruction
of a Filter can vary by servlet container, and this
can cause problems if one Filter depends on
configuration settings established by an earlier initialized
Filter. The Spring IoC container on the other hand
has more comprehensive lifecycle/IoC interfaces (such as
InitializingBean,
DisposableBean, BeanNameAware,
ApplicationContextAware and many others) as well as
a well-understood interface contract, predictable method invocation
ordering, autowiring support, and even options to avoid implementing
Spring interfaces (eg the destroy-method attribute
in Spring XML). For this reason we recommend the use of Spring
lifecycle services instead of servlet container lifecycle services
wherever possible. By default FilterToBeanProxy
will not delegate init(FilterConfig) and
destroy() methods through to the proxied bean. If
you do require such invocations to be delegated, set the
lifecycle initialization parameter to
servlet-container-managed.
Rather than using FilterToBeanProxy, we
strongly recommend to use FilterChainProxy instead.
Whilst FilterToBeanProxy is a very useful class,
the problem is that the lines of code required for
<filter> and
<filter-mapping> entries in
web.xml explodes when using more than a few
filters. To overcome this issue, Spring Security provides a
FilterChainProxy class. It is wired using a
FilterToBeanProxy (just like in the example above),
but the target class is
org.springframework.security.util.FilterChainProxy.
The filter chain is then declared in the application context, using
code such as this:
<bean id="filterChainProxy"
class="org.springframework.security.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/webServices/**=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
/**=httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
</value>
</property>
</bean>
You may notice similarities with the way
FilterSecurityInterceptor is declared. 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.
Each of the corresponding configuration attributes represent the name
of a bean defined in the application context. The filters will then be
invoked in the order they are specified, with standard
FilterChain behaviour being respected (a
Filter can elect not to proceed with the chain if
it wishes to end processing).
As you can see, FilterChainProxy requires the
duplication of filter names for different request patterns (in the
above example, exceptionTranslationFilter and
filterSecurityInterceptor are duplicated). This
design decision was made to enable FilterChainProxy
to specify different Filter invocation orders for
different URI patterns, and also to improve both the expressiveness
(in terms of regular expressions, Ant Paths, and any custom
FilterInvocationDefinitionSource implementations)
and clarity of which Filters should be
invoked.
You may have noticed we have declared two
HttpSessionContextIntegrationFilters in the filter
chain (ASC is short for
allowSessionCreation, a property of
HttpSessionContextIntegrationFilter). 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
HttpSessionContextIntegrationFilter (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 once,
irrespective of how many times it is declared by the
FilterInvocationDefinitionSource. You control the
overall choice as to whether these methods are called or not via the
lifecycle initialization parameter of the
FilterToBeanProxy that proxies
FilterChainProxy. As discussed above, by default
any servlet container lifecycle invocations are not delegated through
to FilterChainProxy.
You can also omit a URI pattern from the filter chain by using
the token #NONE# on the right-hand side of the
<URI Pattern> = <Filter Chain>
expression. For example, using the example above, if you wanted to
exclude the /webservices location completely, you
would modify the corresponding line in the bean declaration to be
/webServices/**=#NONE#
Note that anything matching this path will then have
no authentication or authorization services applied and will be freely
accessible.
The order that filters are defined in web.xml
is very important. Irrespective of which filters you are actually
using, the order of the <filter-mapping>s
should be as follows:
ChannelProcessingFilter, because it might
need to redirect to a different protocol
ConcurrentSessionFilter, because it
doesn't use any SecurityContextHolder
functionality but needs to update the
SessionRegistry to reflect ongoing requests
from the principal
HttpSessionContextIntegrationFilter, so a
SecurityContext can be setup 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 -
AuthenticationProcessingFilter,
CasProcessingFilter,
BasicProcessingFilter, HttpRequestIntegrationFilter,
JbossIntegrationFilter etc - so that the
SecurityContextHolder can be modified to
contain a valid Authentication request
token
The
SecurityContextHolderAwareRequestFilter, if you
are using it to install a Spring Security aware
HttpServletRequestWrapper into your servlet
container
RememberMeProcessingFilter, 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 there
AnonymousProcessingFilter, so that if no
earlier authentication processing mechanism updated the
SecurityContextHolder, an anonymous
Authentication object will be put there
ExceptionTranslationFilter, to catch any
Spring Security exceptions so that either an HTTP error response
can be returned or an appropriate
AuthenticationEntryPoint can be launched
FilterSecurityInterceptor, to protect web
URIs
All of the above filters use
FilterToBeanProxy or
FilterChainProxy. It is recommended that a single
FilterToBeanProxy proxy through to a single
FilterChainProxy for each application, with that
FilterChainProxy defining all of Spring Security
Filters.
If you're using SiteMesh, ensure Spring Security filters execute
before the SiteMesh filters are called. This enables the
SecurityContextHolder to be populated in time for
use by SiteMesh decorators