mirror of
https://github.com/spring-projects/spring-security.git
synced 2026-02-01 19:19:40 +00:00
332 lines
17 KiB
XML
332 lines
17 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.docbook.org/xml/4.4/docbookx.dtd">
|
|
|
|
<chapter id="supporting-infrastructure">
|
|
<title>Supporting Infrastructure</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<sect1 id="localization">
|
|
<title>Localization</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>Shipping in the <literal>acegi-security-xx.jar</literal> you
|
|
will find an <literal>org.springframework.security</literal> package
|
|
that in turn contains a <literal>messages.properties</literal> file.
|
|
This should be referred to by your
|
|
<literal>ApplicationContext</literal>, as Acegi Security classes
|
|
implement Spring's <literal>MessageSourceAware</literal> 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:</para>
|
|
|
|
<para><programlisting><bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
|
|
<property name="basename"><value>org/acegisecurity/messages</value></property>
|
|
</bean> </programlisting></para>
|
|
|
|
<para>The <literal>messages.properties</literal> 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.</para>
|
|
|
|
<para>If you wish to customize the
|
|
<literal>messages.properties</literal> 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 <literal>messages.properties</literal>.</para>
|
|
|
|
<para>Rounding out the discussion on localization is the Spring
|
|
<literal>ThreadLocal</literal> known as
|
|
<literal>org.springframework.context.i18n.LocaleContextHolder</literal>.
|
|
You should set the <literal>LocaleContextHolder</literal> to represent
|
|
the preferred <literal>Locale</literal> of each user. Spring Security
|
|
will attempt to locate a message from the message source using the
|
|
<literal>Locale</literal> obtained from this
|
|
<literal>ThreadLocal</literal>. Please refer to Spring documentation
|
|
for further details on using <literal>LocaleContextHolder</literal>
|
|
and the helper classes that can automatically set it for you (eg
|
|
<literal>AcceptHeaderLocaleResolver</literal>,
|
|
<literal>CookieLocaleResolver</literal>,
|
|
<literal>FixedLocaleResolver</literal>,
|
|
<literal>SessionLocaleResolver</literal> etc)</para>
|
|
</sect1>
|
|
|
|
<sect1 id="filters">
|
|
<title>Filters</title>
|
|
|
|
<para>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
|
|
<literal>FilterToBeanProxy</literal> or
|
|
<literal>FilterChainProxy</literal>. We'll look at both below.</para>
|
|
|
|
<para>Most filters are configured using the
|
|
<literal>FilterToBeanProxy</literal>. An example configuration from
|
|
<literal>web.xml</literal> follows:</para>
|
|
|
|
<para><programlisting><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></programlisting></para>
|
|
|
|
<para>Notice that the filter in <literal>web.xml</literal> is actually
|
|
a <literal>FilterToBeanProxy</literal>, and not the filter that will
|
|
actually implement the logic of the filter. What
|
|
<literal>FilterToBeanProxy</literal> does is delegate the
|
|
<literal>Filter</literal>'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
|
|
<literal>javax.servlet.Filter</literal>.</para>
|
|
|
|
<para>The <literal>FilterToBeanProxy</literal> only requires a single
|
|
initialization parameter, <literal>targetClass</literal> or
|
|
<literal>targetBean</literal>. The <literal>targetClass</literal>
|
|
parameter locates the first object in the application context of the
|
|
specified class, whilst <literal>targetBean</literal> locates the
|
|
object by bean name. Like standard Spring web applications, the
|
|
<literal>FilterToBeanProxy</literal> accesses the application context
|
|
via<literal>
|
|
WebApplicationContextUtils.getWebApplicationContext(ServletContext)</literal>,
|
|
so you should configure a <literal>ContextLoaderListener</literal> in
|
|
<literal>web.xml</literal>.</para>
|
|
|
|
<para>There is a lifecycle issue to consider when hosting
|
|
<literal>Filter</literal>s in an IoC container instead of a servlet
|
|
container. Specifically, which container should be responsible for
|
|
calling the <literal>Filter</literal>'s "startup" and "shutdown"
|
|
methods? It is noted that the order of initialization and destruction
|
|
of a <literal>Filter</literal> can vary by servlet container, and this
|
|
can cause problems if one <literal>Filter</literal> depends on
|
|
configuration settings established by an earlier initialized
|
|
<literal>Filter</literal>. The Spring IoC container on the other hand
|
|
has more comprehensive lifecycle/IoC interfaces (such as
|
|
<literal>InitializingBean</literal>,
|
|
<literal>DisposableBean</literal>, <literal>BeanNameAware</literal>,
|
|
<literal>ApplicationContextAware</literal> 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 <literal>destroy-method</literal> 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 <literal>FilterToBeanProxy</literal>
|
|
will not delegate <literal>init(FilterConfig)</literal> and
|
|
<literal>destroy()</literal> methods through to the proxied bean. If
|
|
you do require such invocations to be delegated, set the
|
|
<literal>lifecycle</literal> initialization parameter to
|
|
<literal>servlet-container-managed</literal>.</para>
|
|
|
|
<para>Rather than using <literal>FilterToBeanProxy</literal>, we
|
|
strongly recommend to use <literal>FilterChainProxy</literal> instead.
|
|
Whilst <literal>FilterToBeanProxy</literal> is a very useful class,
|
|
the problem is that the lines of code required for
|
|
<literal><filter></literal> and
|
|
<literal><filter-mapping></literal> entries in
|
|
<literal>web.xml</literal> explodes when using more than a few
|
|
filters. To overcome this issue, Spring Security provides a
|
|
<literal>FilterChainProxy</literal> class. It is wired using a
|
|
<literal>FilterToBeanProxy</literal> (just like in the example above),
|
|
but the target class is
|
|
<literal>org.springframework.security.util.FilterChainProxy</literal>.
|
|
The filter chain is then declared in the application context, using
|
|
code such as this:</para>
|
|
|
|
<para><programlisting><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> </programlisting></para>
|
|
|
|
<para>You may notice similarities with the way
|
|
<literal>FilterSecurityInterceptor</literal> is declared. Both regular
|
|
expressions and Ant Paths are supported, and the most specific URIs
|
|
appear first. At runtime the <literal>FilterChainProxy</literal> 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
|
|
<literal>FilterChain</literal> behaviour being respected (a
|
|
<literal>Filter</literal> can elect not to proceed with the chain if
|
|
it wishes to end processing).</para>
|
|
|
|
<para>As you can see, <literal>FilterChainProxy</literal> requires the
|
|
duplication of filter names for different request patterns (in the
|
|
above example, <literal>exceptionTranslationFilter</literal> and
|
|
<literal>filterSecurityInterceptor</literal> are duplicated). This
|
|
design decision was made to enable <literal>FilterChainProxy</literal>
|
|
to specify different <literal>Filter</literal> invocation orders for
|
|
different URI patterns, and also to improve both the expressiveness
|
|
(in terms of regular expressions, Ant Paths, and any custom
|
|
<literal>FilterInvocationDefinitionSource</literal> implementations)
|
|
and clarity of which <literal>Filter</literal>s should be
|
|
invoked.</para>
|
|
|
|
<para>You may have noticed we have declared two
|
|
<literal>HttpSessionContextIntegrationFilter</literal>s in the filter
|
|
chain (<literal>ASC</literal> is short for
|
|
<literal>allowSessionCreation</literal>, a property of
|
|
<literal>HttpSessionContextIntegrationFilter</literal>). As web
|
|
services will never present a <literal>jsessionid</literal> on future
|
|
requests, creating <literal>HttpSession</literal>s 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
|
|
<literal>HttpSessionContextIntegrationFilter</literal> (with its
|
|
default <literal>allowSessionCreation</literal> as
|
|
<literal>true</literal>) would likely be sufficient.</para>
|
|
|
|
<para>In relation to lifecycle issues, the
|
|
<literal>FilterChainProxy</literal> will always delegate
|
|
<literal>init(FilterConfig)</literal> and <literal>destroy()</literal>
|
|
methods through to the underlaying <literal>Filter</literal>s if such
|
|
methods are called against <literal>FilterChainProxy</literal> itself.
|
|
In this case, <literal>FilterChainProxy</literal> guarantees to only
|
|
initialize and destroy each <literal>Filter</literal> once,
|
|
irrespective of how many times it is declared by the
|
|
<literal>FilterInvocationDefinitionSource</literal>. You control the
|
|
overall choice as to whether these methods are called or not via the
|
|
<literal>lifecycle</literal> initialization parameter of the
|
|
<literal>FilterToBeanProxy</literal> that proxies
|
|
<literal>FilterChainProxy</literal>. As discussed above, by default
|
|
any servlet container lifecycle invocations are not delegated through
|
|
to <literal>FilterChainProxy</literal>.</para>
|
|
|
|
<para>You can also omit a URI pattern from the filter chain by using
|
|
the token <literal>#NONE#</literal> on the right-hand side of the
|
|
<literal><URI Pattern> = <Filter Chain></literal>
|
|
expression. For example, using the example above, if you wanted to
|
|
exclude the <filename>/webservices</filename> location completely, you
|
|
would modify the corresponding line in the bean declaration to be
|
|
<programlisting>
|
|
/webServices/**=#NONE#
|
|
</programlisting> Note that anything matching this path will then have
|
|
no authentication or authorization services applied and will be freely
|
|
accessible.</para>
|
|
|
|
<para>The order that filters are defined in <literal>web.xml</literal>
|
|
is very important. Irrespective of which filters you are actually
|
|
using, the order of the <literal><filter-mapping></literal>s
|
|
should be as follows:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para><literal>ChannelProcessingFilter</literal>, because it might
|
|
need to redirect to a different protocol</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>ConcurrentSessionFilter</literal>, because it
|
|
doesn't use any <literal>SecurityContextHolder</literal>
|
|
functionality but needs to update the
|
|
<literal>SessionRegistry</literal> to reflect ongoing requests
|
|
from the principal</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>HttpSessionContextIntegrationFilter</literal>, so a
|
|
<literal>SecurityContext</literal> can be setup in the
|
|
<literal>SecurityContextHolder</literal> at the beginning of a web
|
|
request, and any changes to the <literal>SecurityContext</literal>
|
|
can be copied to the <literal>HttpSession</literal> when the web
|
|
request ends (ready for use with the next web request)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Authentication processing mechanisms -
|
|
<literal>AuthenticationProcessingFilter</literal>,
|
|
<literal>CasProcessingFilter</literal>,
|
|
<literal>BasicProcessingFilter, HttpRequestIntegrationFilter,
|
|
JbossIntegrationFilter</literal> etc - so that the
|
|
<literal>SecurityContextHolder</literal> can be modified to
|
|
contain a valid <literal>Authentication</literal> request
|
|
token</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The
|
|
<literal>SecurityContextHolderAwareRequestFilter</literal>, if you
|
|
are using it to install a Spring Security aware
|
|
<literal>HttpServletRequestWrapper</literal> into your servlet
|
|
container</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>RememberMeProcessingFilter</literal>, so that if no
|
|
earlier authentication processing mechanism updated the
|
|
<literal>SecurityContextHolder</literal>, and the request presents
|
|
a cookie that enables remember-me services to take place, a
|
|
suitable remembered
|
|
<literal><literal>Authentication</literal></literal> object will
|
|
be put there</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>AnonymousProcessingFilter</literal>, so that if no
|
|
earlier authentication processing mechanism updated the
|
|
<literal>SecurityContextHolder</literal>, an anonymous
|
|
<literal>Authentication</literal> object will be put there</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>ExceptionTranslationFilter</literal>, to catch any
|
|
Spring Security exceptions so that either an HTTP error response
|
|
can be returned or an appropriate
|
|
<literal>AuthenticationEntryPoint</literal> can be launched</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>FilterSecurityInterceptor</literal>, to protect web
|
|
URIs</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>All of the above filters use
|
|
<literal>FilterToBeanProxy</literal> or
|
|
<literal>FilterChainProxy</literal>. It is recommended that a single
|
|
<literal>FilterToBeanProxy</literal> proxy through to a single
|
|
<literal>FilterChainProxy</literal> for each application, with that
|
|
<literal>FilterChainProxy</literal> defining all of Spring Security
|
|
<literal>Filter</literal>s.</para>
|
|
|
|
<para>If you're using SiteMesh, ensure Spring Security filters execute
|
|
before the SiteMesh filters are called. This enables the
|
|
<literal>SecurityContextHolder</literal> to be populated in time for
|
|
use by SiteMesh decorators</para>
|
|
</sect1>
|
|
</chapter> |