manual updates

This commit is contained in:
Luke Taylor 2009-06-11 16:45:41 +00:00
parent 3f603dfdd8
commit d5aec71fac
3 changed files with 206 additions and 216 deletions

View File

@ -97,8 +97,23 @@
Security.</para>
</partintro>
<xi:include href="technical-overview.xml"/>
<xi:include href="supporting-infrastructure.xml"/>
<xi:include href="channel-security.xml"/>
<!--xi:include href="supporting-infrastructure.xml"/-->
<!-- xi:include href="channel-security.xml"/ -->
</part>
<part xml:id="webapp-security" >
<title>Web Application Security</title>
<partintro>
<para>
Most Spring Security users will be using the framework in enterprise applications which
make user of the HTTP and the Servlet API. In this part we'll take a look at how Spring Security provides
authentication and access-control features for the web layer of an application. We'll look
behind the facade of the namespace and see which classes and interfaces are actually assembled to provide web-layer
security. In some situations it is necessary to use traditional bean configuration to provide full control over
the configuration, so we'll also see how to configure these classes directly without the namespace.
</para>
</partintro>
<xi:include href="supporting-infrastructure.xml"/>
</part>
<part xml:id="authentication">
<title>Authentication</title>

View File

@ -1,97 +1,32 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="supporting-infrastructure" xmlns:xlink="http://www.w3.org/1999/xlink">
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Supporting Infrastructure</title></info>
<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>
<section xml: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>spring-security-core-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 Spring 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><![CDATA[
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="org/springframework/security/messages"/>
</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>
</section>
<info><title>Web Security Infrastructure</title></info>
<section xml:id="filters">
<info><title>Filters</title></info>
<title>Spring Security Filters</title>
<para>Spring Security uses many filters, as referred to throughout the
remainder of this reference guide. If you are using <link xlink:href="#ns-config">namespace configuration</link>,
then the you don't usually have to declare the filter beans explicitly. There 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.</para>
<para>In this case, you have a choice in how these filters are added to your web application, in that you can use either
Spring's <literal>DelegatingFilterProxy</literal> or
<classname>FilterChainProxy</classname>. We'll look at both below.</para>
<para>When using <literal>DelegatingFilterProxy</literal>, you will see
something like this in the web.xml file:
<para>Spring Security's web application features are implemented using 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 <classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
and doesn't care whether the requests come from a browser, a web service client, an <classname>HttpInvoker</classname> or an AJAX application.
</para>
<para>
Spring Security maintains a filter chain internally where each of the filters has a particular responsibility and filters are added or removed
depending on which services are required. The ordering of the filters is important as there are dependencies between them.
If you have been using <link xlink:href="#ns-config">namespace configuration</link>, 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.</para>
<section xml:id="delegating-filter-proxy">
<title><classname>DelegatingFilterProxy</classname></title>
<para>
When using servlet filters, you obviously need to declare them in your <filename>web.xml</filename>, 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 <classname>DelegatingFilterProxy</classname>
provides the link between <filename>web.xml</filename> and the application context.
</para>
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like this in the <filename>web.xml</filename> file:
<programlisting><![CDATA[
<filter>
<filter-name>myFilter</filter-name>
@ -103,132 +38,111 @@
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting>
Notice that the filter is actually a <literal>DelegatingFilterProxy</literal>,
and not the filter that will actually implement the logic of the filter. What
<literal>DelegatingFilterProxy</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 web application context lifecycle support and
configuration flexibility. The bean must implement
<literal>javax.servlet.Filter</literal> and it must have the same name as that in
the <literal>filter-name</literal> element.</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. Read the Javadoc for <classname>DelegatingFilterProxy</classname>
for more information</para>
<para>Rather than using <literal>DelegatingFilterProxy</literal>, we
strongly recommend that you use <classname>FilterChainProxy</classname> instead.
Whilst <literal>DelegatingFilterProxy</literal> is a very useful class,
the problem is that the number of lines of code required for
<literal>&lt;filter&gt;</literal> and
<literal>&lt;filter-mapping&gt;</literal> entries in
<literal>web.xml</literal> explodes when using more than a few
filters. To overcome this issue, Spring Security provides a
<classname>FilterChainProxy</classname> class. It is wired using a
<literal>DelegatingFilterProxy</literal> (just like in the example above),
but the target class is
<literal>org.springframework.security.web.FilterChainProxy</literal>.
The filter chain is then declared in the application context, using
code such as this:</para>
<para><programlisting><![CDATA[
Notice that the filter is actually a <literal>DelegatingFilterProxy</literal>,
and not the class that will actually implement the logic of the filter. What
<classname>DelegatingFilterProxy</classname> does is delegate the
<interfacename>Filter</interfacename>'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
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that in
the <literal>filter-name</literal> element. Read the Javadoc for <classname>DelegatingFilterProxy</classname>
for more information</para>
</section>
<section xml:id="filter-chain-proxy">
<title><classname>FilterChainProxy</classname></title>
<para>
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
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for each filter, making sure that they are ordered correctly.
This is a cumbersome approach and clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We would prefer to just add
a single entry to <filename>web.xml</filename> and deal entirely with the application context file for managing our web security beans.
This is where Spring Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a <literal>DelegatingFilterProxy</literal>
(just like in the example above), but the target class is <classname>org.springframework.security.web.FilterChainProxy</classname>.
The filter chain is then declared in the application context. Here's an example:
<programlisting language="xml"><![CDATA[
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters="
httpSessionContextIntegrationFilterWithASCFalse,
securityContextPersistenceFilterWithASCFalse,
basicProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
<sec:filter-chain pattern="/**" filters="
httpSessionContextIntegrationFilterWithASCTrue,
securityContextPersistenceFilterWithASCTrue,
authenticationProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
</sec:filter-chain-map>
</bean>
]]>
</programlisting></para>
<para>You may notice similarities with the way
<classname>FilterSecurityInterceptor</classname> is declared. Both regular
expressions and Ant Paths are supported, and the most specific URIs
appear first. At runtime the <classname>FilterChainProxy</classname> will
locate the first URI pattern that matches the current web request and the list
of filter beans specified by the <literal>filters</literal> 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.</para>
<para>You may have noticed we have declared two
<classname>HttpSessionContextIntegrationFilter</classname>s in the filter
chain (<literal>ASC</literal> is short for
<literal>allowSessionCreation</literal>, a property of
<classname>HttpSessionContextIntegrationFilter</classname>). 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
<classname>HttpSessionContextIntegrationFilter</classname> (with its
default <literal>allowSessionCreation</literal> as
<literal>true</literal>) would likely be sufficient.</para>
<para>In relation to lifecycle issues, the
<classname>FilterChainProxy</classname> 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 <classname>FilterChainProxy</classname> itself.
In this case, <classname>FilterChainProxy</classname> guarantees to only
initialize and destroy each <literal>Filter</literal> once,
irrespective of how many times it is declared by the
<interfacename>FilterInvocationDefinitionSource</interfacename>. You control the
overall choice as to whether these methods are called or not via the
<literal>targetFilterLifecycle</literal> initialization parameter of the
<literal>DelegatingFilterProxy</literal> that proxies
<literal>DelegatingFilterProxy</literal>. As discussed above, by default
any servlet container lifecycle invocations are not delegated through
to <literal>DelegatingFilterProxy</literal>.</para>
<para>You can use the attribute <literal>filters = "none"</literal>
in the same way that you do when using <link xlink:href="#namespace-auto-config">namespace configuration</link>
to build the <classname>FilterChainProxy</classname>. 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.</para>
<para>The order that filters are defined in <literal>web.xml</literal>
</programlisting>
The namespace element <literal>filter-chain-map</literal> is used to set up the security filter chain(s) which are required
within the application. It maps a particular URL pattern to a chain of filters built up from the bean names
specified in the <literal>filters</literal> element. Both regular
expressions and Ant Paths are supported, and the most specific URIs
appear first. At runtime the <classname>FilterChainProxy</classname> will
locate the first URI pattern that matches the current web request and the list
of filter beans specified by the <literal>filters</literal> 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.</para>
<para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter
chain (<literal>ASC</literal> is short for
<literal>allowSessionCreation</literal>, a property of
<classname>SecurityContextPersistenceFilter</classname>). 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
<classname>SecurityContextPersistenceFilter</classname> (with its
default <literal>allowSessionCreation</literal> as
<literal>true</literal>) would likely be sufficient.</para>
<para>In relation to lifecycle issues, the
<classname>FilterChainProxy</classname> will always delegate
<methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
methods through to the underlaying <interfacename>Filter</interfacename>s if such
methods are called against <classname>FilterChainProxy</classname> itself.
In this case, <classname>FilterChainProxy</classname> guarantees to only
initialize and destroy each <literal>Filter</literal> 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
<literal>targetFilterLifecycle</literal> initialization parameter of
<literal>DelegatingFilterProxy</literal>. By default this property
is <literal>false</literal> and servlet container lifecycle invocations are not delegated through
<literal>DelegatingFilterProxy</literal>.</para>
<para>
When we looked at how to set up web security using <link xlink:href="#namespace-auto-config">namespace configuration</link>,
we used a <literal>DelegatingFilterProxy</literal> with the name <quote>springSecurityFilterChain</quote>. You should now be able to
see that this is the name of the <classname>FilterChainProxy</classname> which is created by the namespace.
</para>
<section>
<title>Bypassing the Filter Chain</title>
<para>
As with the namespace, you can use the attribute <literal>filters = "none"</literal> 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.
</para>
</section>
</section>
<section>
<title>Filter Ordering</title>
<para>The order that filters are defined in the chain
is very important. Irrespective of which filters you are actually
using, the order of the <literal>&lt;filter-mapping&gt;</literal>s
should be as follows:</para>
using, the order should be as follows:
<orderedlist inheritnum="ignore" continuation="restarts">
<listitem>
<para><literal>ChannelProcessingFilter</literal>, because it might
<para><classname>ChannelProcessingFilter</classname>, because it might
need to redirect to a different protocol</para>
</listitem>
<listitem>
<para><literal>ConcurrentSessionFilter</literal>, because it
<para><classname>ConcurrentSessionFilter</classname>, because it
doesn't use any <classname>SecurityContextHolder</classname>
functionality but needs to update the
<interfacename>SessionRegistry</interfacename> to reflect ongoing requests
@ -236,7 +150,7 @@
</listitem>
<listitem>
<para><classname>HttpSessionContextIntegrationFilter</classname>, so a
<para><classname>SecurityContextPersistenceFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be setup in the
<classname>SecurityContextHolder</classname> at the beginning of a web
request, and any changes to the <interfacename>SecurityContext</interfacename>
@ -246,10 +160,9 @@
<listitem>
<para>Authentication processing mechanisms -
<literal>UsernamePasswordAuthenticationProcessingFilter</literal>,
<literal>CasProcessingFilter</literal>,
<literal>BasicProcessingFilter, HttpRequestIntegrationFilter,
JbossIntegrationFilter</literal> etc - so that the
<classname>UsernamePasswordAuthenticationProcessingFilter</classname>,
<classname>CasProcessingFilter</classname>,
<classname>BasicProcessingFilter</classname> etc - so that the
<classname>SecurityContextHolder</classname> can be modified to
contain a valid <interfacename>Authentication</interfacename> request
token</para>
@ -274,7 +187,7 @@
</listitem>
<listitem>
<para><literal>AnonymousProcessingFilter</literal>, so that if no
<para><classname>AnonymousProcessingFilter</classname>, so that if no
earlier authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, an anonymous
<interfacename>Authentication</interfacename> object will be put there</para>
@ -292,21 +205,20 @@
URIs</para>
</listitem>
</orderedlist>
<para>All of the above filters use
<literal>DelegatingFilterProxy</literal> or
<classname>FilterChainProxy</classname>. It is recommended that a single
<literal>DelegatingFilterProxy</literal> proxy through to a single
<classname>FilterChainProxy</classname> for each application, with that
<classname>FilterChainProxy</classname> defining all of Spring Security
filters.</para>
<para>If you're using SiteMesh, ensure Spring Security filters execute
before the SiteMesh filters are called. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for
use by SiteMesh decorators</para>
</para>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using SiteMesh, ensure Spring Security filters execute
before the SiteMesh filters are called. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for
use by SiteMesh decorators.</para>
</section>
</section>
<section xml:id="taglib">
<info><title>Tag Libraries</title></info>

View File

@ -580,4 +580,67 @@ Successfully authenticated. Security context contains: \
</section>
</section>
</section>
<section xml: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-speaking 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>spring-security-core-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 Spring 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><![CDATA[
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="org/springframework/security/messages"/>
</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
<classname>org.springframework.context.i18n.LocaleContextHolder</classname>.
You should set the <classname>LocaleContextHolder</classname> 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 the Spring Framework documentation
for further details on using <literal>LocaleContextHolder</literal>.</para>
</section>
</chapter>