Updated docs to reflect changes for SEC-1259

This commit is contained in:
Luke Taylor 2009-10-08 14:14:40 +00:00
parent 80eb47c6fe
commit 73905b9ebd
10 changed files with 543 additions and 623 deletions

View File

@ -47,16 +47,17 @@
principal. There is a corresponding <literal>AnonymousAuthenticationProvider</literal>,
which is chained into the <literal>ProviderManager</literal> so that
<literal>AnonymousAuthenticationToken</literal>s are accepted. Finally, there is an
AnonymousProcessingFilter, which is chained after the normal authentication mechanisms
and automatically adds an <literal>AnonymousAuthenticationToken</literal> to the
<classname>AnonymousAuthenticationFilter</classname>, which is chained after the
normal authentication mechanisms and automatically adds an
<literal>AnonymousAuthenticationToken</literal> to the
<classname>SecurityContextHolder</classname> if there is no existing
<interfacename>Authentication</interfacename> held there. The definition of the
filter and authentication provider appears as follows:</para>
<para>
<programlisting>
<![CDATA[
<bean id="anonymousProcessingFilter"
class="org.springframework.security.web.authentication.AnonymousProcessingFilter">
<bean id="anonymousAuthFilter"
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<property name="key" value="foobar"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
@ -68,10 +69,10 @@
</programlisting>
</para>
<para>The <literal>key</literal> is shared between the filter and authentication provider,
so that tokens created by the former are accepted by the latter<footnote>
<para>The use of the <literal>key</literal> property should not be regarded as
providing any real security here. It is merely a book-keeping exercise. If you
are sharing a <classname>ProviderManager</classname> which contains an
so that tokens created by the former are accepted by the latter<footnote><para>The use
of the <literal>key</literal> property should not be regarded as providing any
real security here. It is merely a book-keeping exercise. If you are sharing a
<classname>ProviderManager</classname> which contains an
<classname>AnonymousAuthenticationProvider</classname> in a scenario where
it is possible for an authenticating client to construct the
<interfacename>Authentication</interfacename> object (such as with RMI
@ -82,14 +83,15 @@
anonymous provider. This isn't a problem with normal usage but if you are using
RMI you would be best to use a customized <classname>ProviderManager</classname>
which omits the anonymous provider rather than sharing the one you use for your
HTTP authentication mechanisms.</para>
</footnote>. The <literal>userAttribute</literal> is expressed in the form of
HTTP authentication mechanisms.</para></footnote>. The
<literal>userAttribute</literal> is expressed in the form of
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
This is the same syntax as used after the equals sign for
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal> property.</para>
<para>As explained earlier, the benefit of anonymous authentication is that all URI patterns
can have security applied to them. For example:</para>
<para><programlisting>
<para>
<programlisting>
<![CDATA[
<bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
@ -105,31 +107,29 @@
</security:filter-security-metadata-source>" +
</property>
</bean>]]>
</programlisting></para>
</programlisting>
</para>
</section>
<section xml:id="anonymous-auth-trust-resolver">
<title><interfacename>AuthenticationTrustResolver</interfacename></title>
<para>
Rounding out the anonymous authentication discussion is the
<interfacename>AuthenticationTrustResolver</interfacename> interface, with its corresponding
<literal>AuthenticationTrustResolverImpl</literal> implementation. This interface
provides an <literal>isAnonymous(Authentication)</literal> method, which allows
interested classes to take into account this special type of authentication status. The
<classname>ExceptionTranslationFilter</classname> uses this interface in processing
<literal>AccessDeniedException</literal>s. If an
<literal>AccessDeniedException</literal> is thrown, and the authentication is of an
<para> Rounding out the anonymous authentication discussion is the
<interfacename>AuthenticationTrustResolver</interfacename> interface, with its
corresponding <literal>AuthenticationTrustResolverImpl</literal> implementation. This
interface provides an <literal>isAnonymous(Authentication)</literal> method, which
allows interested classes to take into account this special type of authentication
status. The <classname>ExceptionTranslationFilter</classname> uses this interface in
processing <literal>AccessDeniedException</literal>s. If an
<literal>AccessDeniedException</literal> is thrown, and the authentication is of an
anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead
commence the <interfacename>AuthenticationEntryPoint</interfacename> so the principal
can authenticate properly. This is a necessary distinction, otherwise principals would
always be deemed <quote>authenticated</quote> and never be given an opportunity to login
via form, basic, digest or some other normal authentication mechanism.
</para>
<para>
You will often see the <literal>ROLE_ANONYMOUS</literal> attribute in the above interceptor configuration
replaced with <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>. This is an example of the use of the
<classname>AuthenticatedVoter</classname> which will see in ???. It uses an
<interfacename>AuthenticationTrustResolver</interfacename> to process this particular configuration
attribute and grant access to aonymous users.
via form, basic, digest or some other normal authentication mechanism. </para>
<para> You will often see the <literal>ROLE_ANONYMOUS</literal> attribute in the above
interceptor configuration replaced with <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>.
This is an example of the use of the <classname>AuthenticatedVoter</classname> which
will see in ???. It uses an <interfacename>AuthenticationTrustResolver</interfacename>
to process this particular configuration attribute and grant access to aonymous users.
</para>
</section>
</chapter>

View File

@ -62,7 +62,7 @@
<title><literal>realm</literal></title>
<para> Sets the realm name used for basic authentication (if enabled). Corresponds to the
<literal>realmName</literal> proerty on
<classname>BasicProcessingFilterEntryPoint</classname>. </para>
<classname>BasicAuthenticationEntryPoint</classname>. </para>
</section>
<section xml:id="nsa-entry-point-ref">
<title><literal>entry-point-ref</literal></title>
@ -123,7 +123,7 @@
<interfacename>FilterInvocationDefinitionSource</interfacename> used by the
<classname>FilterSecurityInterceptor</classname> and to exclude particular patterns from
the filter chain entirely (by setting the attribute <literal>filters="none"</literal>). It
is also responsible for configuring a <classname>ChannelProcessingFilter</classname> if
is also responsible for configuring a <classname>ChannelAuthenticationFilter</classname> if
particular URLs need to be accessed by HTTPS, for example. </para>
<section xml:id="nsa-pattern">
<title><literal>pattern</literal></title>
@ -149,8 +149,8 @@
accessed over HTTP or HTTPS respectively. Alternatively the value "any" can be used when
there is no preference. If this attribute is present on any
<literal>&lt;intercept-url&gt;</literal> element, then a
<classname>ChannelProcessingFilter</classname> will be added to the filter stack and its
additional dependencies added to the application context.
<classname>ChannelAuthenticationFilter</classname> will be added to the filter stack and
its additional dependencies added to the application context.
<!--See the chapter on <link
xlink:href="#channel-security-config">channel security</link> for an example
configuration using traditional beans. --></para>
@ -237,15 +237,14 @@
</section>
<section xml:id="nsa-http-basic">
<title>The <literal>&lt;http-basic&gt;</literal> Element</title>
<para> Adds a <classname>BasicProcessingFilter</classname> and
<classname>BasicProcessingFilterEntryPoint</classname> to the configuration. The latter
will only be used as the configuration entry point if form-based login is not enabled.
</para>
<para> Adds a <classname>BasicAuthenticationFilter</classname> and
<classname>BasicAuthenticationEntryPoint</classname> to the configuration. The latter will
only be used as the configuration entry point if form-based login is not enabled. </para>
</section>
<section xml:id="nsa-remember-me">
<title>The <literal>&lt;remember-me&gt;</literal> Element</title>
<para> Adds the <classname>RememberMeProcessingFilter</classname> to the stack. This in turn
will be configured with either a <classname>TokenBasedRememberMeServices</classname>, a
<para> Adds the <classname>RememberMeAuthenticationFilter</classname> to the stack. This in
turn will be configured with either a <classname>TokenBasedRememberMeServices</classname>, a
<classname>PersistentTokenBasedRememberMeServices</classname> or a user-specified bean
implementing <interfacename>RememberMeServices</interfacename> depending on the attribute
settings. </para>
@ -354,17 +353,17 @@
</section>
<section xml:id="nsa-anonymous">
<title>The <literal>&lt;anonymous&gt;</literal> Element</title>
<para> Adds an <classname>AnonymousProcessingFilter</classname> to the stack and an
<para> Adds an <classname>AnonymousAuthenticationFilter</classname> to the stack and an
<classname>AnonymousAuthenticationProvider</classname>. Required if you are using the
<literal>IS_AUTHENTICATED_ANONYMOUSLY</literal> attribute. </para>
</section>
<section xml:id="nsa-x509">
<title>The <literal>&lt;x509&gt;</literal> Element</title>
<para> Adds support for X.509 authentication. An
<classname>X509PreAuthenticatedProcessingFilter</classname> will be added to the stack and
a <classname>PreAuthenticatedProcessingFilterEntryPoint</classname> bean will be created.
The latter will only be used if no other authentication mechanisms are in use (it's only
functionality is to return an HTTP 403 error code). A
<classname>X509AuthenticationFilter</classname> will be added to the stack and an
<classname>Http403ForbiddenEntryPoint</classname> bean will be created. The latter will
only be used if no other authentication mechanisms are in use (it's only functionality is to
return an HTTP 403 error code). A
<classname>PreAuthenticatedAuthenticationProvider</classname> will also be created which
delegates the loading of user authorities to a
<interfacename>UserDetailsService</interfacename>. </para>

View File

@ -4,20 +4,21 @@
</info>
<para>Basic and digest authentiation are alternative authentication mechanisms which are popular
in web applications. Basic authentication is often used with stateless clients which pass
their credentials on each request. It's quite common to use it in combination with form-based
authentication where an application is used through both a browser-based user interface
and as a web-service. However, basic authentication transmits the password as plain text so it
should only really be used over an encrypted transport layer such as HTTPS.</para>
their credentials on each request. It's quite common to use it in combination with
form-based authentication where an application is used through both a browser-based user
interface and as a web-service. However, basic authentication transmits the password as
plain text so it should only really be used over an encrypted transport layer such as
HTTPS.</para>
<section xml:id="basic-processing-filter">
<info>
<title><classname>BasicProcessingFilter</classname></title>
<title><classname>BasicAuthenticationFilter</classname></title>
</info>
<para><literal>BasicProcessingFilter</literal> is responsible for processing basic
<para><literal>BasicAuthenticationFilter</literal> is responsible for processing basic
authentication credentials presented in HTTP headers. This can be used for
authenticating calls made by Spring remoting protocols (such as Hessian and Burlap), as
well as normal browser user agents (such as Firefox and Internet Explorer). The standard
governing HTTP Basic Authentication is defined by RFC 1945, Section 11, and
<literal>BasicProcessingFilter</literal> conforms with this RFC. Basic
<literal>BasicAuthenticationFilter</literal> conforms with this RFC. Basic
Authentication is an attractive approach to authentication, because it is very widely
deployed in user agents and implementation is extremely simple (it's just a Base64
encoding of the username:password, specified in an HTTP header).</para>
@ -26,51 +27,50 @@
<title>Configuration</title>
</info>
<para>To implement HTTP Basic Authentication, you need to add a
<literal>BasicProcessingFilter</literal> to your filter chain. The application
context should contain <literal>BasicProcessingFilter</literal> and its
required collaborator:</para>
<literal>BasicAuthenticationFilter</literal> to your filter chain. The
application context should contain <literal>BasicAuthenticationFilter</literal> and
its required collaborator:</para>
<para>
<programlisting language="xml"><![CDATA[
<bean id="basicProcessingFilter"
class="org.springframework.security.web.authentication.www.BasicProcessingFilter">
<bean id="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint">
class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="Name Of Your Realm"/>
</bean>]]>
</programlisting>
</para>
<para>The configured <interfacename>AuthenticationManager</interfacename> processes each
authentication request. If authentication fails, the configured
<interfacename>AuthenticationEntryPoint</interfacename> will be used to retry the
authentication process. Usually you will use the filter in combination with a
<literal>BasicProcessingFilterEntryPoint</literal>, which returns a 401 response
<interfacename>AuthenticationEntryPoint</interfacename> will be used to retry
the authentication process. Usually you will use the filter in combination with a
<literal>BasicAuthenticationEntryPoint</literal>, which returns a 401 response
with a suitable header to retry HTTP Basic authentication. If authentication is
successful, the resulting <interfacename>Authentication</interfacename> object will be
placed into the <classname>SecurityContextHolder</classname> as usual.</para>
successful, the resulting <interfacename>Authentication</interfacename> object will
be placed into the <classname>SecurityContextHolder</classname> as usual.</para>
<para>If the authentication event was successful, or authentication was not attempted
because the HTTP header did not contain a supported authentication request, the filter
chain will continue as normal. The only time the filter chain will be interrupted is if
authentication fails and the <interfacename>AuthenticationEntryPoint</interfacename> is
called.</para>
</section>
because the HTTP header did not contain a supported authentication request, the
filter chain will continue as normal. The only time the filter chain will be
interrupted is if authentication fails and the
<interfacename>AuthenticationEntryPoint</interfacename> is called.</para>
</section>
</section>
<section xml:id="digest-processing-filter">
<title><classname>DigestProcessingFilter</classname></title>
<para><classname>DigestProcessingFilter</classname> is capable
of processing digest authentication credentials presented in HTTP headers. Digest
Authentication attempts to solve many of the weaknesses of Basic authentication,
specifically by ensuring credentials are never sent in clear text across the wire. Many
user agents support Digest Authentication, including FireFox and Internet Explorer. The
standard governing HTTP Digest Authentication is defined by RFC 2617, which updates an
earlier version of the Digest Authentication standard prescribed by RFC 2069. Most user
agents implement RFC 2617. Spring Security's <classname>DigestProcessingFilter</classname> is
<title><classname>DigestAuthenticationFilter</classname></title>
<para><classname>DigestAuthenticationFilter</classname> is capable of processing digest
authentication credentials presented in HTTP headers. Digest Authentication attempts to
solve many of the weaknesses of Basic authentication, specifically by ensuring
credentials are never sent in clear text across the wire. Many user agents support
Digest Authentication, including FireFox and Internet Explorer. The standard governing
HTTP Digest Authentication is defined by RFC 2617, which updates an earlier version of
the Digest Authentication standard prescribed by RFC 2069. Most user agents implement
RFC 2617. Spring Security's <classname>DigestAuthenticationFilter</classname> is
compatible with the "<literal>auth</literal>" quality of protection
(<literal>qop</literal>) prescribed by RFC 2617, which also provides backward
(<literal>qop</literal>) prescribed by RFC 2617, which also provides backward
compatibility with RFC 2069. Digest Authentication is a more attractive option if you
need to use unencrypted HTTP (i.e. no TLS/HTTPS) and wish to maximise security of the
authentication process. Indeed Digest Authentication is a mandatory requirement for the
@ -88,9 +88,9 @@
key: A private key to prevent modification of the nonce token
</programlisting>
</para>
<para>The <classname>DigestProcessingFilterEntryPoint</classname> has a property specifying the
<literal>key</literal> used for generating the nonce tokens, along with a
<literal>nonceValiditySeconds</literal> property for determining the expiration time
<para>The <classname>DigestAuthenticatonEntryPoint</classname> has a property specifying the
<literal>key</literal> used for generating the nonce tokens, along with a
<literal>nonceValiditySeconds</literal> property for determining the expiration time
(default 300, which equals five minutes). Whist ever the nonce is valid, the digest is
computed by concatenating various strings including the username, password, nonce, URI
being requested, a client-generated nonce (merely a random value which the user agent
@ -98,12 +98,12 @@
server and user agent perform this digest computation, resulting in different hash codes
if they disagree on an included value (eg password). In Spring Security implementation,
if the server-generated nonce has merely expired (but the digest was otherwise valid),
the <classname>DigestProcessingFilterEntryPoint</classname> will send a
<literal>"stale=true"</literal> header. This tells the user agent there is no need
the <classname>DigestAuthenticationEntryPoint</classname> will send a
<literal>"stale=true"</literal> header. This tells the user agent there is no need
to disturb the user (as the password and username etc is correct), but simply to try
again using a new nonce.</para>
<para>An appropriate value for <classname>DigestProcessingFilterEntryPoint</classname>'s
<literal>nonceValiditySeconds</literal> parameter will depend on your application.
<para>An appropriate value for <classname>DigestAuthenticationEntryPoint</classname>'s
<literal>nonceValiditySeconds</literal> parameter will depend on your application.
Extremely secure applications should note that an intercepted authentication header can
be used to impersonate the principal until the <literal>expirationTime</literal>
contained in the nonce is reached. This is the key principle when selecting an
@ -111,28 +111,30 @@
running over TLS/HTTPS in the first instance.</para>
<para>Because of the more complex implementation of Digest Authentication, there are often
user agent issues. For example, Internet Explorer fails to present an
"<literal>opaque</literal>" token on subsequent requests in the same session. Spring
"<literal>opaque</literal>" token on subsequent requests in the same session. Spring
Security filters therefore encapsulate all state information into the
"<literal>nonce</literal>" token instead. In our testing, Spring Security's
"<literal>nonce</literal>" token instead. In our testing, Spring Security's
implementation works reliably with FireFox and Internet Explorer, correctly handling
nonce timeouts etc.</para>
<section xml:id="digest-config">
<title>Configuration</title>
<para>Now that we've reviewed the theory, let's see how to use it. To implement HTTP Digest
Authentication, it is necessary to define <literal>DigestProcessingFilter</literal> in
the fitler chain. The application context will need to define the
<literal>DigestProcessingFilter</literal> and its required collaborators:</para>
<title>Configuration</title>
<para>Now that we've reviewed the theory, let's see how to use it. To implement HTTP
Digest Authentication, it is necessary to define
<literal>DigestAuthenticationFilter</literal> in the filter chain. The
application context will need to define the
<literal>DigestAuthenticationFilter</literal> and its required
collaborators:</para>
<para>
<programlisting><![CDATA[
<bean id="digestProcessingFilter" class=
"org.springframework.security.web.authentication.www.DigestProcessingFilter">
<bean id="digestFilter" class=
"org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<property name="userDetailsService" ref="jdbcDaoImpl"/>
<property name="authenticationEntryPoint" ref="digestProcessingFilterEntryPoint"/>
<property name="authenticationEntryPoint" ref="digestEntryPoint"/>
<property name="userCache" ref="userCache"/>
</bean>
<bean id="digestProcessingFilterEntryPoint" class=
"org.springframework.security.web.authentication.www.DigestProcessingFilterEntryPoint">
<bean id="digestEntryPoint" class=
"org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
<property name="realmName" value="Contacts Realm via Digest Authentication"/>
<property name="key" value="acegi"/>
<property name="nonceValiditySeconds" value="10"/>
@ -140,31 +142,31 @@
</programlisting>
</para>
<para>The configured <interfacename>UserDetailsService</interfacename> is needed because
<literal>DigestProcessingFilter</literal> must have direct access to the clear text
password of a user. Digest Authentication will NOT work if you are using encoded
passwords in your DAO. The DAO collaborator, along with the
<literal>UserCache</literal>, are typically shared directly with a
<classname>DaoAuthenticationProvider</classname>. The
<literal>authenticationEntryPoint</literal> property must be
<classname>DigestProcessingFilterEntryPoint</classname>, so that
<classname>DigestProcessingFilter</classname> can obtain the correct
<literal>realmName</literal> and <literal>key</literal> for digest
<literal>DigestAuthenticationFilter</literal> must have direct access to the
clear text password of a user. Digest Authentication will NOT work if you are using
encoded passwords in your DAO. The DAO collaborator, along with the
<literal>UserCache</literal>, are typically shared directly with a
<classname>DaoAuthenticationProvider</classname>. The
<literal>authenticationEntryPoint</literal> property must be
<classname>DigestAuthenticationEntryPoint</classname>, so that
<classname>DigestAuthenticationFilter</classname> can obtain the correct
<literal>realmName</literal> and <literal>key</literal> for digest
calculations.</para>
<para>Like <literal>BasicAuthenticationFilter</literal>, if authentication is successful an
<interfacename>Authentication</interfacename> request token will be placed into the
<classname>SecurityContextHolder</classname>. If the authentication event was
successful, or authentication was not attempted because the HTTP header did not contain
a Digest Authentication request, the filter chain will continue as normal. The only time
the filter chain will be interrupted is if authentication fails and the
<interfacename>AuthenticationEntryPoint</interfacename> is called, as discussed in
the previous paragraph.</para>
<para>Digest Authentication's RFC offers a range of additional features to further increase
security. For example, the nonce can be changed on every request. Despite this, Spring
Security implementation was designed to minimise the complexity of the implementation
(and the doubtless user agent incompatibilities that would emerge), and avoid needing to
store server-side state. You are invited to review RFC 2617 if you wish to explore these
features in more detail. As far as we are aware, Spring Security's implementation does
comply with the minimum standards of this RFC.</para>
</section>
<para>Like <literal>BasicAuthenticationFilter</literal>, if authentication is successful
an <interfacename>Authentication</interfacename> request token will be placed into
the <classname>SecurityContextHolder</classname>. If the authentication event was
successful, or authentication was not attempted because the HTTP header did not
contain a Digest Authentication request, the filter chain will continue as normal.
The only time the filter chain will be interrupted is if authentication fails and
the <interfacename>AuthenticationEntryPoint</interfacename> is called, as discussed
in the previous paragraph.</para>
<para>Digest Authentication's RFC offers a range of additional features to further
increase security. For example, the nonce can be changed on every request. Despite
this, Spring Security implementation was designed to minimise the complexity of the
implementation (and the doubtless user agent incompatibilities that would emerge),
and avoid needing to store server-side state. You are invited to review RFC 2617 if
you wish to explore these features in more detail. As far as we are aware, Spring
Security's implementation does comply with the minimum standards of this RFC.</para>
</section>
</section>
</chapter>

View File

@ -1,60 +1,44 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CAS Authentication</title>
<section xml:id="cas-overview">
<title>Overview</title>
<para>JA-SIG produces an enterprise-wide single sign on system known
as CAS. Unlike other initiatives, JA-SIG's Central Authentication
Service is open source, widely used, simple to understand, platform
independent, and supports proxy capabilities. Spring Security fully
supports CAS, and provides an easy migration path from
single-application deployments of Spring Security through to
multiple-application deployments secured by an enterprise-wide CAS
server.</para>
<para>You can learn more about CAS at
<literal>http://www.ja-sig.org/products/cas/</literal>. You will also need
to visit this site to download the CAS Server files.</para>
<para>JA-SIG produces an enterprise-wide single sign on system known as CAS. Unlike other
initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to
understand, platform independent, and supports proxy capabilities. Spring Security fully
supports CAS, and provides an easy migration path from single-application deployments of
Spring Security through to multiple-application deployments secured by an enterprise-wide CAS
server.</para>
<para>You can learn more about CAS at <literal>http://www.ja-sig.org/products/cas/</literal>.
You will also need to visit this site to download the CAS Server files.</para>
</section>
<section xml:id="cas-how-it-works">
<info><title>How CAS Works</title></info>
<para>Whilst the CAS web site contains documents that detail
the architecture of CAS, we present the general overview again here
within the context of Spring Security. Spring Security 2.0 supports
CAS 3. At the time of writing, the CAS server was at version 3.2.</para>
<para>Somewhere in your enterprise you will need to setup a CAS
server. The CAS server is simply a standard WAR file, so there isn't
anything difficult about setting up your server. Inside the WAR file
you will customise the login and other single sign on pages displayed
to users.</para>
<info>
<title>How CAS Works</title>
</info>
<para>Whilst the CAS web site contains documents that detail the architecture of CAS, we present
the general overview again here within the context of Spring Security. Spring Security 2.0
supports CAS 3. At the time of writing, the CAS server was at version 3.2.</para>
<para>Somewhere in your enterprise you will need to setup a CAS server. The CAS server is simply
a standard WAR file, so there isn't anything difficult about setting up your server. Inside
the WAR file you will customise the login and other single sign on pages displayed to
users.</para>
<para>When deploying a CAS 3.2 server, you will also need to specify an
<literal>AuthenticationHandler</literal> in the
<filename>deployerConfigContext.xml</filename> included with CAS. The
<literal>AuthenticationHandler</literal> has a simple method that
returns a boolean as to whether a given set of Credentials is valid.
Your <literal>AuthenticationHandler</literal> implementation will need
to link into some type of backend authentication repository, such as
an LDAP server or database. CAS itself includes numerous
<literal>AuthenticationHandler</literal>s out of the box to assist
with this. When you download and deploy the server war file, it is set up
to successfully authenticate users who enter a password matching their
username, which is useful for testing.</para>
<para>Apart from the CAS server itself, the other key players are of
course the secure web applications deployed throughout your
enterprise. These web applications are known as "services". There are
two types of services: standard services and proxy services. A proxy
service is able to request resources from other services on behalf of
the user. This will be explained more fully later.</para>
<!--
<literal>AuthenticationHandler</literal> in the
<filename>deployerConfigContext.xml</filename> included with CAS. The
<literal>AuthenticationHandler</literal> has a simple method that returns a boolean as to
whether a given set of Credentials is valid. Your <literal>AuthenticationHandler</literal>
implementation will need to link into some type of backend authentication repository, such as
an LDAP server or database. CAS itself includes numerous
<literal>AuthenticationHandler</literal>s out of the box to assist with this. When you
download and deploy the server war file, it is set up to successfully authenticate users who
enter a password matching their username, which is useful for testing.</para>
<para>Apart from the CAS server itself, the other key players are of course the secure web
applications deployed throughout your enterprise. These web applications are known as
"services". There are two types of services: standard services and proxy services. A proxy
service is able to request resources from other services on behalf of the user. This will be
explained more fully later.</para>
<!--
<section xml:id="cas-sequence">
<title>Spring Security and CAS Interaction Sequence</title>
@ -260,84 +244,69 @@
</section>
-->
</section>
<section xml:id="cas-client">
<info><title>Configuration of CAS Client</title></info>
<para>The web application side of CAS is made easy due to Spring
Security. It is assumed you already know the basics of using Spring
Security, so these are not covered again below. We'll assume a namespace
based configuration is being used and add in the CAS beans as required.
</para>
<para>You will need to add a <literal>ServiceProperties</literal> bean
to your application context. This represents your service:</para>
<para><programlisting><![CDATA[
<info>
<title>Configuration of CAS Client</title>
</info>
<para>The web application side of CAS is made easy due to Spring Security. It is assumed you
already know the basics of using Spring Security, so these are not covered again below. We'll
assume a namespace based configuration is being used and add in the CAS beans as required. </para>
<para>You will need to add a <literal>ServiceProperties</literal> bean to your application
context. This represents your service:</para>
<para>
<programlisting><![CDATA[
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>]]>
</programlisting></para>
<para>The <literal>service</literal> must equal a URL that will be
monitored by the <literal>CasProcessingFilter</literal>. The
<literal>sendRenew</literal> defaults to false, but should be set to
true if your application is particularly sensitive. What this
parameter does is tell the CAS login service that a single sign on
login is unacceptable. Instead, the user will need to re-enter their
username and password in order to gain access to the service.</para>
<para>The following beans should be configured to commence the CAS
authentication process:</para>
<para><programlisting><![CDATA[
</programlisting>
</para>
<para>The <literal>service</literal> must equal a URL that will be monitored by the
<literal>CasAuthenticationFilter</literal>. The <literal>sendRenew</literal> defaults to
false, but should be set to true if your application is particularly sensitive. What this
parameter does is tell the CAS login service that a single sign on login is unacceptable.
Instead, the user will need to re-enter their username and password in order to gain access to
the service.</para>
<para>The following beans should be configured to commence the CAS authentication
process:</para>
<para>
<programlisting><![CDATA[
<security:authentication-manager alias="authenticationManager"/>
<bean id="casProcessingFilter"
class="org.springframework.security.cas.web.CasProcessingFilter">
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<security:custom-filter after="CAS_PROCESSING_FILTER"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/casfailed.jsp"/>
<property name="defaultTargetUrl" value="/"/>
</bean>
<bean id="casProcessingFilterEntryPoint"
class="org.springframework.security.cas.web.CasProcessingFilterEntryPoint">
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>
]]>
</programlisting></para>
<para>
The <classname>CasProcessingFilterEntryPoint</classname> should be selected to
drive authentication using <link xlink:href="ns-entry-point-ref"><literal>entry-point-ref</literal></link>.
</programlisting>
</para>
<para>The <literal>CasProcessingFilter</literal> has very similar
properties to the <literal>UsernamePasswordAuthenticationFilter</literal>
(used for form-based logins). Each property is
self-explanatory. Note that we've also used the namespace syntax
for setting up an alias to the authentication mnager, since the
<literal>CasProcessingFilter</literal> needs a reference to it.</para>
<para>For CAS to operate, the
<classname>ExceptionTranslationFilter</classname> must have its
<literal>authenticationEntryPoint</literal> property set to the
<literal>CasProcessingFilterEntryPoint</literal> bean.</para>
<para>The <literal>CasProcessingFilterEntryPoint</literal> must refer
to the <literal>ServiceProperties</literal> bean (discussed above),
which provides the URL to the enterprise's CAS login server. This is
where the user's browser will be redirected.</para>
<para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its
collaborators:
<programlisting><![CDATA[
<para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
authentication using <link xlink:href="ns-entry-point-ref"
><literal>entry-point-ref</literal></link>. </para>
<para>The <literal>CasAuthenticationFilter</literal> has very similar properties to the
<literal>UsernamePasswordAuthenticationFilter</literal> (used for form-based logins). Each
property is self-explanatory. Note that we've also used the namespace syntax for setting up an
alias to the authentication mnager, since the <literal>CasAuthenticationFilter</literal> needs
a reference to it.</para>
<para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have its
<literal>authenticationEntryPoint</literal> property set to the
<literal>CasAuthenticationEntryPoint</literal> bean.</para>
<para>The <literal>CasAuthenticationEntryPoint</literal> must refer to the
<literal>ServiceProperties</literal> bean (discussed above), which provides the URL to the
enterprise's CAS login server. This is where the user's browser will be redirected.</para>
<para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its collaborators: <programlisting><![CDATA[
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<security:custom-authentication-provider />
@ -355,16 +324,14 @@
<security:user name="joe" password="joe" authorities="ROLE_USER" />
...
</security:user-service>]]>
</programlisting>
The <classname>CasAuthenticationProvider</classname> uses a <interfacename>UserDetailsService</interfacename>
instance to load the authorities for a user, once they have been authentiated by CAS. We've shown a simple
in-memory setup here.
</para>
<para>The beans are all reasonable self-explanatory if you refer back
to the "How CAS Works" section.</para>
</programlisting> The
<classname>CasAuthenticationProvider</classname> uses a
<interfacename>UserDetailsService</interfacename> instance to load the authorities for a
user, once they have been authentiated by CAS. We've shown a simple in-memory setup here. </para>
<para>The beans are all reasonable self-explanatory if you refer back to the "How CAS Works"
section.</para>
</section>
<!--
<!--
<para>Note the <literal>CasProxyTicketValidator</literal> has a
remarked out <literal>trustStore</literal> property. This property
might be helpful if you experience HTTPS certificate issues. Also note
@ -462,4 +429,4 @@
</section>
-->
</chapter>
</chapter>

View File

@ -250,15 +250,15 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
<classname>ExceptionTranslationFilter</classname>.
</para></listitem><listitem><para>Implement the login page (using a JSP or
MVC controller).</para></listitem><listitem><para>Configure an instance of
<classname>UsernamePasswordAuthenticationFilter</classname> in
the application context</para></listitem><listitem><para>Add the filter bean
to your filter chain proxy (making sure you pay attention to the order).
<classname>UsernamePasswordAuthenticationFilter</classname> in the
application context</para></listitem><listitem><para>Add the filter bean to
your filter chain proxy (making sure you pay attention to the order).
<!-- TODO: link --></para></listitem></orderedlist> The login form simply
contains <literal>j_username</literal> and <literal>j_password</literal> input fields,
and posts to the URL that is monitored by the filter (by default this is
<literal>/j_spring_security_check</literal>). The basic filter configuration looks
something like this: <programlisting><![CDATA[
<bean id="authenticationProcessingFilter" class=
<bean id="authenticationFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>

View File

@ -188,7 +188,7 @@
authentication and logout handling services respectively <footnote><para>In versions prior
to 3.0, this list also included remember-me functionality. This could cause some
confusing errors with some configurations and was removed in 3.0. In 3.0, the addition
of an <classname>AnonymousProcessingFilter</classname> is part of the default
of an <classname>AnonymousAuthenticationFilter</classname> is part of the default
<literal>&lt;http></literal> configuration, so the <literal>&lt;anonymous
/></literal> element is added regardless of whether <literal>auto-config</literal>
is enabled.</para></footnote> . They each have attributes which can be used to alter
@ -472,39 +472,37 @@
align="center">Alias</entry><entry align="center">Filter Class</entry><entry
align="center">Namespace Element or
Attribute</entry></row></thead><tbody><row><entry>
CHANNEL_FILTER</entry><entry><literal>ChannelProcessingFilter</literal></entry><entry><literal>http/intercept-url</literal></entry></row><row><entry>
CHANNEL_FILTER</entry><entry><literal>ChannelProcessingFilter</literal></entry><entry><literal>http/intercept-url@requires-channel</literal></entry></row><row><entry>
CONCURRENT_SESSION_FILTER</entry><entry><literal>ConcurrentSessionFilter</literal>
</entry><entry><literal>http/concurrent-session-control</literal></entry></row><row><entry>
SESSION_CONTEXT_INTEGRATION_FILTER</entry><entry><classname>HttpSessionContextIntegrationFilter</classname></entry><entry><literal>http</literal></entry></row><row><entry>
</entry><entry><literal>session-management/concurrency-control</literal></entry></row><row><entry>
SECURITY_CONTEXT_FILTER</entry><entry><classname>SecurityContextPersistenceFilter</classname></entry><entry><literal>http</literal></entry></row><row><entry>
LOGOUT_FILTER
</entry><entry><literal>LogoutFilter</literal></entry><entry><literal>http/logout</literal></entry></row><row><entry>
X509_FILTER
</entry><entry><literal>X509PreAuthenticatedProcessigFilter</literal></entry><entry><literal>http/x509</literal></entry></row><row><entry>
</entry><entry><literal>X509AuthenticationFilter</literal></entry><entry><literal>http/x509</literal></entry></row><row><entry>
PRE_AUTH_FILTER
</entry><entry><literal>AstractPreAuthenticatedProcessingFilter</literal>
Subclasses</entry><entry>N/A</entry></row><row><entry> CAS_PROCESSING_FILTER
</entry><entry><literal>CasProcessingFilter</literal></entry><entry>N/A</entry></row><row><entry>
AUTHENTICATION_PROCESSING_FILTER
Subclasses</entry><entry>N/A</entry></row><row><entry> CAS_FILTER
</entry><entry><literal>CasAuthenticationFilter</literal></entry><entry>N/A</entry></row><row><entry>
FORM_LOGIN_FILTER
</entry><entry><literal>UsernamePasswordAuthenticationFilter</literal></entry><entry><literal>http/form-login</literal></entry></row><row><entry>
BASIC_PROCESSING_FILTER
</entry><entry><literal>BasicProcessingFilter</literal></entry><entry><literal>http/http-basic</literal></entry></row><row><entry>
SERVLET_API_SUPPORT_FILTER</entry><entry><literal>SecurityContextHolderAwareRequestFilter</literal></entry><entry><literal>http/@servlet-api-provision</literal></entry></row><row><entry>
BASIC_AUTH_FILTER
</entry><entry><literal>BasicAuthenticationFilter</literal></entry><entry><literal>http/http-basic</literal></entry></row><row><entry>
SERVLET_API_SUPPORT_FILTER</entry><entry><literal>SecurityContextHolderAwareFilter</literal></entry><entry><literal>http/@servlet-api-provision</literal></entry></row><row><entry>
REMEMBER_ME_FILTER
</entry><entry><classname>RememberMeProcessingFilter</classname></entry><entry><literal>http/remember-me</literal></entry></row><row><entry>
</entry><entry><classname>RememberMeAuthenticationFilter</classname></entry><entry><literal>http/remember-me</literal></entry></row><row><entry>
ANONYMOUS_FILTER
</entry><entry><literal>AnonymousProcessingFilter</literal></entry><entry><literal>http/anonymous</literal></entry></row><row><entry>
EXCEPTION_TRANSLATION_FILTER
</entry><entry><literal>AnonymousAuthenticationFilter</literal></entry><entry><literal>http/anonymous</literal></entry></row><row><entry>
SESSION_MANAGEMENT_FILTER</entry><entry><literal>SessionManagementFilter</literal></entry><entry><literal>session-management</literal></entry></row><row><entry>EXCEPTION_TRANSLATION_FILTER
</entry><entry><classname>ExceptionTranslationFilter</classname></entry><entry><literal>http</literal></entry></row><row><entry>
NTLM_FILTER
</entry><entry><literal>NtlmProcessingFilter</literal></entry><entry>N/A</entry></row><row><entry>
FILTER_SECURITY_INTERCEPTOR
</entry><entry><classname>FilterSecurityInterceptor</classname></entry><entry><literal>http</literal></entry></row><row><entry>
SWITCH_USER_FILTER
</entry><entry><literal>SwitchUserProcessingFilter</literal></entry><entry>N/A</entry></row></tbody></tgroup></table>
</entry><entry><literal>SwitchUserFilter</literal></entry><entry>N/A</entry></row></tbody></tgroup></table>
You can add your own filter to the stack, using the <literal>custom-filter</literal> element
and one of these names to specify the position your filter should appear at: <programlisting language="xml"><![CDATA[
<http>
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER" ref="myFilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>

View File

@ -8,150 +8,137 @@
has already been reliably authenticated by some external system prior to accessing the
application. We refer to these situations as <quote>pre-authenticated</quote> scenarios.
Examples include X.509, Siteminder and authentication by the J2EE container in which the
application is running. When using pre-authentication, Spring Security has to
<orderedlist>
<listitem>
<para>Identify the user making the request. </para>
</listitem>
<listitem>
<para>Obtain the authorities for the user.</para>
</listitem>
</orderedlist>The details will depend on the external authentication mechanism. A user might be
identified by their certificate information in the case of X.509, or by an HTTP request header
in the case of Siteminder. If relying on container authentication, the user will be identified
by calling the <methodname>getUserPrincipal()</methodname> method on the incoming HTTP request.
In some cases, the external mechanism may supply role/authority information for the user but in
others the authorities must be obtained from a separate source, such as a
<interfacename>UserDetailsService</interfacename>.
</para>
application is running. When using pre-authentication, Spring Security has to
<orderedlist><listitem><para>Identify the user making the request.
</para></listitem><listitem><para>Obtain the authorities for the
user.</para></listitem></orderedlist>The details will depend on the external authentication
mechanism. A user might be identified by their certificate information in the case of X.509, or
by an HTTP request header in the case of Siteminder. If relying on container authentication, the
user will be identified by calling the <methodname>getUserPrincipal()</methodname> method on the
incoming HTTP request. In some cases, the external mechanism may supply role/authority
information for the user but in others the authorities must be obtained from a separate source,
such as a <interfacename>UserDetailsService</interfacename>. </para>
<section>
<title>Pre-Authentication Framework Classes</title>
<para> Because most pre-authentication mechanisms follow the same pattern, Spring
Security has a set of classes which provide an internal framework for implementing
pre-authenticated authentication providers. This removes duplication and allows new
implementations to be added in a structured fashion, without having to write everything from
scratch. You don't need to know about these classes if you want to use something like
<link xlink:href="#x509">X.509 authentication</link>, as it already has a namespace configuration
option which is simpler to use and get started with. If you need to use explicit bean confiuration or
are planning on writing your own implementation then an understanding of how the
provided implementations work will be useful. You will find classes under the
<package>org.springframework.security.web.authentication.preauth</package>. We just provide an outline
here so you should consult the Javadoc and source where appropriate.
</para>
<para> Because most pre-authentication mechanisms follow the same pattern, Spring Security has a
set of classes which provide an internal framework for implementing pre-authenticated
authentication providers. This removes duplication and allows new implementations to be added
in a structured fashion, without having to write everything from scratch. You don't need to
know about these classes if you want to use something like <link xlink:href="#x509">X.509
authentication</link>, as it already has a namespace configuration option which is simpler
to use and get started with. If you need to use explicit bean confiuration or are planning on
writing your own implementation then an understanding of how the provided implementations work
will be useful. You will find classes under the
<package>org.springframework.security.web.authentication.preauth</package>. We just provide
an outline here so you should consult the Javadoc and source where appropriate. </para>
<section>
<title>AbstractPreAuthenticatedProcessingFilter</title>
<para>
This class will check the current contents of the security context and, if empty, it will attempt to extract
user information from the HTTP request and submit it to the <interfacename>AuthenticationManager</interfacename>.
Subclasses override the following methods to obtain this information:
<programlisting language="java">
<para> This class will check the current contents of the security context and, if empty, it
will attempt to extract user information from the HTTP request and submit it to the
<interfacename>AuthenticationManager</interfacename>. Subclasses override the following
methods to obtain this information:
<programlisting language="java">
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
</programlisting>
After calling these, the filter will create a <classname>PreAuthenticatedAuthenticationToken</classname>
containing the returned data and submit it for authentication. By <quote>authentication</quote> here, we
really just mean further processing to perhaps load the user's authorities, but the standard Spring Security
authentication architecture is followed.
</para>
After calling these, the filter will create a
<classname>PreAuthenticatedAuthenticationToken</classname> containing the returned data
and submit it for authentication. By <quote>authentication</quote> here, we really just mean
further processing to perhaps load the user's authorities, but the standard Spring Security
authentication architecture is followed. </para>
</section>
<section>
<title>AbstractPreAuthenticatedAuthenticationDetailsSource</title>
<para>
Like other Spring Security authentication filters, the pre-authentication filter has an
<literal>authenticationDetailsSource</literal> property which by default will create a
<classname>WebAuthenticationDetails</classname> object to store additional information such as
the session-identifier and originating IP address in the <literal>details</literal> property of
the <interfacename>Authentication</interfacename> object.
In cases where user role information can be obtained from the pre-authentication mechanism, the
data is also stored in this property. Subclasses of
<classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an extended details
object which implements the <interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling the
authentication provider to read the authorities which were externally allocated to the user. We'll look at a concrete
example next.
</para>
<para> Like other Spring Security authentication filters, the pre-authentication filter has an
<literal>authenticationDetailsSource</literal> property which by default will create a
<classname>WebAuthenticationDetails</classname> object to store additional information
such as the session-identifier and originating IP address in the <literal>details</literal>
property of the <interfacename>Authentication</interfacename> object. In cases where user
role information can be obtained from the pre-authentication mechanism, the data is also
stored in this property. Subclasses of
<classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an extended
details object which implements the
<interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling the
authentication provider to read the authorities which were externally allocated to the user.
We'll look at a concrete example next. </para>
<section xml:id="j2ee-preauth-details">
<title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title>
<para>
If the filter is configured with an <literal>authenticationDetailsSource</literal> which is an instance of this
class, the authority information is obtained by calling the <methodname>isUserInRole(String role)</methodname> method
for each of a pre-determined set of <quote>mappable roles</quote>. The class gets these from a configured
<interfacename>MappableAttributesRetriever</interfacename>. Possible implementations include hard-coding a list in the application
context and reading the role information from the <literal>&lt;security-role&gt;</literal> information in a
<filename>web.xml</filename> file. The pre-authentication sample application uses the latter approach.
</para>
<para>There is an additional stage where the roles (or attributes) are mapped to Spring Security
<interfacename>GrantedAuthority</interfacename> objects using a configured
<interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>. The default will just add the usual <literal>ROLE_</literal>
prefix to the names, but it gives you full control over the behaviour.
</para>
<para> If the filter is configured with an <literal>authenticationDetailsSource</literal>
which is an instance of this class, the authority information is obtained by calling the
<methodname>isUserInRole(String role)</methodname> method for each of a pre-determined
set of <quote>mappable roles</quote>. The class gets these from a configured
<interfacename>MappableAttributesRetriever</interfacename>. Possible implementations
include hard-coding a list in the application context and reading the role information
from the <literal>&lt;security-role&gt;</literal> information in a
<filename>web.xml</filename> file. The pre-authentication sample application uses the
latter approach. </para>
<para>There is an additional stage where the roles (or attributes) are mapped to Spring
Security <interfacename>GrantedAuthority</interfacename> objects using a configured
<interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>. The default will
just add the usual <literal>ROLE_</literal> prefix to the names, but it gives you full
control over the behaviour. </para>
</section>
</section>
<section>
<title>PreAuthenticatedAuthenticationProvider</title>
<para>
The pre-authenticated provider has little more to do than load the <interfacename>UserDetails</interfacename>
object for the user. It does this by delegating to a <interfacename>AuthenticationUserDetailsService</interfacename>.
The latter is similar to the standard <interfacename>UserDetailsService</interfacename> but takes an
<interfacename>Authentication</interfacename> object rather than just user name:
<programlisting language="java">
<para> The pre-authenticated provider has little more to do than load the
<interfacename>UserDetails</interfacename> object for the user. It does this by delegating
to a <interfacename>AuthenticationUserDetailsService</interfacename>. The latter is similar
to the standard <interfacename>UserDetailsService</interfacename> but takes an
<interfacename>Authentication</interfacename> object rather than just user name:
<programlisting language="java">
public interface AuthenticationUserDetailsService {
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
}
</programlisting>
This interface may have also other uses but with pre-authentication it allows access to the authorities which
were packaged in the <interfacename>Authentication</interfacename> object, as we saw in the previous section.
The <classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class does this.
Alternatively, it may delegate to a standard <interfacename>UserDetailsService</interfacename> via the
<classname>UserDetailsByNameServiceWrapper</classname> implementation.
</para>
</programlisting>
This interface may have also other uses but with pre-authentication it allows access to the
authorities which were packaged in the <interfacename>Authentication</interfacename> object,
as we saw in the previous section. The
<classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class does
this. Alternatively, it may delegate to a standard
<interfacename>UserDetailsService</interfacename> via the
<classname>UserDetailsByNameServiceWrapper</classname> implementation. </para>
</section>
<section>
<title>Http403ForbiddenEntryPoint</title>
<para>
The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the <link xlink:href="#tech-intro-auth-entry-point">technical
overview</link> chapter. Normally it is responsible for kick-starting the authentication process for an unauthenticated user
(when they try to access a protected resource), but in the pre-authenticated case this doesn't apply. You would only
configure the <classname>ExceptionTranslationFilter</classname> with an instance of this class if you aren't
using pre-authentication in combination with other authentication mechanisms.
It will be called if the user is rejected by the <classname>AbstractPreAuthenticatedProcessingFilter</classname>
resulting in a null authentication. It always returns a <literal>403</literal>-forbidden response code if called.
</para>
<para> The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the <link
xlink:href="#tech-intro-auth-entry-point">technical overview</link> chapter. Normally it
is responsible for kick-starting the authentication process for an unauthenticated user
(when they try to access a protected resource), but in the pre-authenticated case this
doesn't apply. You would only configure the
<classname>ExceptionTranslationFilter</classname> with an instance of this class if you
aren't using pre-authentication in combination with other authentication mechanisms. It will
be called if the user is rejected by the
<classname>AbstractPreAuthenticatedProcessingFilter</classname> resulting in a null
authentication. It always returns a <literal>403</literal>-forbidden response code if
called. </para>
</section>
</section>
<section>
<title>Concrete Implementations</title>
<para>
X.509 authentication is covered in its <link xlink:href="#x509">own chapter</link>. Here we'll look at some classes
which provide support for other pre-authenticated scenarios.
</para>
<para> X.509 authentication is covered in its <link xlink:href="#x509">own chapter</link>. Here
we'll look at some classes which provide support for other pre-authenticated scenarios. </para>
<section>
<title>Request-Header Authentication (Siteminder)</title>
<para>
An external authentication system may supply information to the application by setting specific headers on the HTTP request.
A well known example of this is is Siteminder, which passes the username in a header called <literal>SM_USER</literal>.
This mechanism is supported by the class <classname>RequestHeaderPreAuthenticatedProcessingFilter</classname> which
simply extracts the username from the header. It defaults to using the name <literal>SM_USER</literal> as the
header name. See the Javadoc for more details.
</para>
<para> An external authentication system may supply information to the application by setting
specific headers on the HTTP request. A well known example of this is is Siteminder, which
passes the username in a header called <literal>SM_USER</literal>. This mechanism is
supported by the class <classname>RequestHeaderAuthenticationFilter</classname> which simply
extracts the username from the header. It defaults to using the name
<literal>SM_USER</literal> as the header name. See the Javadoc for more details. </para>
<tip>
<para>Note that when using a system like this, the framework performs no authentication checks at all and
it is <emphasis>extremely</emphasis> important that the external system is configured properly and protects all
access to the application. If an attacker is able to forge the headers in their original request without this being
detected then they could potentially choose any userame they wished.
</para>
<para>Note that when using a system like this, the framework performs no authentication
checks at all and it is <emphasis>extremely</emphasis> important that the external system
is configured properly and protects all access to the application. If an attacker is able
to forge the headers in their original request without this being detected then they could
potentially choose any userame they wished. </para>
</tip>
<section>
<title>Siteminder Example Configuration</title>
<para>
A typical configuration using this filter would look like this:
<programlisting><![CDATA[
<para> A typical configuration using this filter would look like this: <programlisting><![CDATA[
<bean id="siteminderFilter" class=
"org.springframework.security.web.authentication.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
"org.springframework.security.web.authentication.preauth.header.RequestHeaderAuthenticationFilter">
<security:custom-filter position="PRE_AUTH_FILTER" />
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
@ -170,30 +157,27 @@ class="org.springframework.security.web.authentication.preauth.PreAuthenticatedA
<security:authentication-manager alias="authenticationManager" />
]]>
</programlisting>
We've assumed here that the security namespace is being used for configuration (hence the user of the <literal>custom-filter</literal>,
<literal>authentication-manager</literal> and <literal>custom-authentication-provider</literal> elements (you can read more about them
in the <link xlink:href="ns-config">namespace chapter</link>). You would leave these out of a traditional bean configuration.
It's also assumed that you have added a <interfacename>UserDetailsService</interfacename> (called <quote>userDetailsService</quote>)
to your configuration to load the user's roles.
</programlisting> We've assumed here that the security namespace is being used for
configuration (hence the user of the <literal>custom-filter</literal>,
<literal>authentication-manager</literal> and
<literal>custom-authentication-provider</literal> elements (you can read more about them
in the <link xlink:href="ns-config">namespace chapter</link>). You would leave these out
of a traditional bean configuration. It's also assumed that you have added a
<interfacename>UserDetailsService</interfacename> (called
<quote>userDetailsService</quote>) to your configuration to load the user's roles.
</para>
</section>
</section>
<section>
<title>J2EE Container Authentication</title>
<para>
The class <classname>J2eePreAuthenticatedProcessingFilter</classname> will extract the username from the
<literal>userPrincipal</literal> property of the <interfacename>HttpServletRequest</interfacename>. use of this
filter would usually be combined with the use of J2EE roles as described above in <xref linkend="j2ee-preauth-details"/>.
</para>
<para>
There is a sample application in the codebase which uses this approach, so get hold of the code from subversion and
have a look at the application context file if you are interested. The code is in the <filename>samples/preauth</filename>
directory.
</para>
<para> The class <classname>J2eePreAuthenticatedProcessingFilter</classname> will extract the
username from the <literal>userPrincipal</literal> property of the
<interfacename>HttpServletRequest</interfacename>. use of this filter would usually be
combined with the use of J2EE roles as described above in <xref
linkend="j2ee-preauth-details"/>. </para>
<para> There is a sample application in the codebase which uses this approach, so get hold of
the code from subversion and have a look at the application context file if you are
interested. The code is in the <filename>samples/preauth</filename> directory. </para>
</section>
</section>
</chapter>

View File

@ -1,34 +1,33 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="remember-me"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Remember-Me Authentication</title></info>
<section xml:id="remember-me-overview">
<info><title>Overview</title></info>
<para>Remember-me or persistent-login authentication refers to web sites being able to
remember the identity of a principal between sessions. This is
typically accomplished by sending a cookie to the browser, with the
cookie being detected during future sessions and causing automated
login to take place. Spring Security provides the necessary hooks for
these operations to take place, and has two concrete
remember-me implementations. One uses hashing to preserve the security of
cookie-based tokens and the other uses a database or other persistent storage
mechanism to store the generated tokens. </para>
<para>
Note that both implemementations require a <interfacename>UserDetailsService</interfacename>.
If you are using an authentication provider which doesn't use a <interfacename>UserDetailsService</interfacename>
(for example, the LDAP provider) then it won't work unless you also have a <interfacename>UserDetailsService</interfacename>
bean in your application context.
</para>
</section>
<info>
<title>Remember-Me Authentication</title>
</info>
<section xml:id="remember-me-overview">
<info>
<title>Overview</title>
</info>
<para>Remember-me or persistent-login authentication refers to web sites being able to
remember the identity of a principal between sessions. This is typically accomplished by
sending a cookie to the browser, with the cookie being detected during future sessions
and causing automated login to take place. Spring Security provides the necessary hooks
for these operations to take place, and has two concrete remember-me implementations.
One uses hashing to preserve the security of cookie-based tokens and the other uses a
database or other persistent storage mechanism to store the generated tokens. </para>
<para> Note that both implemementations require a
<interfacename>UserDetailsService</interfacename>. If you are using an
authentication provider which doesn't use a
<interfacename>UserDetailsService</interfacename> (for example, the LDAP provider)
then it won't work unless you also have a
<interfacename>UserDetailsService</interfacename> bean in your application context.
</para>
</section>
<section xml:id="remember-me-hash-token">
<title>Simple Hash-Based Token Approach</title>
<para>This approach uses hashing to achieve a useful remember-me strategy.
In essence a cookie is sent to the browser upon successful interactive authentication, with the
<para>This approach uses hashing to achieve a useful remember-me strategy. In essence a
cookie is sent to the browser upon successful interactive authentication, with the
cookie being composed as follows:
<programlisting>
<programlisting>
base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
@ -38,109 +37,101 @@
expressed in milliseconds
key: A private key to prevent modification of the remember-me token
</programlisting></para>
<para>As such the remember-me token is valid only for the period
specified, and provided that the username, password and key does not
change. Notably, this has a potential security issue in that a
captured remember-me token will be usable from any user agent until
such time as the token expires. This is the same issue as with digest
authentication. If a principal is aware a token has been captured,
they can easily change their password and immediately invalidate all
remember-me tokens on issue. If more significant security is
needed you should use the approach described in the next section. Alternatively
remember-me services should simply not be used at all.</para>
<para>If you are familiar with the topics discussed in the chapter on <link xlink:href="ns-config">namespace configuration</link>,
you can enable remember-me authentication just by adding the <literal>&lt;remember-me&gt;</literal> element:
<programlisting><![CDATA[
<para>As such the remember-me token is valid only for the period specified, and provided
that the username, password and key does not change. Notably, this has a potential
security issue in that a captured remember-me token will be usable from any user agent
until such time as the token expires. This is the same issue as with digest
authentication. If a principal is aware a token has been captured, they can easily
change their password and immediately invalidate all remember-me tokens on issue. If
more significant security is needed you should use the approach described in the next
section. Alternatively remember-me services should simply not be used at all.</para>
<para>If you are familiar with the topics discussed in the chapter on <link
xlink:href="ns-config">namespace configuration</link>, you can enable remember-me
authentication just by adding the <literal>&lt;remember-me&gt;</literal> element: <programlisting><![CDATA[
<http>
...
<remember-me key="myAppKey"/>
</http>
]]>
</programlisting>
The <interfacename>UserDetailsService</interfacename> will normally be selected automatically. If you have more than one in
your application context, you need to specify which one should be used with the <literal>user-service-ref</literal> attribute,
where the value is the name of your <interfacename>UserDetailsService</interfacename> bean.
</para>
</programlisting> The <interfacename>UserDetailsService</interfacename> will
normally be selected automatically. If you have more than one in your application
context, you need to specify which one should be used with the
<literal>user-service-ref</literal> attribute, where the value is the name of your
<interfacename>UserDetailsService</interfacename> bean. </para>
</section>
<section xml:id="remember-me-persistent-token">
<title>Persistent Token Approach</title>
<para>This approach is based on the article
<link xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice">http://jaspan.com/improved_persistent_login_cookie_best_practice</link>
with some minor modifications <footnote><para>Essentially, the username is not included in the cookie, to prevent exposing a valid login
name unecessarily. There is a discussion on this in the comments section of this article.</para></footnote>.
To use the this approach with namespace configuration, you would supply a datasource reference:
<programlisting><![CDATA[
<para>This approach is based on the article <link
xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice"
>http://jaspan.com/improved_persistent_login_cookie_best_practice</link> with some
minor modifications <footnote><para>Essentially, the username is not included in the
cookie, to prevent exposing a valid login name unecessarily. There is a
discussion on this in the comments section of this article.</para></footnote>.
To use the this approach with namespace configuration, you would supply a datasource
reference: <programlisting><![CDATA[
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
]]>
</programlisting>
The database should contain a <literal>persistent_logins</literal> table, created using the following SQL (or equivalent):
<programlisting>
</programlisting> The database should contain a
<literal>persistent_logins</literal> table, created using the following SQL (or
equivalent):
<programlisting>
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)
</programlisting>
</para>
</programlisting></para>
<!-- TODO: Add more info on the implementation and behaviour when tokens are stolen etc. Also some info for admins on invalidating tokens using key, or deleting info from db -->
</section>
<section xml:id="remember-me-impls">
<info><title>Remember-Me Interfaces and Implementations</title></info>
<para>Remember-me authentication is not used with basic
authentication, given it is often not used with
<literal>HttpSession</literal>s. Remember-me is used with
<literal>UsernamePasswordAuthenticationFilter</literal>, and is implemented
via hooks in the <literal>AbstractAuthenticationProcessingFilter</literal>
superclass. The hooks will invoke a concrete
<interfacename>RememberMeServices</interfacename> at the appropriate times. The
interface looks like this:
<programlisting language="java">
</section>
<section xml:id="remember-me-impls">
<info>
<title>Remember-Me Interfaces and Implementations</title>
</info>
<para>Remember-me authentication is not used with basic authentication, given it is often
not used with <literal>HttpSession</literal>s. Remember-me is used with
<literal>UsernamePasswordAuthenticationFilter</literal>, and is implemented via
hooks in the <literal>AbstractAuthenticationProcessingFilter</literal> superclass. The
hooks will invoke a concrete <interfacename>RememberMeServices</interfacename> at the
appropriate times. The interface looks like this:
<programlisting language="java">
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication successfulAuthentication);
</programlisting>
Please refer to the JavaDocs for a fuller discussion on what the
methods do, although note at this stage that
<literal>AbstractAuthenticationProcessingFilter</literal> only calls the
<literal>loginFail()</literal> and <literal>loginSuccess()</literal>
methods. The <literal>autoLogin()</literal> method is called by
<classname>RememberMeProcessingFilter</classname> whenever the
<classname>SecurityContextHolder</classname> does not contain an
<interfacename>Authentication</interfacename>. This interface therefore provides
the underlying remember-me implementation with sufficient
notification of authentication-related events, and delegates to the
implementation whenever a candidate web request might contain a cookie
and wish to be remembered. This design allows any number of remember-me implementation
strategies. We've seen above that Spring Security provides
two implementations. We'll look at thes in turn.</para>
Please refer to the JavaDocs for a fuller discussion on what the methods do, although
note at this stage that <literal>AbstractAuthenticationProcessingFilter</literal> only
calls the <literal>loginFail()</literal> and <literal>loginSuccess()</literal> methods.
The <literal>autoLogin()</literal> method is called by
<classname>RememberMeAuthenticationFilter</classname> whenever the
<classname>SecurityContextHolder</classname> does not contain an
<interfacename>Authentication</interfacename>. This interface therefore provides the
underlying remember-me implementation with sufficient notification of
authentication-related events, and delegates to the implementation whenever a candidate
web request might contain a cookie and wish to be remembered. This design allows any
number of remember-me implementation strategies. We've seen above that Spring Security
provides two implementations. We'll look at thes in turn.</para>
<section>
<title>TokenBasedRememberMeServices</title>
<para>
This implementation supports the simpler approach described in <xref linkend="remember-me-hash-token"/>.
<classname>TokenBasedRememberMeServices</classname> generates a
<literal>RememberMeAuthenticationToken</literal>, which is processed
by <literal>RememberMeAuthenticationProvider</literal>. A
<literal>key</literal> is shared between this authentication provider
and the <literal>TokenBasedRememberMeServices</literal>. In addition,
<literal>TokenBasedRememberMeServices</literal> requires A
UserDetailsService from which it can retrieve the username and
password for signature comparison purposes, and generate the
<literal>RememberMeAuthenticationToken</literal> to contain the
correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of logout
command should be provided by the application that invalidates the cookie if
the user requests this. <classname>TokenBasedRememberMeServices</classname> also implements Spring Security's
<interfacename>LogoutHandler</interfacename> interface so can be used with <classname>LogoutFilter</classname>
to have the cookie cleared automatically.
</para>
<para>The beans required in an application context to enable remember-me services are as follows:
<programlisting language="xml"><![CDATA[
<bean id="rememberMeProcessingFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeProcessingFilter">
<para> This implementation supports the simpler approach described in <xref
linkend="remember-me-hash-token"/>.
<classname>TokenBasedRememberMeServices</classname> generates a
<literal>RememberMeAuthenticationToken</literal>, which is processed by
<literal>RememberMeAuthenticationProvider</literal>. A <literal>key</literal> is
shared between this authentication provider and the
<literal>TokenBasedRememberMeServices</literal>. In addition,
<literal>TokenBasedRememberMeServices</literal> requires A UserDetailsService
from which it can retrieve the username and password for signature comparison
purposes, and generate the <literal>RememberMeAuthenticationToken</literal> to
contain the correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of
logout command should be provided by the application that invalidates the cookie if
the user requests this. <classname>TokenBasedRememberMeServices</classname> also
implements Spring Security's <interfacename>LogoutHandler</interfacename> interface
so can be used with <classname>LogoutFilter</classname> to have the cookie cleared
automatically. </para>
<para>The beans required in an application context to enable remember-me services are as
follows: <programlisting language="xml"><![CDATA[
<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
@ -157,27 +148,26 @@
</bean>
]]>
</programlisting>Don't forget to add your
<interfacename>RememberMeServices</interfacename> implementation to your
<literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal>
property, include the
<literal>RememberMeAuthenticationProvider</literal> in your
<literal>AuthenticationManager.setProviders()</literal> list, and add
<classname>RememberMeProcessingFilter</classname> into your
<classname>FilterChainProxy</classname> (typically immediately after your
<literal>UsernamePasswordAuthenticationFilter</literal>).</para>
<interfacename>RememberMeServices</interfacename> implementation to your
<literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal>
property, include the <literal>RememberMeAuthenticationProvider</literal> in your
<literal>AuthenticationManager.setProviders()</literal> list, and add
<classname>RememberMeAuthenticationFilter</classname> into your
<classname>FilterChainProxy</classname> (typically immediately after your
<literal>UsernamePasswordAuthenticationFilter</literal>).</para>
</section>
<section>
<title>PersistentTokenBasedRememberMeServices</title>
<para>
This class can be used in the same way as <classname>TokenBasedRememberMeServices</classname>, but it additionally
needs to be configured with a <interfacename>PersistentTokenRepository</interfacename> to store the tokens.
There are two standard implementations.
<itemizedlist>
<listitem><para><classname>InMemoryTokenRepositoryImpl</classname> which is intended for testing only.</para></listitem>
<listitem><para><classname>JdbcTokenRepositoryImpl</classname> which stores the tokens in a database. </para></listitem>
</itemizedlist>
The database schema is described above in <xref linkend="remember-me-persistent-token"/>.
</para>
<para> This class can be used in the same way as
<classname>TokenBasedRememberMeServices</classname>, but it additionally needs
to be configured with a <interfacename>PersistentTokenRepository</interfacename> to
store the tokens. There are two standard implementations.
<itemizedlist><listitem><para><classname>InMemoryTokenRepositoryImpl</classname>
which is intended for testing
only.</para></listitem><listitem><para><classname>JdbcTokenRepositoryImpl</classname>
which stores the tokens in a database. </para></listitem></itemizedlist>
The database schema is described above in <xref
linkend="remember-me-persistent-token"/>. </para>
</section>
</section>
</chapter>
</chapter>

View File

@ -6,27 +6,27 @@
<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>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>
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
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[
<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>
@ -37,11 +37,11 @@
<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
<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>
@ -50,11 +50,11 @@
<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
<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
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
@ -64,24 +64,24 @@
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters="
securityContextPersistenceFilterWithASCFalse,
basicProcessingFilter,
basicAuthenticationFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
<sec:filter-chain pattern="/**" filters="
securityContextPersistenceFilterWithASCTrue,
authenticationProcessingFilter,
formLoginFilter,
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 URIs appear first. At runtime the
</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
@ -89,112 +89,92 @@
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>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,
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
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="#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 this is the
<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 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>
<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
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 -
<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>CasAuthenticationFilter</classname>,
<classname>BasicAuthenticationFilter</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
<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>RememberMeAuthenticationFilter</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
<interfacename>Authentication</interfacename> object will be put
there</para></listitem><listitem><para><classname>AnonymousAuthenticationFilter</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>
<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>
<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
<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 xml:id="taglib">
<info>
<title>Tag Libraries</title>

View File

@ -35,11 +35,11 @@
<para>
<interfacename>SessionAuthenticationStrategy</interfacename> is used by both
<classname>SessionManagementFilter</classname> and
<classname>AbstractAutheticationProcessingFilter</classname>, so if you are using a
<classname>AbstractAuthenticationProcessingFilter</classname>, so if you are using a
customized form-login class, for example, you will need to inject it into both of these. In
this case, a typical configuration, combining the namespace and custom beans might look like this:<programlisting><![CDATA[
<http>
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER" ref="myAuthFilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
<session-management session-authentication-strategy-ref="sas"/>
</http>