Move docs on request matching to correct file and delete unused one

This commit is contained in:
Luke Taylor 2010-11-24 00:19:08 +00:00
parent 49242729e4
commit 89f80659a1
2 changed files with 88 additions and 339 deletions

View File

@ -48,16 +48,18 @@
</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 Secuirity's <classname>FilterChainProxy</classname> comes in. It is
wired using a <literal>DelegatingFilterProxy</literal>, just like in the example above,
but with the <literal>filter-name</literal> set to the bean name
<para>Spring Security's web infrastructure should only be used by delegating to an
instance of <classname>FilterChainProxy</classname>. The security filters should not
be used by themselves. In theory you could 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, but this would be
cumbersome and would clutter up the <filename>web.xml</filename> file quickly if you
have a lot of filters. <classname>FilterChainProxy</classname> lets us add a single
entry to <filename>web.xml</filename> and deal entirely with the application context
file for managing our web security beans. It is wired using a
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with
the <literal>filter-name</literal> set to the bean name
<quote>filterChainProxy</quote>. The filter chain is then declared in the application
context with the same bean name. Here's an example: <programlisting language="xml"><![CDATA[
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
@ -98,6 +100,10 @@
<classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para>
<para>Note that <classname>FilterChainProxy</classname> does not invoke standard filter
lifecycle methods on the filters it is configured with. We recommend you use
Spring's application context lifecycle interfaces as an alternative, just as you
would for any other Spring bean.</para>
<para> When we looked at how to set up web security using <link xlink:href="#ns-web-xml"
>namespace configuration</link>, we used a <literal>DelegatingFilterProxy</literal> with
the name <quote>springSecurityFilterChain</quote>. You should now be able to see that
@ -183,6 +189,78 @@
</listitem>
</orderedlist></para>
</section>
<section xml:id="request-matching">
<title>Request Matching and <interfacename>HttpFirewall</interfacename></title>
<para>Spring Security has several areas where patterns you have defined are tested
against incoming requests in order to decide how the request should be handled. This
occurs when the <classname>FilterChainProxy</classname> decides which filter chain a
request should be passed through and also when the
<classname>FilterSecurityInterceptor</classname> decides which security constraints
apply to a request. It's important to understand what the mechanism is and what URL
value is used when testing against the patterns that you define.</para>
<para>The Servlet Specification defines several properties for the
<interfacename>HttpServletRequest</interfacename> which are accessible via getter
methods, and which we might want to match against. These are the
<literal>contextPath</literal>, <literal>servletPath</literal>,
<literal>pathInfo</literal> and <literal>queryString</literal>. Spring Security is
only interested in securing paths within the application, so the
<literal>contextPath</literal> is ignored. Unfortunately, the servlet spec does not
define exactly what the values of <literal>servletPath</literal> and
<literal>pathInfo</literal> will contain for a particular request URI. For example,
each path segment of a URL may contain parameters, as defined in <link
xlink:href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</link><footnote>
<para>You have probably seen this when a browser doesn't support cookies and the
<literal>jsessionid</literal> parameter is appended to the URL after a
semi-colon. However the RFC allows the presence of these parameters in any path
segment of the URL</para>
</footnote>. The Specification does not clearly state whether these should be
included in the <literal>servletPath</literal> and <literal>pathInfo</literal>
values and the behaviour varies between different servlet containers. There is a
danger that when an application is deployed in a container which does not strip path
parameters from these values, an attacker could add them to the requested URL in
order to cause a pattern match to succeed or fail unexpectedly.<footnote>
<para>The original values will be returned once the request leaves the
<classname>FilterChainProxy</classname>, so will still be available to the
application.</para>
</footnote>. Other variations in the incoming URL are also possible. For example, it
could contain path-traversal sequences (like <literal>/../</literal>) or multiple
forward slashes (<literal>//</literal>) which could also cause pattern-matches to
fail. Some containers normalize these out before performing the servlet mapping, but
others don't. To protect against issues like these,
<classname>FilterChainProxy</classname> uses an
<interfacename>HttpFirewall</interfacename> strategy to check and wrap the request.
Un-normalized requests are automatically rejected by default, and path parameters
and duplicate slashes are removed for matching purposes.<footnote>
<para>So, for example, an original request path
<literal>/secure;hack=1/somefile.html;hack=2</literal> will be returned as
<literal>/secure/somefile.html</literal>.</para>
</footnote>. It is therefore essential that a
<classname>FilterChainProxy</classname> is used to manage the security filter chain.
Note that the <literal>servletPath</literal> and <literal>pathInfo</literal> values
are decoded by the container, so your application should not have any valid paths
which contain semi-colons, as these parts will be removed for matching purposes. </para>
<para>As mentioned above, the default strategy is to use Ant-style paths for matching
and this is likely to be the best choice for most users. The strategy is implemented
in the class <classname>AntPathRequestMatcher</classname> which uses Spring's
<classname>AntPathMatcher</classname> to perform a case-insensitive match of the
pattern against the concatenated <literal>servletPath</literal> and
<literal>pathInfo</literal>, ignoring the <literal>queryString</literal>.</para>
<para>If for some reason, you need a more powerful matching strategy, you can use
regular expressions. The strategy implementation is then
<classname>RegexRequestMatcher</classname>. See the Javadoc for this class for more
information.</para>
<para>In practice we recommend that you use method security at your service layer, to
control access to your application, and do not rely entirely on the use of security
constraints defined at the web-application level. URLs change and it is difficult to
take account of all the possible URLs that an application might support and how
requests might be manipulated. You should try and restrict yourself to using a few
simple ant paths which are simple to understand. Always try to use a
<quote>deny-by-default</quote> approach where you have a catch-all wildcard
(<literal>/**</literal> or <literal>**</literal>) defined last and denying access.</para>
<para>Security defined at the service layer is much more robust and harder to bypass, so
you should always take advantage of Spring Security's method security
options.</para>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using some other framework that is also filter-based, then you need to make

View File

@ -1,329 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Web Application Infrastructure</title>
</info>
<section xml:id="filters">
<title>The Security Filter Chain</title>
<para>Spring 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
<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 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 <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>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting> 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>Spring Security's web infrastructure should only be used by delegating to an
instance of <classname>FilterChainProxy</classname>. The security filters should not
be used by themselves In theory you could 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, but this would be
cumbersome and would clutter up the <filename>web.xml</filename> file quickly if you
have a lot of filters. <classname>FilterChainProxy</classname> lets us add a single
entry to <filename>web.xml</filename> and deal entirely with the application context
file for managing our web security beans. It is wired using a
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with
the <literal>filter-name</literal> set to the bean name
<quote>filterChainProxy</quote>. The filter chain is then declared in the
application context with the same bean name. 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="
securityContextPersistenceFilterWithASCFalse,
basicProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
<sec:filter-chain pattern="/**" filters="
securityContextPersistenceFilterWithASCTrue,
authenticationProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
</sec:filter-chain-map>
</bean>
]]>
</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<footnote>
<para>Note that you'll need to include the security namespace in your application
context XML file in order to use this syntax.</para>
</footnote>. 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 URLs appear first. At
runtime the <classname>FilterChainProxy</classname> will locate the first URL
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>Note that <classname>FilterChainProxy</classname> does not invoke standard filter
lifecycle methods on the filters it is configured with. We recommend you use
Spring's application context lifecycle interfaces as an alternative, just as you
would for any other Spring bean.</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> 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. If you want to make use of the contents of the
<classname>SecurityContext</classname> contents during a request, then it must
have passed through the security filter chain. Otherwise the
<classname>SecurityContextHolder</classname> will not have been populated and
the contents will be null.</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 should be as follows: <orderedlist>
<listitem>
<para><classname>ChannelProcessingFilter</classname>, because it might need to
redirect to a different protocol</para>
</listitem>
<listitem>
<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 from the principal</para>
</listitem>
<listitem>
<para><classname>SecurityContextPersistenceFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be set up in the
<classname>SecurityContextHolder</classname> at the beginning of a web
request, and any changes to the
<interfacename>SecurityContext</interfacename> 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 -
<classname>UsernamePasswordAuthenticationFilter</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>
</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><classname>RememberMeProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, and the request presents a
cookie that enables remember-me services to take place, a suitable
remembered <interfacename>Authentication</interfacename> object will be put
there</para>
</listitem>
<listitem>
<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>
</listitem>
<listitem>
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring
Security exceptions so that either an HTTP error response can be returned or
an appropriate <interfacename>AuthenticationEntryPoint</interfacename> can
be launched</para>
</listitem>
<listitem>
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and
raise exceptions when access is denied</para>
</listitem>
</orderedlist></para>
</section>
<section xml:id="request-matching">
<title>Request Matching and <interfacename>HttpFirewall</interfacename></title>
<para>Spring Security has several areas where patterns you have defined are tested
against incoming requests in order to decide how the request should be handled. This
occurs when the <classname>FilterChainProxy</classname> decides which filter chain a
request should be passed through and also when the
<classname>FilterSecurityInterceptor</classname> decides which security constraints
apply to a request. It's important to understand what the mechanism is and what URL
value is used when testing against the patterns that you define.</para>
<para>The Servlet Specification defines several properties for the
<interfacename>HttpServletRequest</interfacename> which are accessible via getter
methods, and which we might want to match against. These are the
<literal>contextPath</literal>, <literal>servletPath</literal>,
<literal>pathInfo</literal> and <literal>queryString</literal>. Spring Security is
only interested in securing paths within the application, so the
<literal>contextPath</literal> is ignored. Unfortunately, the servlet spec does not
define exactly what the values of <literal>servletPath</literal> and
<literal>pathInfo</literal> will contain for a particular request URI. For example,
each path segment of a URL may contain parameters, as defined in <link
xlink:href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</link><footnote>
<para>You have probably seen this when a browser doesn't support cookies and the
<literal>jsessionid</literal> parameter is appended to the URL after a
semi-colon. However the RFC allows the presence of these parameters in any path
segment of the URL</para>
</footnote>. The Specification does not clearly state whether these should be
included in the <literal>servletPath</literal> and <literal>pathInfo</literal>
values and the behaviour varies between different servlet containers. There is a
danger that when an application is deployed in a container which does not strip path
parameters from these values, an attacker could add them to the requested URL in
order to cause a pattern match to succeed or fail unexpectedly.<footnote>
<para>The original values will be returned once the request leaves the
<classname>FilterChainProxy</classname>, so will still be available to the
application.</para>
</footnote>. Other variations in the incoming URL are also possible. For example, it
could contain path-traversal sequences (like <literal>/../</literal>) or multiple
forward slashes (<literal>//</literal>) which could also cause pattern-matches to
fail. Some containers normalize these out before performing the servlet mapping, but
others don't. To protect against issues like these,
<classname>FilterChainProxy</classname> uses an
<interfacename>HttpFirewall</interfacename> strategy to check and wrap the request.
Un-normalized requests are automatically rejected by default, and path parameters
and duplicate slashes are removed for matching purposes.<footnote>
<para>So, for example, an original request path
<literal>/secure;hack=1/somefile.html;hack=2</literal> will be returned as
<literal>/secure/somefile.html</literal>.</para>
</footnote>. It is therefore essential that a
<classname>FilterChainProxy</classname> is used to manage the security filter chain.
Note that the <literal>servletPath</literal> and <literal>pathInfo</literal> values
are decoded by the container, so your application should not have any valid paths
which contain semi-colons, as these parts will be removed for matching purposes. </para>
<para>As mentioned above, the default strategy is to use Ant-style paths for matching
and this is likely to be the best choice for most users. The strategy is implemented
in the class <classname>AntPathRequestMatcher</classname> which uses Spring's
<classname>AntPathMatcher</classname> to perform a case-insensitive match of the
pattern against the concatenated <literal>servletPath</literal> and
<literal>pathInfo</literal>, ignoring the <literal>queryString</literal>.</para>
<para>If for some reason, you need a more powerful matching strategy, you can use
regular expressions. The strategy implementation is then
<classname>RegexRequestMatcher</classname>. See the Javadoc for this class for more
information.</para>
<para>In practice we recommend that you use method security at your service layer, to
control access to your application, and do not rely entirely on the use of security
constraints defined at the web-application level. URLs change and it is difficult to
take account of all the possible URLs that an application might support and how
requests might be manipulated. You should try and restrict yourself to using a few
simple ant paths which are simple to understand. Always try to use a
<quote>deny-by-default</quote> approach where you have a catch-all wildcard
(<literal>/**</literal>) defined last and denying access.</para>
<para>Security defined at the service layer is much more robust and harder to bypass, so
you should always take advantage of Spring Security's method security
options.</para>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If 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
<classname>SecurityContextHolder</classname> 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. </para>
</section>
</section>
<!--
<section xml:id="taglib">
<info>
<title>Tag Libraries</title>
</info>
<para>Spring Security comes bundled with several JSP tag libraries which provide a range of
different services.</para>
<section xml:id="taglib-config">
<info>
<title>Configuration</title>
</info>
<para>All taglib classes are included in the core
<literal>spring-security-taglibs-&lt;version>.jar</literal> file, with the
<literal>security.tld</literal> located in the JAR's <literal>META-INF</literal>
directory. This means for JSP 1.2+ web containers you can simply include the JAR in the
WAR's <literal>WEB-INF/lib</literal> directory and it will be available.</para>
</section>
<section xml:id="taglib-usage">
<info>
<title>Usage</title>
</info>
<para>Now that you've configured the tag libraries, refer to the individual reference guide
sections for details on how to use them. Note that when using the tags, you should include
the taglib reference in your JSP:
<programlisting>
&lt;%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %&gt;
</programlisting></para>
</section>
</section>
<section xml:id="authentication-taglibs">
<info>
<title>Authentication Tag Libraries</title>
</info>
<para><literal>AuthenticationTag</literal> is used to simply output a property of the current
<interfacename>Authentication</interfacename> object to the web page.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AuthenticationTag</literal>:</para>
<para>
<programlisting>&lt;security:authentication property="principal.username"/&gt;</programlisting>
</para>
<para>This tag would cause the principal's name to be output. Here we are assuming the
<literal>Authentication.getPrincipal()</literal> is a
<interfacename>UserDetails</interfacename> object, which is generally the case when using
one of Spring Security's stadard <classname>AuthenticationProvider</classname>
implementations.</para>
</section>
-->
</chapter>