瀏覽代碼

SEC-1584: Doc updates to explain request matching process.

Luke Taylor 15 年之前
父節點
當前提交
161710cc87
共有 2 個文件被更改,包括 200 次插入74 次删除
  1. 5 1
      docs/manual/src/docbook/namespace-config.xml
  2. 195 73
      docs/manual/src/docbook/web-infrastructure.xml

+ 5 - 1
docs/manual/src/docbook/namespace-config.xml

@@ -129,7 +129,11 @@
           <literal>&lt;http></literal> element is the parent for all web-related namespace
         functionality. The <literal>&lt;intercept-url></literal> element defines a
           <literal>pattern</literal> which is matched against the URLs of incoming requests using an
-        ant path style syntax. The <literal>access</literal> attribute defines the access
+        ant path style syntax<footnote>
+          <para>See the section on <link xlink:href="#request-matching">Request
+              Matching</link> in the Web Application Infrastructure chapter for more details
+              on how matches are actually performed.</para>
+          </footnote>. The <literal>access</literal> attribute defines the access
         requirements for requests matching the given pattern. With the default configuration, this
         is typically a comma-separated list of roles, one of which a user must have to be allowed to
         make the request. The prefix <quote>ROLE_</quote> is a marker which indicates that a simple

+ 195 - 73
docs/manual/src/docbook/web-infrastructure.xml

@@ -40,29 +40,32 @@
     <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> 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 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[
+                <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="
@@ -78,56 +81,175 @@
   </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 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. 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>
+      </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>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. 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</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. 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> value
+                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. Spring Security's
+                <classname>FilterChainProxy</classname> therefore wraps incoming requests to
+                consistently return <literal>servletPath</literal> and <literal>pathInfo</literal>
+                values which do not contain path parameters. For example, an original request path
+                <literal>/secure;hack=1/somefile.html;hack=2</literal> will be returned as
+                <literal>/secure/somefile.html</literal>. It is therefore essential that a
+                <classname>FilterChainProxy</classname> is used to manage the security filter
+                chain.</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. Matching is performed
+                a pattern against the concatenated <literal>servletPath</literal> and
+                <literal>pathInfo</literal>, ignoring the <literal>queryString</literal>, and is case insensitive by default.</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>
       <title>Filter Ordering</title>