Manual formatting.

This commit is contained in:
Luke Taylor 2010-03-03 23:08:05 +00:00
parent ae8027fa47
commit 90caf1bb37
30 changed files with 4145 additions and 3860 deletions

View File

@ -8,30 +8,30 @@
<title>Overview</title>
</info>
<para>It's generally considered good security practice to adopt a
<quote>deny-by-default</quote> where you explicitly specify what is allowed and
disallow everything else. Defining what is accessible to unauthenticated users is a
similar situation, particularly for web applications. Many sites require that users must
be authenticated for anything other than a few URLs (for example the home and login
pages). In this case it is easiest to define access configuration attributes for these
specific URLs rather than have for every secured resource. Put differently, sometimes it
is nice to say <literal>ROLE_SOMETHING</literal> is required by default and only allow
certain exceptions to this rule, such as for login, logout and home pages of an
application. You could also omit these pages from the filter chain entirely, thus
bypassing the access control checks, but this may be undesirable for other reasons,
particularly if the pages behave differently for authenticated users.</para>
<quote>deny-by-default</quote> where you explicitly specify what is allowed and disallow
everything else. Defining what is accessible to unauthenticated users is a similar
situation, particularly for web applications. Many sites require that users must be
authenticated for anything other than a few URLs (for example the home and login pages).
In this case it is easiest to define access configuration attributes for these specific
URLs rather than have for every secured resource. Put differently, sometimes it is nice
to say <literal>ROLE_SOMETHING</literal> is required by default and only allow certain
exceptions to this rule, such as for login, logout and home pages of an application. You
could also omit these pages from the filter chain entirely, thus bypassing the access
control checks, but this may be undesirable for other reasons, particularly if the pages
behave differently for authenticated users.</para>
<para>This is what we mean by anonymous authentication. Note that there is no real
conceptual difference between a user who is <quote>anonymously authenticated</quote> and
an unauthenticated user. Spring Security's anonymous authentication just gives you a
more convenient way to configure your access-control attributes. Calls to servlet API
calls such as <methodname>getCallerPrincipal</methodname>, for example, will still
return null even though there is actually an anonymous authentication object in the
<classname>SecurityContextHolder</classname>.</para>
<classname>SecurityContextHolder</classname>.</para>
<para>There are other situations where anonymous authentication is useful, such as when an
auditing interceptor queries the <classname>SecurityContextHolder</classname> to
identify which principal was responsible for a given operation. Classes can be authored
more robustly if they know the <classname>SecurityContextHolder</classname> always
contains an <interfacename>Authentication</interfacename> object, and never
<literal>null</literal>.</para>
<literal>null</literal>.</para>
</section>
<section xml:id="anonymous-config">
<info>
@ -39,23 +39,22 @@
</info>
<para>Anonymous authentication support is provided automatically when using the HTTP
configuration Spring Security 3.0 and can be customized (or disabled) using the
<literal>&lt;anonymous></literal> element. You don't need to configure the beans
<literal>&lt;anonymous></literal> element. You don't need to configure the beans
described here unless you are using traditional bean configuration.</para>
<para>Three classes that together provide the anonymous authentication feature.
<literal>AnonymousAuthenticationToken</literal> is an implementation of
<interfacename>Authentication</interfacename>, and stores the
<interfacename>GrantedAuthority</interfacename>s which apply to the anonymous
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
<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>
<literal>AnonymousAuthenticationToken</literal> is an implementation of
<interfacename>Authentication</interfacename>, and stores the
<interfacename>GrantedAuthority</interfacename>s which apply to the anonymous 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
<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="anonymousAuthFilter"
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
@ -67,32 +66,30 @@
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>]]>
</programlisting>
</para>
</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
<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
invocations), then a malicious client could submit an
<classname>AnonymousAuthenticationToken</classname> which it had created
itself (with chosen username and authority list). If the <literal>key</literal>
is guessable or can be found out, then the token would be accepted by the
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
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
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 invocations),
then a malicious client could submit an
<classname>AnonymousAuthenticationToken</classname> which it had created itself
(with chosen username and authority list). If the <literal>key</literal> is
guessable or can be found out, then the token would be accepted by the 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
<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>
<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">
@ -108,19 +105,18 @@
</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
<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
<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
@ -130,13 +126,13 @@
interceptor configuration replaced with <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>,
which is effectively the same thing when defining access controls. This is an example of
the use of the <classname>AuthenticatedVoter</classname> which we will see in the <link
xlink:href="#authz-authenticated-voter">authorization chapter</link>. It uses an
<interfacename>AuthenticationTrustResolver</interfacename> to process this
particular configuration attribute and grant access to anonymous users. The
<classname>AuthenticatedVoter</classname> approach is more powerful, since it allows
you to differentiate between anonymous, remember-me and fully-authenticated users. If
you don't need this functionality though, then you can stick with
<literal>ROLE_ANONYMOUS</literal>, which will be processed by Spring Security's
standard <classname>RoleVoter</classname>. </para>
xlink:href="#authz-authenticated-voter">authorization chapter</link>. It uses an
<interfacename>AuthenticationTrustResolver</interfacename> to process this particular
configuration attribute and grant access to anonymous users. The
<classname>AuthenticatedVoter</classname> approach is more powerful, since it allows you
to differentiate between anonymous, remember-me and fully-authenticated users. If you
don't need this functionality though, then you can stick with
<literal>ROLE_ANONYMOUS</literal>, which will be processed by Spring Security's standard
<classname>RoleVoter</classname>. </para>
</section>
</chapter>

View File

@ -1,20 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<appendix version="5.0" xml:id="appendix-schema" xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>Security Database Schema</title>
</info>
<para> There are various database schema used by the framework and this appendix provides a single
reference point to them all. You only need to provide the tables for the areas of functonality
you require. </para>
<para> DDL statements are given for the HSQLDB database. You can use these as a guideline for
defining the schema for the database you are using. </para>
<section>
<title>User Schema</title>
<para> The standard JDBC implementation of the <interfacename>UserDetailsService</interfacename>
(<classname>JdbcDaoImpl</classname>) requires tables to load the password, account status
(enabled or disabled) and a list of authorities (roles) for the user.
<programlisting xml:id="db_schema_users_authorities">
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>Security Database Schema</title>
</info>
<para> There are various database schema used by the framework and this appendix provides a
single reference point to them all. You only need to provide the tables for the areas of
functonality you require. </para>
<para> DDL statements are given for the HSQLDB database. You can use these as a guideline for
defining the schema for the database you are using. </para>
<section>
<title>User Schema</title>
<para> The standard JDBC implementation of the
<interfacename>UserDetailsService</interfacename> (<classname>JdbcDaoImpl</classname>)
requires tables to load the password, account status (enabled or disabled) and a list of
authorities (roles) for the user.
<programlisting xml:id="db_schema_users_authorities">
create table users(
username varchar_ignorecase(50) not null primary key,
password varchar_ignorecase(50) not null,
@ -26,11 +27,11 @@
constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);
</programlisting></para>
<section>
<title>Group Authorities</title>
<para> Spring Security 2.0 introduced support for group authorities in
<classname>JdbcDaoImpl</classname>. The table structure if groups are enabled is as
follows:<programlisting xml:id="db-schema-groups">
<section>
<title>Group Authorities</title>
<para> Spring Security 2.0 introduced support for group authorities in
<classname>JdbcDaoImpl</classname>. The table structure if groups are enabled is as
follows:<programlisting xml:id="db-schema-groups">
create table groups (
id bigint generated by default as identity(start with 0) primary key,
group_name varchar_ignorecase(50) not null);
@ -46,55 +47,57 @@ create table group_members (
group_id bigint not null,
constraint fk_group_members_group foreign key(group_id) references groups(id));
</programlisting></para>
</section>
</section>
</section>
<section>
<title>Persistent Login (Remember-Me) Schema</title>
<para> This table is used to store data used by the more secure <link
xlink:href="#remember-me-persistent-token">persistent token</link> remember-me
implementation. If you are using <classname>JdbcTokenRepositoryImpl</classname> either
directly or through the namespace, then you will need this table.
<programlisting xml:id="db-schema-remeber-me">
<section>
<title>Persistent Login (Remember-Me) Schema</title>
<para> This table is used to store data used by the more secure <link
xlink:href="#remember-me-persistent-token">persistent token</link> remember-me
implementation. If you are using <classname>JdbcTokenRepositoryImpl</classname> either
directly or through the namespace, then you will need this table.
<programlisting xml:id="db-schema-remeber-me">
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>
</section>
<section xml:id="dbschema-acl">
<title>ACL Schema</title>
<para>There are four tables used by the Spring Security <link xlink:href="#domain-acls"
>ACL</link> implementation. <orderedlist>
<listitem>
<para><literal>acl_sid</literal> stores the security identities recognised by the ACL
system. These can be unique principals or authorities which may apply to multiple
principals.</para>
</listitem>
<listitem>
<para><literal>acl_class</literal> defines the domain object types to which ACLs apply.
The <literal>class</literal> column stores the Java class name of the object. </para>
</listitem>
<listitem>
<para><literal>acl_object_identity</literal> stores the object identity definitions of
specific domai objects.</para>
</listitem>
<listitem>
<para><literal>acl_entry</literal> stores the ACL permissions which apply to a specific
object identity and security identity.</para>
</listitem>
</orderedlist></para>
<para>It is assumed that the database will auto-generate the primary keys for each of the
identities. The <literal>JdbcMutableAclService</literal> has to be able to retrieve these when
it has created a new row in the <literal>acl_sid</literal> or <literal>acl_class</literal>
tables. It has two properties which define the SQL needed to retrieve these values
<literal>classIdentityQuery</literal> and <literal>sidIdentityQuery</literal>. Both of these
default to <literal>call identity()</literal></para>
<section>
<title>Hypersonic SQL</title>
<para>The default schema works with the embedded HSQLDB database that is used in unit tests
within the
framework.<programlisting xml:id="dbschema-acl-hsql">
</section>
<section xml:id="dbschema-acl">
<title>ACL Schema</title>
<para>There are four tables used by the Spring Security <link xlink:href="#domain-acls"
>ACL</link> implementation. <orderedlist>
<listitem>
<para><literal>acl_sid</literal> stores the security identities recognised by the
ACL system. These can be unique principals or authorities which may apply to
multiple principals.</para>
</listitem>
<listitem>
<para><literal>acl_class</literal> defines the domain object types to which ACLs
apply. The <literal>class</literal> column stores the Java class name of the
object. </para>
</listitem>
<listitem>
<para><literal>acl_object_identity</literal> stores the object identity definitions
of specific domai objects.</para>
</listitem>
<listitem>
<para><literal>acl_entry</literal> stores the ACL permissions which apply to a
specific object identity and security identity.</para>
</listitem>
</orderedlist></para>
<para>It is assumed that the database will auto-generate the primary keys for each of the
identities. The <literal>JdbcMutableAclService</literal> has to be able to retrieve
these when it has created a new row in the <literal>acl_sid</literal> or
<literal>acl_class</literal> tables. It has two properties which define the SQL needed
to retrieve these values <literal>classIdentityQuery</literal> and
<literal>sidIdentityQuery</literal>. Both of these default to <literal>call
identity()</literal></para>
<section>
<title>Hypersonic SQL</title>
<para>The default schema works with the embedded HSQLDB database that is used in unit
tests within the
framework.<programlisting xml:id="dbschema-acl-hsql">
create table acl_sid (
id bigint generated by default as identity(start with 100) not null primary key,
principal boolean not null,
@ -129,10 +132,10 @@ create table acl_entry (
constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );
</programlisting></para>
<section>
<title>PostgreSQL</title>
<para>
<programlisting>create table acl_sid(
<section>
<title>PostgreSQL</title>
<para>
<programlisting>create table acl_sid(
id bigserial not null primary key,
principal boolean not null,
sid varchar(100) not null,
@ -168,21 +171,21 @@ create table acl_entry(
constraint foreign_fk_4 foreign key(acl_object_identity)
references acl_object_identity(id),
constraint foreign_fk_5 foreign key(sid) references acl_sid(id));
</programlisting>
</para>
<para>You will have to set the <literal>classIdentityQuery</literal> and
<literal>sidIdentityQuery</literal> properties of
<classname>JdbcMutableAclService</classname> to the following values, respectively: <itemizedlist>
<listitem>
<para><literal>select currval(pg_get_serial_sequence('acl_class',
'id'))</literal></para>
</listitem>
<listitem>
<para><literal>select currval(pg_get_serial_sequence('acl_sid',
'id'))</literal></para>
</listitem>
</itemizedlist></para>
</section>
</programlisting> </para>
<para>You will have to set the <literal>classIdentityQuery</literal> and
<literal>sidIdentityQuery</literal> properties of
<classname>JdbcMutableAclService</classname> to the following values,
respectively: <itemizedlist>
<listitem>
<para><literal>select currval(pg_get_serial_sequence('acl_class',
'id'))</literal></para>
</listitem>
<listitem>
<para><literal>select currval(pg_get_serial_sequence('acl_sid',
'id'))</literal></para>
</listitem>
</itemizedlist></para>
</section>
</section>
</section>
</section>
</appendix>

File diff suppressed because it is too large Load Diff

View File

@ -1,232 +1,246 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authz-arch"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Authorization Architecture</title>
</info>
<section xml:id="authz-authorities">
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Authorities</title>
<title>Authorization Architecture</title>
</info>
<para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>, all
<interfacename>Authentication</interfacename> implementations store a list of
<interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
that have been granted to the principal. The <interfacename>GrantedAuthority</interfacename>
objects are inserted into the <interfacename>Authentication</interfacename> object by the
<interfacename>AuthenticationManager</interfacename> and are later read by
<interfacename>AccessDecisionManager</interfacename>s when making authorization
decisions.</para>
<para><interfacename>GrantedAuthority</interfacename> is an interface with only one method:
<programlisting>
<section xml:id="authz-authorities">
<info>
<title>Authorities</title>
</info>
<para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>,
all <interfacename>Authentication</interfacename> implementations store a list of
<interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
that have been granted to the principal. The
<interfacename>GrantedAuthority</interfacename> objects are inserted into the
<interfacename>Authentication</interfacename> object by the
<interfacename>AuthenticationManager</interfacename> and are later read by
<interfacename>AccessDecisionManager</interfacename>s when making authorization
decisions.</para>
<para><interfacename>GrantedAuthority</interfacename> is an interface with only one method:
<programlisting>
String getAuthority();
</programlisting> This method allows
<interfacename>AccessDecisionManager</interfacename>s to obtain a precise
<literal>String</literal> representation of the
<interfacename>GrantedAuthority</interfacename>. By returning a representation as a
<literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be easily
<quote>read</quote> by most <interfacename>AccessDecisionManager</interfacename>s. If a
<interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
<literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is considered
<quote>complex</quote> and <literal>getAuthority()</literal> must return
<literal>null</literal>.</para>
<para>An example of a <quote>complex</quote>
<interfacename>GrantedAuthority</interfacename> would be an implementation that stores a list
of operations and authority thresholds that apply to different customer account numbers.
Representing this complex <interfacename>GrantedAuthority</interfacename> as a
<literal>String</literal> would be quite difficult, and as a result the
<literal>getAuthority()</literal> method should return <literal>null</literal>. This will
indicate to any <interfacename>AccessDecisionManager</interfacename> that it will need to
specifically support the <interfacename>GrantedAuthority</interfacename> implementation in
order to understand its contents.</para>
<para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified
<literal>String</literal> to be converted into a
<interfacename>GrantedAuthority</interfacename>. All
<classname>AuthenticationProvider</classname>s included with the security architecture use
<literal>GrantedAuthorityImpl</literal> to populate the
<interfacename>Authentication</interfacename> object.</para>
</section>
<section xml:id="authz-pre-invocation">
<info>
<title>Pre-Invocation Handling</title>
</info>
<para> As we've also seen in the <link xlink:href="#secure-objects">Technical Overview</link>
chapter, Spring Security provides interceptors which control access to secure objects such as
method invocations or web requests. A pre-invocation decision on whether the invocation is
allowed to proceed is made by the <interfacename>AccessDecisionManager</interfacename>. </para>
<section xml:id="authz-access-decision-manager">
<title>The AccessDecisionManager</title>
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the
<classname>AbstractSecurityInterceptor</classname> and is responsible for making final
access control decisions. The <interfacename>AccessDecisionManager</interfacename> interface
contains three methods:
<programlisting>
<interfacename>AccessDecisionManager</interfacename>s to obtain a precise
<literal>String</literal> representation of the
<interfacename>GrantedAuthority</interfacename>. By returning a representation as a
<literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be
easily <quote>read</quote> by most
<interfacename>AccessDecisionManager</interfacename>s. If a
<interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
<literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is
considered <quote>complex</quote> and <literal>getAuthority()</literal> must return
<literal>null</literal>.</para>
<para>An example of a <quote>complex</quote> <interfacename>GrantedAuthority</interfacename>
would be an implementation that stores a list of operations and authority thresholds
that apply to different customer account numbers. Representing this complex
<interfacename>GrantedAuthority</interfacename> as a <literal>String</literal> would be
quite difficult, and as a result the <literal>getAuthority()</literal> method should
return <literal>null</literal>. This will indicate to any
<interfacename>AccessDecisionManager</interfacename> that it will need to specifically
support the <interfacename>GrantedAuthority</interfacename> implementation in order to
understand its contents.</para>
<para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified
<literal>String</literal> to be converted into a
<interfacename>GrantedAuthority</interfacename>. All
<classname>AuthenticationProvider</classname>s included with the security architecture
use <literal>GrantedAuthorityImpl</literal> to populate the
<interfacename>Authentication</interfacename> object.</para>
</section>
<section xml:id="authz-pre-invocation">
<info>
<title>Pre-Invocation Handling</title>
</info>
<para> As we've also seen in the <link xlink:href="#secure-objects">Technical
Overview</link> chapter, Spring Security provides interceptors which control access to
secure objects such as method invocations or web requests. A pre-invocation decision on
whether the invocation is allowed to proceed is made by the
<interfacename>AccessDecisionManager</interfacename>. </para>
<section xml:id="authz-access-decision-manager">
<title>The AccessDecisionManager</title>
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the
<classname>AbstractSecurityInterceptor</classname> and is responsible for making
final access control decisions. The
<interfacename>AccessDecisionManager</interfacename> interface contains three
methods:
<programlisting>
void decide(Authentication authentication, Object secureObject,
List&lt;ConfigAttribute&gt; config) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
</programlisting>
The <interfacename>AccessDecisionManager</interfacename>'s <methodname>decide</methodname>
method is passed all the relevant information it needs in order to make an authorization
decision. In particular, passing the secure <literal>Object</literal> enables those
arguments contained in the actual secure object invocation to be inspected. For example,
let's assume the secure object was a <classname>MethodInvocation</classname>. It would be
easy to query the <classname>MethodInvocation</classname> for any
<literal>Customer</literal> argument, and then implement some sort of security logic in
the <interfacename>AccessDecisionManager</interfacename> to ensure the principal is
permitted to operate on that customer. Implementations are expected to throw an
<literal>AccessDeniedException</literal> if access is denied.</para>
<para>The <literal>supports(ConfigAttribute)</literal> method is called by the
<classname>AbstractSecurityInterceptor</classname> at startup time to determine if the
<interfacename>AccessDecisionManager</interfacename> can process the passed
<literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
called by a security interceptor implementation to ensure the configured
<interfacename>AccessDecisionManager</interfacename> supports the type of secure object
that the security interceptor will present.</para>
</section>
<section xml:id="authz-voting-based">
<title>Voting-Based AccessDecisionManager Implementations</title>
<para>Whilst users can implement their own
<interfacename>AccessDecisionManager</interfacename> to control all aspects of
authorization, Spring Security includes several
<interfacename>AccessDecisionManager</interfacename> implementations that are based on
voting. <xref linkend="authz-access-voting"/> illustrates the relevant classes.</para>
<figure xml:id="authz-access-voting">
<title>Voting Decision Manager</title>
<mediaobject>
<imageobject>
<imagedata align="center" fileref="images/access-decision-voting.png"
format="PNG" scale="75"/>
</imageobject>
</mediaobject>
</figure>
<para>Using this approach, a series of <interfacename>AccessDecisionVoter</interfacename>
implementations are polled on an authorization decision. The
<interfacename>AccessDecisionManager</interfacename> then decides whether or not to throw
an <literal>AccessDeniedException</literal> based on its assessment of the votes.</para>
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three methods:
<programlisting>
The <interfacename>AccessDecisionManager</interfacename>'s
<methodname>decide</methodname> method is passed all the relevant information it
needs in order to make an authorization decision. In particular, passing the secure
<literal>Object</literal> enables those arguments contained in the actual secure
object invocation to be inspected. For example, let's assume the secure object was a
<classname>MethodInvocation</classname>. It would be easy to query the
<classname>MethodInvocation</classname> for any <literal>Customer</literal>
argument, and then implement some sort of security logic in the
<interfacename>AccessDecisionManager</interfacename> to ensure the principal is
permitted to operate on that customer. Implementations are expected to throw an
<literal>AccessDeniedException</literal> if access is denied.</para>
<para>The <literal>supports(ConfigAttribute)</literal> method is called by the
<classname>AbstractSecurityInterceptor</classname> at startup time to determine if
the <interfacename>AccessDecisionManager</interfacename> can process the passed
<literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
called by a security interceptor implementation to ensure the configured
<interfacename>AccessDecisionManager</interfacename> supports the type of secure
object that the security interceptor will present.</para>
</section>
<section xml:id="authz-voting-based">
<title>Voting-Based AccessDecisionManager Implementations</title>
<para>Whilst users can implement their own
<interfacename>AccessDecisionManager</interfacename> to control all aspects of
authorization, Spring Security includes several
<interfacename>AccessDecisionManager</interfacename> implementations that are based
on voting. <xref linkend="authz-access-voting"/> illustrates the relevant
classes.</para>
<figure xml:id="authz-access-voting">
<title>Voting Decision Manager</title>
<mediaobject>
<imageobject>
<imagedata align="center" fileref="images/access-decision-voting.png"
format="PNG" scale="75"/>
</imageobject>
</mediaobject>
</figure>
<para>Using this approach, a series of
<interfacename>AccessDecisionVoter</interfacename> implementations are polled on an
authorization decision. The <interfacename>AccessDecisionManager</interfacename>
then decides whether or not to throw an <literal>AccessDeniedException</literal>
based on its assessment of the votes.</para>
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three
methods:
<programlisting>
int vote(Authentication authentication, Object object, List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
</programlisting>
Concrete implementations return an <literal>int</literal>, with possible values being
reflected in the <interfacename>AccessDecisionVoter</interfacename> static fields
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
<literal>ACCESS_GRANTED</literal>. A voting implementation will return
<literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision. If it
does have an opinion, it must return either <literal>ACCESS_DENIED</literal> or
<literal>ACCESS_GRANTED</literal>.</para>
<para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s provided
with Spring Security that tally the votes. The <literal>ConsensusBased</literal>
implementation will grant or deny access based on the consensus of non-abstain votes.
Properties are provided to control behavior in the event of an equality of votes or if all
votes are abstain. The <literal>AffirmativeBased</literal> implementation will grant access
if one or more <literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny vote will
be ignored, provided there was at least one grant vote). Like the
<literal>ConsensusBased</literal> implementation, there is a parameter that controls the
behavior if all voters abstain. The <literal>UnanimousBased</literal> provider expects
unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access, ignoring
abstains. It will deny access if there is any <literal>ACCESS_DENIED</literal> vote. Like
the other implementations, there is a parameter that controls the behaviour if all voters
abstain.</para>
<para>It is possible to implement a custom
<interfacename>AccessDecisionManager</interfacename> that tallies votes differently. For
example, votes from a particular <interfacename>AccessDecisionVoter</interfacename> might
receive additional weighting, whilst a deny vote from a particular voter may have a veto
effect.</para>
<section xml:id="authz-role-voter">
<title><classname>RoleVoter</classname></title>
<para> The most commonly used <interfacename>AccessDecisionVoter</interfacename> provided
with Spring Security is the simple <classname>RoleVoter</classname>, which treats
configuration attributes as simple role names and votes to grant access if the user has
been assigned that role.</para>
<para>It will vote if any <interfacename>ConfigAttribute</interfacename> begins with the
prefix <literal>ROLE_</literal>. It will vote to grant access if there is a
<interfacename>GrantedAuthority</interfacename> which returns a
<literal>String</literal> representation (via the <literal>getAuthority()</literal>
method) exactly equal to one or more <literal>ConfigAttributes</literal> starting with the
prefix <literal>ROLE_</literal>. If there is no exact match of any
<literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
<literal>RoleVoter</literal> will vote to deny access. If no
<literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the voter will
abstain.</para>
</section>
<section xml:id="authz-authenticated-voter">
<title><classname>AuthenticatedVoter</classname></title>
<para> Another voter which we've implicitly seen is the
<classname>AuthenticatedVoter</classname>, which can be used to differentiate between
anonymous, fully-authenticated and remember-me authenticated users. Many sites allow
certain limited access under remember-me authentication, but require a user to confirm
their identity by logging in for full access.</para>
<para>When we've used the attribute <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal> to grant
anonymous access, this attribute was being processed by the
<classname>AuthenticatedVoter</classname>. See the Javadoc for this class for more
information. </para>
</section>
<section>
<title>Custom Voters</title>
<para>It is also possible to implement a custom
<interfacename>AccessDecisionVoter</interfacename>. Several examples are provided in
Spring Security unit tests, including <literal>ContactSecurityVoter</literal> and
<literal>DenyVoter</literal>. The <literal>ContactSecurityVoter</literal> abstains from
voting decisions where a <literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
<literal>ConfigAttribute</literal> is not found. If voting, it queries the
<classname>MethodInvocation</classname> to extract the owner of the
<literal>Contact</literal> object that is subject of the method call. It votes to grant
access if the <literal>Contact</literal> owner matches the principal presented in the
<interfacename>Authentication</interfacename> object. It could have just as easily
compared the <literal>Contact</literal> owner with some
<interfacename>GrantedAuthority</interfacename> the
<interfacename>Authentication</interfacename> object presented. All of this is achieved
with relatively few lines of code and demonstrates the flexibility of the authorization
model.</para>
</section>
Concrete implementations return an <literal>int</literal>, with possible values
being reflected in the <interfacename>AccessDecisionVoter</interfacename> static
fields <literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
<literal>ACCESS_GRANTED</literal>. A voting implementation will return
<literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision.
If it does have an opinion, it must return either <literal>ACCESS_DENIED</literal>
or <literal>ACCESS_GRANTED</literal>.</para>
<para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s
provided with Spring Security that tally the votes. The
<literal>ConsensusBased</literal> implementation will grant or deny access based on
the consensus of non-abstain votes. Properties are provided to control behavior in
the event of an equality of votes or if all votes are abstain. The
<literal>AffirmativeBased</literal> implementation will grant access if one or more
<literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny vote will be
ignored, provided there was at least one grant vote). Like the
<literal>ConsensusBased</literal> implementation, there is a parameter that controls
the behavior if all voters abstain. The <literal>UnanimousBased</literal> provider
expects unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access,
ignoring abstains. It will deny access if there is any
<literal>ACCESS_DENIED</literal> vote. Like the other implementations, there is a
parameter that controls the behaviour if all voters abstain.</para>
<para>It is possible to implement a custom
<interfacename>AccessDecisionManager</interfacename> that tallies votes differently.
For example, votes from a particular
<interfacename>AccessDecisionVoter</interfacename> might receive additional
weighting, whilst a deny vote from a particular voter may have a veto effect.</para>
<section xml:id="authz-role-voter">
<title><classname>RoleVoter</classname></title>
<para> The most commonly used <interfacename>AccessDecisionVoter</interfacename>
provided with Spring Security is the simple <classname>RoleVoter</classname>,
which treats configuration attributes as simple role names and votes to grant
access if the user has been assigned that role.</para>
<para>It will vote if any <interfacename>ConfigAttribute</interfacename> begins with
the prefix <literal>ROLE_</literal>. It will vote to grant access if there is a
<interfacename>GrantedAuthority</interfacename> which returns a
<literal>String</literal> representation (via the
<literal>getAuthority()</literal> method) exactly equal to one or more
<literal>ConfigAttributes</literal> starting with the prefix
<literal>ROLE_</literal>. If there is no exact match of any
<literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
<literal>RoleVoter</literal> will vote to deny access. If no
<literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the
voter will abstain.</para>
</section>
<section xml:id="authz-authenticated-voter">
<title><classname>AuthenticatedVoter</classname></title>
<para> Another voter which we've implicitly seen is the
<classname>AuthenticatedVoter</classname>, which can be used to differentiate
between anonymous, fully-authenticated and remember-me authenticated users. Many
sites allow certain limited access under remember-me authentication, but require
a user to confirm their identity by logging in for full access.</para>
<para>When we've used the attribute <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>
to grant anonymous access, this attribute was being processed by the
<classname>AuthenticatedVoter</classname>. See the Javadoc for this class for
more information. </para>
</section>
<section>
<title>Custom Voters</title>
<para>It is also possible to implement a custom
<interfacename>AccessDecisionVoter</interfacename>. Several examples are
provided in Spring Security unit tests, including
<literal>ContactSecurityVoter</literal> and <literal>DenyVoter</literal>. The
<literal>ContactSecurityVoter</literal> abstains from voting decisions where a
<literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
<literal>ConfigAttribute</literal> is not found. If voting, it queries the
<classname>MethodInvocation</classname> to extract the owner of the
<literal>Contact</literal> object that is subject of the method call. It votes
to grant access if the <literal>Contact</literal> owner matches the principal
presented in the <interfacename>Authentication</interfacename> object. It could
have just as easily compared the <literal>Contact</literal> owner with some
<interfacename>GrantedAuthority</interfacename> the
<interfacename>Authentication</interfacename> object presented. All of this is
achieved with relatively few lines of code and demonstrates the flexibility of
the authorization model.</para>
</section>
</section>
</section>
</section>
<section xml:id="authz-after-invocation-handling">
<info>
<title>After Invocation Handling</title>
</info>
<para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
<classname>AbstractSecurityInterceptor</classname> before proceeding with the secure object
invocation, some applications need a way of modifying the object actually returned by the
secure object invocation. Whilst you could easily implement your own AOP concern to achieve
this, Spring Security provides a convenient hook that has several concrete implementations
that integrate with its ACL capabilities.</para>
<para><xref linkend="authz-after-invocation"/> illustrates Spring Security's
<literal>AfterInvocationManager</literal> and its concrete implementations. <figure
xml:id="authz-after-invocation">
<title>After Invocation Implementation</title>
<mediaobject>
<imageobject>
<imagedata align="center" fileref="images/after-invocation.png" format="PNG" scale="75"/>
</imageobject>
</mediaobject>
</figure></para>
<para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal> has a
single concrete implementation, <literal>AfterInvocationProviderManager</literal>, which polls
a list of <literal>AfterInvocationProvider</literal>s. Each
<literal>AfterInvocationProvider</literal> is allowed to modify the return object or throw
an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify the object,
as the result of the previous provider is passed to the next in the list.</para>
<para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you will
still need configuration attributes that allow the
<classname>MethodSecurityInterceptor</classname>'s
<interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're using
the typical Spring Security included <interfacename>AccessDecisionManager</interfacename>
implementations, having no configuration attributes defined for a particular secure method
invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to abstain from
voting. In turn, if the <interfacename>AccessDecisionManager</interfacename> property
"<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
<literal>AccessDeniedException</literal> will be thrown. You may avoid this potential issue
by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
<literal>true</literal> (although this is generally not recommended) or (ii) simply ensure
that there is at least one configuration attribute that an
<interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal> or
<literal>ROLE_AUTHENTICATED</literal> configuration attribute.</para>
<!-- TODO: Move to ACL section and add reference here -->
<!--
<section xml:id="authz-after-invocation-handling">
<info>
<title>After Invocation Handling</title>
</info>
<para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
<classname>AbstractSecurityInterceptor</classname> before proceeding with the secure
object invocation, some applications need a way of modifying the object actually
returned by the secure object invocation. Whilst you could easily implement your own AOP
concern to achieve this, Spring Security provides a convenient hook that has several
concrete implementations that integrate with its ACL capabilities.</para>
<para><xref linkend="authz-after-invocation"/> illustrates Spring Security's
<literal>AfterInvocationManager</literal> and its concrete implementations. <figure
xml:id="authz-after-invocation">
<title>After Invocation Implementation</title>
<mediaobject>
<imageobject>
<imagedata align="center" fileref="images/after-invocation.png" format="PNG"
scale="75"/>
</imageobject>
</mediaobject>
</figure></para>
<para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal>
has a single concrete implementation, <literal>AfterInvocationProviderManager</literal>,
which polls a list of <literal>AfterInvocationProvider</literal>s. Each
<literal>AfterInvocationProvider</literal> is allowed to modify the return object or
throw an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify
the object, as the result of the previous provider is passed to the next in the
list.</para>
<para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you
will still need configuration attributes that allow the
<classname>MethodSecurityInterceptor</classname>'s
<interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're
using the typical Spring Security included
<interfacename>AccessDecisionManager</interfacename> implementations, having no
configuration attributes defined for a particular secure method invocation will cause
each <interfacename>AccessDecisionVoter</interfacename> to abstain from voting. In turn,
if the <interfacename>AccessDecisionManager</interfacename> property
"<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
<literal>AccessDeniedException</literal> will be thrown. You may avoid this potential
issue by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
<literal>true</literal> (although this is generally not recommended) or (ii) simply
ensure that there is at least one configuration attribute that an
<interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal>
or <literal>ROLE_AUTHENTICATED</literal> configuration attribute.</para>
<!-- TODO: Move to ACL section and add reference here -->
<!--
<section xml:id="after-invocation-acl-aware">
<info>
<title>ACL-Aware AfterInvocationProviders</title>
@ -285,8 +299,8 @@ boolean supports(Class clazz);
<para>The Contacts sample application demonstrates these two
<literal>AfterInvocationProvider</literal>s.</para>
</section> -->
</section>
<!-- TODO: Move taglibs to a separate chapter which describes them all
</section>
<!-- TODO: Move taglibs to a separate chapter which describes them all
<section xml:id="authorization-taglibs">
<info>
<title>Authorization Tag Libraries</title>

View File

@ -18,7 +18,7 @@
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>BasicAuthenticationFilter</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>
@ -27,11 +27,10 @@
<title>Configuration</title>
</info>
<para>To implement HTTP Basic Authentication, you need to add a
<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[
<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="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
@ -42,21 +41,20 @@
class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="Name Of Your Realm"/>
</bean>]]>
</programlisting>
</para>
</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>BasicAuthenticationEntryPoint</literal>, which returns a 401 response
with a suitable header to retry HTTP Basic authentication. If authentication is
<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>
<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>
<interfacename>AuthenticationEntryPoint</interfacename> is called.</para>
</section>
</section>
<section xml:id="digest-processing-filter">
@ -70,7 +68,7 @@
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
@ -86,11 +84,10 @@
expirationTime: The date and time when the nonce expires, expressed in milliseconds
key: A private key to prevent modification of the nonce token
</programlisting>
</para>
</programlisting> </para>
<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
<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
@ -99,11 +96,11 @@
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>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>
<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>DigestAuthenticationEntryPoint</classname>'s
<literal>nonceValiditySeconds</literal> parameter will depend on your application.
<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,21 +108,19 @@
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>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[
<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="digestFilter" class=
"org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<property name="userDetailsService" ref="jdbcDaoImpl"/>
@ -139,18 +134,17 @@
<property name="key" value="acegi"/>
<property name="nonceValiditySeconds" value="10"/>
</bean>]]>
</programlisting>
</para>
</programlisting> </para>
<para>The configured <interfacename>UserDetailsService</interfacename> is needed because
<literal>DigestAuthenticationFilter</literal> must have direct access to the
clear text password of a user. Digest Authentication will NOT work if you are using
<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
<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

View File

@ -1,44 +1,46 @@
<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/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 3.0
supports CAS 3. At the time of writing, the CAS server was at version 3.3.</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.3 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>
<!--
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/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 3.0 supports CAS 3. At the time of writing, the CAS server was at version
3.3.</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.3 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>
<!--
<section xml:id="cas-sequence">
<title>Spring Security and CAS Interaction Sequence</title>
@ -243,36 +245,34 @@
Let's now look at how this is configured</para>
</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 <classname>ServiceProperties</classname> bean to your application
context. This represents your CAS service:</para>
<para>
<programlisting><![CDATA[
</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 <classname>ServiceProperties</classname> bean to your
application context. This represents your CAS 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>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
(assuming you're using a namespace configuration):</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
(assuming you're using a namespace configuration):</para>
<para> <programlisting><![CDATA[
<security:http entry-point-ref="casEntryPoint">
...
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
@ -289,21 +289,22 @@
<property name="serviceProperties" ref="serviceProperties"/>
</bean>
]]>
</programlisting>
</para>
<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 <classname>CasAuthenticationFilter</classname> has very similar properties to the
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based logins).
</para>
<para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have its
<literal>authenticationEntryPoint</literal> property set to the
<classname>CasAuthenticationEntryPoint</classname> bean.</para>
<para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the
<classname>ServiceProperties</classname> 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[
</programlisting> </para>
<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 <classname>CasAuthenticationFilter</classname> has very similar properties to the
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based
logins). </para>
<para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have
its <literal>authenticationEntryPoint</literal> property set to the
<classname>CasAuthenticationEntryPoint</classname> bean.</para>
<para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the
<classname>ServiceProperties</classname> 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[
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager>
@ -325,13 +326,14 @@
...
</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>
</section>
<!--
<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

View File

@ -15,7 +15,7 @@
protocol, such as HTTPS.</para>
<para>An important issue in considering transport security is that of session hijacking.
Your web container manages a <literal>HttpSession</literal> by reference to a
<literal>jsessionid</literal> that is sent to user agents either via a cookie or URL
<literal>jsessionid</literal> that is sent to user agents either via a cookie or URL
rewriting. If the <literal>jsessionid</literal> is ever sent over HTTP, there is a
possibility that session identifier can be intercepted and used to impersonate the user
after they complete the authentication process. This is because most web containers
@ -23,19 +23,18 @@
to HTTPS pages.</para>
<para>If session hijacking is considered too significant a risk for your particular
application, the only option is to use HTTPS for every request. This means the
<literal>jsessionid</literal> is never sent across an insecure channel. You will
need to ensure your <literal>web.xml</literal>-defined
<literal>&lt;welcome-file&gt;</literal> points to an HTTPS location, and the
application never directs the user to an HTTP location. Spring Security provides a
solution to assist with the latter.</para>
<literal>jsessionid</literal> is never sent across an insecure channel. You will need to
ensure your <literal>web.xml</literal>-defined <literal>&lt;welcome-file&gt;</literal>
points to an HTTPS location, and the application never directs the user to an HTTP
location. Spring Security provides a solution to assist with the latter.</para>
</section>
<section xml:id="channel-security-config">
<info>
<title>Configuration</title>
</info>
<para>Channel security is supported by the <link xlink:href="#ns-requires-channel">security
namespace</link> by means of the <literal>requires-channel</literal> attribute on
the <literal>&lt;intercept-url&gt;</literal> element and this is the simplest (and
namespace</link> by means of the <literal>requires-channel</literal> attribute on the
<literal>&lt;intercept-url&gt;</literal> element and this is the simplest (and
recommended approach).</para>
<para>To configure channel security explicitly, you would define the following the filter in
your application context: <programlisting><![CDATA[
@ -74,14 +73,14 @@
supported by the <literal>ChannelProcessingFilter</literal>.</para>
<para>The <literal>ChannelProcessingFilter</literal> operates by filtering all web requests
and determining the configuration attributes that apply. It then delegates to the
<literal>ChannelDecisionManager</literal>. The default implementation,
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most cases. It
simply delegates to the list of configured <literal>ChannelProcessor</literal>
instances. The attribute <literal>ANY_CHANNEL</literal> can be used to override this
behaviour and skip a particular URL. Otherwise, a <literal>ChannelProcessor</literal>
will review the request, and if it is unhappy with the request (e.g. if it was received
across the incorrect transport protocol), it will perform a redirect, throw an exception
or take whatever other action is appropriate.</para>
<literal>ChannelDecisionManager</literal>. The default implementation,
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most cases. It simply
delegates to the list of configured <literal>ChannelProcessor</literal> instances. The
attribute <literal>ANY_CHANNEL</literal> can be used to override this behaviour and skip
a particular URL. Otherwise, a <literal>ChannelProcessor</literal> will review the
request, and if it is unhappy with the request (e.g. if it was received across the
incorrect transport protocol), it will perform a redirect, throw an exception or take
whatever other action is appropriate.</para>
<para>Included with Spring Security are two concrete <literal>ChannelProcessor</literal>
implementations: <literal>SecureChannelProcessor</literal> ensures requests with a
configuration attribute of <literal>REQUIRES_SECURE_CHANNEL</literal> are received over
@ -89,27 +88,26 @@
configuration attribute of <literal>REQUIRES_INSECURE_CHANNEL</literal> are received
over HTTP. Both implementations delegate to a <literal>ChannelEntryPoint</literal> if
the required transport protocol is not used. The two
<literal>ChannelEntryPoint</literal> implementations included with Spring Security
<literal>ChannelEntryPoint</literal> implementations included with Spring Security
simply redirect the request to HTTP and HTTPS as appropriate. Appropriate defaults are
assigned to the <literal>ChannelProcessor</literal> implementations for the
configuration attribute keywords they respond to and the
<interfacename>ChannelEntryPoint</interfacename> they delegate to, although you have
the ability to override these using the application context.</para>
<interfacename>ChannelEntryPoint</interfacename> they delegate to, although you have the
ability to override these using the application context.</para>
<para>Note that the redirections are absolute (eg
<literal>http://www.company.com:8080/app/page</literal>), not relative (eg
<literal>/app/page</literal>). During testing it was discovered that Internet
Explorer 6 Service Pack 1 has a bug whereby it does not respond correctly to a
redirection instruction which also changes the port to use. Accordingly, absolute URLs
are used in conjunction with bug detection logic in the
<classname>PortResolverImpl</classname> that is wired up by default to many Spring
Security beans. Please refer to the JavaDocs for <classname>PortResolverImpl</classname>
for further details.</para>
<literal>http://www.company.com:8080/app/page</literal>), not relative (eg
<literal>/app/page</literal>). During testing it was discovered that Internet Explorer 6
Service Pack 1 has a bug whereby it does not respond correctly to a redirection
instruction which also changes the port to use. Accordingly, absolute URLs are used in
conjunction with bug detection logic in the <classname>PortResolverImpl</classname> that
is wired up by default to many Spring Security beans. Please refer to the JavaDocs for
<classname>PortResolverImpl</classname> for further details.</para>
<para>You should note that using a secure channel is recommended if usernames and passwords
are to be kept secure during the login process. If you do decide to use
<classname>ChannelProcessingFilter</classname> with form-based login, please ensure
that your login page is set to <literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
<literal>LoginUrlAuthenticationEntryPoint.forceHttps</literal> property is
<literal>true</literal>.</para>
<classname>ChannelProcessingFilter</classname> with form-based login, please ensure that
your login page is set to <literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
<literal>LoginUrlAuthenticationEntryPoint.forceHttps</literal> property is
<literal>true</literal>.</para>
</section>
<section xml:id="channel-security-conclusion">
<info>
@ -118,25 +116,25 @@
<para>Once configured, using the channel security filter is very easy. Simply request pages
without regard to the protocol (ie HTTP or HTTPS) or port (eg 80, 8080, 443, 8443 etc).
Obviously you'll still need a way of making the initial request (probably via the
<literal>web.xml</literal>
<literal>&lt;welcome-file&gt;</literal> or a well-known home page URL), but once this is
done the filter will perform redirects as defined by your application context.</para>
<literal>web.xml</literal> <literal>&lt;welcome-file&gt;</literal> or a well-known home
page URL), but once this is done the filter will perform redirects as defined by your
application context.</para>
<para>You can also add your own <literal>ChannelProcessor</literal> implementations to the
<literal>ChannelDecisionManagerImpl</literal>. For example, you might set a
<literal>HttpSession</literal> attribute when a human user is detected via a "enter
the contents of this graphic" procedure. Your <literal>ChannelProcessor</literal> would
<literal>ChannelDecisionManagerImpl</literal>. For example, you might set a
<literal>HttpSession</literal> attribute when a human user is detected via a "enter the
contents of this graphic" procedure. Your <literal>ChannelProcessor</literal> would
respond to say <literal>REQUIRES_HUMAN_USER</literal> configuration attributes and
redirect to an appropriate entry point to start the human user validation process if the
<literal>HttpSession</literal> attribute is not currently set.</para>
<literal>HttpSession</literal> attribute is not currently set.</para>
<para>To decide whether a security check belongs in a <literal>ChannelProcessor</literal> or
an <interfacename>AccessDecisionVoter</interfacename>, remember that the former is
designed to handle unauthenticated requests, whilst the latter is designed to handle
authenticated requests. The latter therefore has access to the granted authorities of
the authenticated principal. In addition, problems detected by a
<literal>ChannelProcessor</literal> will generally cause an HTTP/HTTPS redirection
so its requirements can be met, whilst problems detected by an
<interfacename>AccessDecisionVoter</interfacename> will ultimately result in an
<literal>AccessDeniedException</literal> (depending on the governing
<interfacename>AccessDecisionManager</interfacename>).</para>
<literal>ChannelProcessor</literal> will generally cause an HTTP/HTTPS redirection so
its requirements can be met, whilst problems detected by an
<interfacename>AccessDecisionVoter</interfacename> will ultimately result in an
<literal>AccessDeniedException</literal> (depending on the governing
<interfacename>AccessDecisionManager</interfacename>).</para>
</section>
</chapter>

View File

@ -17,8 +17,8 @@
enhancement requests if you include corresponding unit tests. This is necessary to
ensure project test coverage is adequately maintained.</para>
<para>You can access the issue tracker at <link
xlink:href="http://jira.springsource.org/browse/SEC"
>http://jira.springsource.org/browse/SEC</link>. </para>
xlink:href="http://jira.springsource.org/browse/SEC"
>http://jira.springsource.org/browse/SEC</link>. </para>
</section>
<section xml:id="becoming-involved">
<info>
@ -42,7 +42,7 @@
</info>
<para>Questions and comments on Spring Security are welcome. You can use the Spring
Community Forum web site at <uri xlink:href="http://forum.springsource.org"
>http://forum.springsource.org</uri> to discuss Spring Security with other users of
the framework. Remember to use JIRA for bug reports, as explained above.</para>
>http://forum.springsource.org</uri> to discuss Spring Security with other users of the
framework. Remember to use JIRA for bug reports, as explained above.</para>
</section>
</chapter>

View File

@ -9,12 +9,12 @@
<title><classname>FilterSecurityInterceptor</classname></title>
<para>We've already seen <classname>FilterSecurityInterceptor</classname> briefly when
discussing <link xlink:href="#tech-intro-access-control">access-control in
general</link>, and we've already used it with the namespace where the
<literal>&lt;intercept-url></literal> elements are combined to configure it
internally. Now we'll see how to explicitly configure it for use with a
<classname>FilterChainProxy</classname>, along with its companion filter
<classname>ExceptionTranslationFilter</classname>. A typical configuration example
is shown below: <programlisting language="xml"><![CDATA[
general</link>, and we've already used it with the namespace where the
<literal>&lt;intercept-url></literal> elements are combined to configure it internally.
Now we'll see how to explicitly configure it for use with a
<classname>FilterChainProxy</classname>, along with its companion filter
<classname>ExceptionTranslationFilter</classname>. A typical configuration example is
shown below: <programlisting language="xml"><![CDATA[
<bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
@ -28,43 +28,41 @@
</bean>]]></programlisting></para>
<para><classname>FilterSecurityInterceptor</classname> is responsible for handling the
security of HTTP resources. It requires a reference to an
<interfacename>AuthenticationManager</interfacename> and an
<interfacename>AccessDecisionManager</interfacename>. It is also supplied with
<interfacename>AuthenticationManager</interfacename> and an
<interfacename>AccessDecisionManager</interfacename>. It is also supplied with
configuration attributes that apply to different HTTP URL requests. Refer back to <link
xlink:href="#tech-intro-config-attributes">the original discussion on these</link>
in the technical introduction.</para>
xlink:href="#tech-intro-config-attributes">the original discussion on these</link> in
the technical introduction.</para>
<para>The <classname>FilterSecurityInterceptor</classname> can be configured with
configuration attributes in two ways. The first, which is shown above, is using the
<literal>&lt;filter-security-metadata-source&gt;</literal> namespace element. This
is similar to the <literal>&lt;filter-chain-map&gt;</literal> used to configure a
<classname>FilterChainProxy</classname> but the
<literal>&lt;intercept-url&gt;</literal> child elements only use the
<literal>pattern</literal> and <literal>access</literal> attributes. Commas are used
to delimit the different configuration attributes that apply to each HTTP URL. The
second option is to write your own
<literal>&lt;filter-security-metadata-source&gt;</literal> namespace element. This is
similar to the <literal>&lt;filter-chain-map&gt;</literal> used to configure a
<classname>FilterChainProxy</classname> but the <literal>&lt;intercept-url&gt;</literal>
child elements only use the <literal>pattern</literal> and <literal>access</literal>
attributes. Commas are used to delimit the different configuration attributes that apply
to each HTTP URL. The second option is to write your own
<interfacename>SecurityMetadataSource</interfacename>, but this is beyond the scope of
this document. Irrespective of the approach used, the
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning a
<literal>List&lt;ConfigAttribute&gt;</literal> containing all of the configuration
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning a
<literal>List&lt;ConfigAttribute&gt;</literal> containing all of the configuration
attributes associated with a single secure HTTP URL.</para>
<para>It should be noted that the
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal> method
actually expects an instance of
<interfacename>FilterSecurityMetadataSource</interfacename>. This is a marker
interface which subclasses <interfacename>SecurityMetadataSource</interfacename>. It
simply denotes the <interfacename>SecurityMetadataSource</interfacename> understands
<classname>FilterInvocation</classname>s. In the interests of simplicity we'll
continue to refer to the
<interfacename>FilterInvocationSecurityMetadataSource</interfacename> as a
<interfacename>SecurityMetadataSource</interfacename>, as the distinction is of
little relevance to most users.</para>
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal> method actually
expects an instance of <interfacename>FilterSecurityMetadataSource</interfacename>. This
is a marker interface which subclasses
<interfacename>SecurityMetadataSource</interfacename>. It simply denotes the
<interfacename>SecurityMetadataSource</interfacename> understands
<classname>FilterInvocation</classname>s. In the interests of simplicity we'll continue
to refer to the <interfacename>FilterInvocationSecurityMetadataSource</interfacename> as
a <interfacename>SecurityMetadataSource</interfacename>, as the distinction is of little
relevance to most users.</para>
<para>The <interfacename>SecurityMetadataSource</interfacename> created by the namespace
syntax obtains the configuration attributes for a particular
<classname>FilterInvocation</classname> by matching the request URL against the
<classname>FilterInvocation</classname> by matching the request URL against the
configured <literal>pattern</literal> attributes. This behaves in the same way as it
does for namespace configuration. The default is to treat all expressions as Apache Ant
paths and regular expressions are also supported for more complex cases. The
<literal>path-type</literal> attribute is used to specify the type of pattern being
<literal>path-type</literal> attribute is used to specify the type of pattern being
used. It is not possible to mix expression syntaxes within the same definition. As an
example, the previous configuration using regular expressions instead of Ant paths would
be written as follows:</para>
@ -84,10 +82,10 @@
<para>Patterns are always evaluated in the order they are defined. Thus it is important that
more specific patterns are defined higher in the list than less specific patterns. This
is reflected in our example above, where the more specific
<literal>/secure/super/</literal> pattern appears higher than the less specific
<literal>/secure/</literal> pattern. If they were reversed, the
<literal>/secure/</literal> pattern would always match and the
<literal>/secure/super/</literal> pattern would never be evaluated.</para>
<literal>/secure/super/</literal> pattern appears higher than the less specific
<literal>/secure/</literal> pattern. If they were reversed, the
<literal>/secure/</literal> pattern would always match and the
<literal>/secure/super/</literal> pattern would never be evaluated.</para>
<!--
TODO: Put in FAQ instead. Or drop.
<para>As with other security interceptors, the <literal>validateConfigAttributes</literal>
@ -101,10 +99,9 @@
-->
</section>
<section xml:id="exception-translation-filter">
<title>
<classname>ExceptionTranslationFilter</classname></title>
<title> <classname>ExceptionTranslationFilter</classname></title>
<para>The <classname>ExceptionTranslationFilter</classname> sits above the
<classname>FilterSecurityInterceptor</classname> in the security filter stack. It
<classname>FilterSecurityInterceptor</classname> in the security filter stack. It
doesn't do any actual security enforcement itself, but handles exceptions thrown by the
security interceptors and provides suitable and HTTP responses. <programlisting language="xml"><![CDATA[
<bean id="exceptionTranslationFilter"
@ -127,11 +124,11 @@
<title><interfacename>AuthenticationEntryPoint</interfacename></title>
<para> The <interfacename>AuthenticationEntryPoint</interfacename> will be called if the
user requests a secure HTTP resource but they are not authenticated. An appropriate
<exceptionname>AuthenticationException</exceptionname> or
<exceptionname>AccessDeniedException</exceptionname> will be thrown by a
security interceptor further down the call stack, triggering the
<methodname>commence</methodname> method on the entry point. This does the job
of presenting the appropriate response to the user so that authentication can begin.
<exceptionname>AuthenticationException</exceptionname> or
<exceptionname>AccessDeniedException</exceptionname> will be thrown by a security
interceptor further down the call stack, triggering the
<methodname>commence</methodname> method on the entry point. This does the job of
presenting the appropriate response to the user so that authentication can begin.
The one we've used here is <classname>LoginUrlAuthenticationEntryPoint</classname>,
which redirects the request to a different URL (typically a login page). The actual
implementation used will depend on the authentication mechanism you want to be used
@ -153,32 +150,31 @@
<para>If an <exceptionname>AccessDeniedException</exceptionname> is thrown and a user
has already been authenticated, then this means that an operation has been attempted
for which they don't have enough permissions. In this case,
<classname>ExceptionTranslationFilter</classname> will invoke a second strategy,
the <interfacename>AccessDeniedHandler</interfacename>. By default, an
<classname>AccessDeniedHandlerImpl</classname> is used, which just sends a 403
<classname>ExceptionTranslationFilter</classname> will invoke a second strategy, the
<interfacename>AccessDeniedHandler</interfacename>. By default, an
<classname>AccessDeniedHandlerImpl</classname> is used, which just sends a 403
(Forbidden) response to the client. Alternatively you can configure an instance
explicitly (as in the above example) and set an error page URL which it will
forwards the request to <footnote>
<para>We use a forward so that the SecurityContextHolder still contains details
of the principal, which may be useful for displaying to the user. In old
releases of Spring Security we relied upon the servlet container to handle a
403 error message, which lacked this useful contextual information.</para>
<para>We use a forward so that the SecurityContextHolder still contains details of
the principal, which may be useful for displaying to the user. In old releases
of Spring Security we relied upon the servlet container to handle a 403 error
message, which lacked this useful contextual information.</para>
</footnote>. This can be a simple <quote>access denied</quote> page, such as a JSP,
or it could be a more complex handler such as an MVC controller. And of course, you
can implement the interface yourself and use your own implementation. </para>
<para>It's also possible to supply a custom
<interfacename>AccessDeniedHandler</interfacename> when you're using the
namespace to configure your application. See <link
xlink:href="#nsa-access-denied-handler">the namespace appendix</link> for more
details.</para>
<interfacename>AccessDeniedHandler</interfacename> when you're using the namespace
to configure your application. See <link xlink:href="#nsa-access-denied-handler">the
namespace appendix</link> for more details.</para>
</section>
</section>
<section xml:id="security-context-persistence-filter">
<title><classname>SecurityContextPersistenceFilter</classname></title>
<para> We covered the purpose of this all-important filter in the <link
xlink:href="#tech-intro-sec-context-persistence">Technical Overview</link> chapter
so you might want to re-read that section at this point. Let's first take a look at how
you would configure it for use with a <classname>FilterChainProxy</classname>. A basic
xlink:href="#tech-intro-sec-context-persistence">Technical Overview</link> chapter so
you might want to re-read that section at this point. Let's first take a look at how you
would configure it for use with a <classname>FilterChainProxy</classname>. A basic
configuration only requires the bean itself <programlisting><![CDATA[
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
@ -205,19 +201,19 @@ public interface SecurityContextRepository {
incoming request and response objects, allowing the implementation to replace these
with wrapper classes. The returned contents will be passed to the filter chain. </para>
<para> The default implementation is
<classname>HttpSessionSecurityContextRepository</classname>, which stores the
<classname>HttpSessionSecurityContextRepository</classname>, which stores the
security context as an <interfacename>HttpSession</interfacename> attribute <footnote>
<para>In Spring Security 2.0 and earlier, this filter was called
<classname>HttpSessionContextIntegrationFilter</classname> and performed
all the work of storing the context was performed by the filter itself. If
you were familiar with this class, then most of the configuration options
which were available can now be found on
<classname>HttpSessionSecurityContextRepository</classname>. </para>
<para>In Spring Security 2.0 and earlier, this filter was called
<classname>HttpSessionContextIntegrationFilter</classname> and performed all the
work of storing the context was performed by the filter itself. If you were
familiar with this class, then most of the configuration options which were
available can now be found on
<classname>HttpSessionSecurityContextRepository</classname>. </para>
</footnote>. The most important configuration parameter for this implementation is
the <literal>allowSessionCreation</literal> property, which defaults to
<literal>true</literal>, thus allowing the class to create a session if it needs
one to store the security context for an authenticated user (it won't create one
unless authentication has taken place and the contents of the security context have
<literal>true</literal>, thus allowing the class to create a session if it needs one
to store the security context for an authenticated user (it won't create one unless
authentication has taken place and the contents of the security context have
changed). If you don't want a session to be created, then you can set this property
to <literal>false</literal>: <programlisting language="xml"><![CDATA[
<bean id="securityContextPersistenceFilter"
@ -229,7 +225,7 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
</property>
</bean>
]]></programlisting> Alternatively you could provide a null implementation of the
<interfacename>SecurityContextRepository</interfacename> interface, which will
<interfacename>SecurityContextRepository</interfacename> interface, which will
prevent the security context from being stored, even if a session has already been
created during the request. </para>
</section>
@ -242,35 +238,35 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
alternatives. The only thing that's missing now is an actual authentication mechanism,
something that will allow a user to authenticate. This filter is the most commonly used
authentication filter and the one that is most often customized <footnote>
<para>For historical reasons, prior to Spring Security 3.0, this filter was called
<classname>AuthenticationProcessingFilter</classname> and the entry point
was called <classname>AuthenticationProcessingFilterEntryPoint</classname>.
Since the framework now supports many different forms of authentication, they
have both been given more specific names in 3.0.</para>
<para>For historical reasons, prior to Spring Security 3.0, this filter was called
<classname>AuthenticationProcessingFilter</classname> and the entry point was called
<classname>AuthenticationProcessingFilterEntryPoint</classname>. Since the framework
now supports many different forms of authentication, they have both been given more
specific names in 3.0.</para>
</footnote>. It also provides the implementation used by the
<literal>&lt;form-login&gt;</literal> element from the namespace. There are three
stages required to configure it. <orderedlist>
<listitem>
<para>Configure a <classname>LoginUrlAuthenticationEntryPoint</classname> with
the URL of the login page, just as we did above, and set it on the
<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). <!-- TODO: link --></para>
</listitem>
<literal>&lt;form-login&gt;</literal> element from the namespace. There are three stages
required to configure it. <orderedlist>
<listitem>
<para>Configure a <classname>LoginUrlAuthenticationEntryPoint</classname> with the
URL of the login page, just as we did above, and set it on the
<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). <!-- 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[
<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="authenticationFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
@ -280,38 +276,37 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
<section xml:id="form-login-flow-handling">
<title>Application Flow on Authentication Success and Failure</title>
<para> The filter calls the configured
<interfacename>AuthenticationManager</interfacename> to process each
authentication request. The destination following a successful authentication or an
authentication failure is controlled by the
<interfacename>AuthenticationSuccessHandler</interfacename> and
<interfacename>AuthenticationFailureHandler</interfacename> strategy interfaces,
<interfacename>AuthenticationManager</interfacename> to process each authentication
request. The destination following a successful authentication or an authentication
failure is controlled by the
<interfacename>AuthenticationSuccessHandler</interfacename> and
<interfacename>AuthenticationFailureHandler</interfacename> strategy interfaces,
respectively. The filter has properties which allow you to set these so you can
customize the behaviour completely <footnote>
<para>In versions prior to 3.0, the application flow at this point had evolved
to a stage was controlled by a mix of properties on this class and strategy
plugins. The decision was made for 3.0 to refactor the code to make these
two strategies entirely responsible. </para>
<para>In versions prior to 3.0, the application flow at this point had evolved to a
stage was controlled by a mix of properties on this class and strategy plugins.
The decision was made for 3.0 to refactor the code to make these two strategies
entirely responsible. </para>
</footnote>. Some standard implementations are supplied such as
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look
at the Javadoc for these classes to see how they work. </para>
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at
the Javadoc for these classes to see how they work. </para>
<para>If authentication is successful, the resulting
<interfacename>Authentication</interfacename> object will be placed into the
<classname>SecurityContextHolder</classname>. The configured
<interfacename>AuthenticationSuccessHandler</interfacename> will then be called
to either redirect or forward the user to the appropriate destination. By default a
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname> is used,
which means that the user will be redirected to the original destination they
requested before they were asked to login. <note>
<para> The <classname>ExceptionTranslationFilter</classname> caches the original
request a user makes. When the user authenticates, the request handler makes
use of this cached request to obtain the original URL and redirect to it.
The original request is then rebuilt and used as an alternative. </para>
<interfacename>Authentication</interfacename> object will be placed into the
<classname>SecurityContextHolder</classname>. The configured
<interfacename>AuthenticationSuccessHandler</interfacename> will then be called to
either redirect or forward the user to the appropriate destination. By default a
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname> is used, which
means that the user will be redirected to the original destination they requested
before they were asked to login. <note>
<para> The <classname>ExceptionTranslationFilter</classname> caches the original
request a user makes. When the user authenticates, the request handler makes use
of this cached request to obtain the original URL and redirect to it. The
original request is then rebuilt and used as an alternative. </para>
</note> If authentication fails, the configured
<interfacename>AuthenticationFailureHandler</interfacename> will be invoked.
</para>
<interfacename>AuthenticationFailureHandler</interfacename> will be invoked. </para>
</section>
</section>
</chapter>

View File

@ -4,42 +4,40 @@
<para> Now that we have a high-level overview of the Spring Security architecture and its core
classes, let's take a closer look at one or two of the core interfaces and their
implementations, in particular the <interfacename>AuthenticationManager</interfacename>,
<interfacename>UserDetailsService</interfacename> and the
<interfacename>AccessDecisionManager</interfacename>. These crop up regularly throughout
the remainder of this document so it's important you know how they are configured and how
they operate. </para>
<interfacename>UserDetailsService</interfacename> and the
<interfacename>AccessDecisionManager</interfacename>. These crop up regularly throughout the
remainder of this document so it's important you know how they are configured and how they
operate. </para>
<section xml:id="core-services-authentication-manager">
<title>The <interfacename>AuthenticationManager</interfacename>,
<classname>ProviderManager</classname> and
<classname>AuthenticationProvider</classname>s</title>
<classname>ProviderManager</classname> and
<classname>AuthenticationProvider</classname>s</title>
<para>The <interfacename>AuthenticationManager</interfacename> is just an interface, so the
implementation can be anything we choose, but how does it work in practice? What if we
need to check multiple authentication databases or a combination of different
authentication services such as a database and an LDAP server?</para>
<para>The default implementation in Spring Security is called
<classname>ProviderManager</classname> and rather than handling the authentication
<classname>ProviderManager</classname> and rather than handling the authentication
request itself, it delegates to a list of configured
<classname>AuthenticationProvider</classname>s, each of which is queried in turn to
see if it can perform the authentication. Each provider will either throw an exception
or return a fully populated <interfacename>Authentication</interfacename> object.
Remember our good friends, <interfacename>UserDetails</interfacename> and
<interfacename>UserDetailsService</interfacename>? If not, head back to the previous
<classname>AuthenticationProvider</classname>s, each of which is queried in turn to see
if it can perform the authentication. Each provider will either throw an exception or
return a fully populated <interfacename>Authentication</interfacename> object. Remember
our good friends, <interfacename>UserDetails</interfacename> and
<interfacename>UserDetailsService</interfacename>? If not, head back to the previous
chapter and refresh your memory. The most common approach to verifying an authentication
request is to load the corresponding <interfacename>UserDetails</interfacename> and
check the loaded password against the one that has been entered by the user. This is the
approach used by the <classname>DaoAuthenticationProvider</classname> (see below). The
loaded <interfacename>UserDetails</interfacename> object - and particularly the
<literal>GrantedAuthority</literal>s it contains - will be used when building the
fully populated <interfacename>Authentication</interfacename> object which is returned
from a successful authentication and stored in the
<classname>SecurityContext</classname>. </para>
<para> If you are using the namespace, an instance of
<classname>ProviderManager</classname> is created and maintained internally, and
you add providers to it by using the namespace authentication provider elements
(see <link xlink:href="#ns-auth-manager">the namespace chapter</link>). In this
case, you should not declare a <classname>ProviderManager</classname> bean in your
application context. However, if you are not using the namespace then you would declare
it like so: <programlisting language="xml"><![CDATA[
<literal>GrantedAuthority</literal>s it contains - will be used when building the fully
populated <interfacename>Authentication</interfacename> object which is returned from a
successful authentication and stored in the <classname>SecurityContext</classname>. </para>
<para> If you are using the namespace, an instance of <classname>ProviderManager</classname>
is created and maintained internally, and you add providers to it by using the namespace
authentication provider elements (see <link xlink:href="#ns-auth-manager">the namespace
chapter</link>). In this case, you should not declare a
<classname>ProviderManager</classname> bean in your application context. However, if you
are not using the namespace then you would declare it like so: <programlisting language="xml"><![CDATA[
<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
@ -54,16 +52,16 @@
is implied by the use of a <literal>List</literal>), with each provider able to attempt
authentication, or skip authentication by simply returning <literal>null</literal>. If
all implementations return null, the <literal>ProviderManager</literal> will throw a
<exceptionname>ProviderNotFoundException</exceptionname>. If you're interested in
<exceptionname>ProviderNotFoundException</exceptionname>. If you're interested in
learning more about chaining providers, please refer to the
<literal>ProviderManager</literal> JavaDocs.</para>
<literal>ProviderManager</literal> JavaDocs.</para>
<para> Authentication mechanisms such as a web form-login processing filter are injected
with a reference to the <interfacename>ProviderManager</interfacename> and will call it
to handle their authentication requests. The providers you require will sometimes be
interchangeable with the authentication mechanisms, while at other times they will
depend on a specific authentication mechanism. For example,
<classname>DaoAuthenticationProvider</classname> and
<classname>LdapAuthenticationProvider</classname> are compatible with any mechanism
<classname>DaoAuthenticationProvider</classname> and
<classname>LdapAuthenticationProvider</classname> are compatible with any mechanism
which submits a simple username/password authentication request and so will work with
form-based logins or HTTP Basic authentication. On the other hand, some authentication
mechanisms create an authentication request object which can only be interpreted by a
@ -78,49 +76,47 @@
<para>The simplest <interfacename>AuthenticationProvider</interfacename> implemented by
Spring Security is <literal>DaoAuthenticationProvider</literal>, which is also one
of the earliest supported by the framework. It leverages a
<interfacename>UserDetailsService</interfacename> (as a DAO) in order to lookup
the username, password and <interfacename>GrantedAuthority</interfacename>s. It
<interfacename>UserDetailsService</interfacename> (as a DAO) in order to lookup the
username, password and <interfacename>GrantedAuthority</interfacename>s. It
authenticates the user simply by comparing the password submitted in a
<classname>UsernamePasswordAuthenticationToken</classname> against the one
loaded by the <interfacename>UserDetailsService</interfacename>. Configuring the
provider is quite simple: <programlisting language="xml"><![CDATA[
<classname>UsernamePasswordAuthenticationToken</classname> against the one loaded by
the <interfacename>UserDetailsService</interfacename>. Configuring the provider is
quite simple: <programlisting language="xml"><![CDATA[
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
<property name="saltSource" ref bean="saltSource"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
</bean>]]></programlisting> The <interfacename>PasswordEncoder</interfacename> and
<interfacename>SaltSource</interfacename> are optional. A
<interfacename>PasswordEncoder</interfacename> provides encoding and decoding of
<interfacename>SaltSource</interfacename> are optional. A
<interfacename>PasswordEncoder</interfacename> provides encoding and decoding of
passwords presented in the <interfacename>UserDetails</interfacename> object that is
returned from the configured <interfacename>UserDetailsService</interfacename>. A
<interfacename>SaltSource</interfacename> enables the passwords to be populated
with a "salt", which enhances the security of the passwords in the authentication
<interfacename>SaltSource</interfacename> enables the passwords to be populated with
a "salt", which enhances the security of the passwords in the authentication
repository. These will be discussed in more detail <link
xlink:href="core-services-password-encodin">below</link>. </para>
xlink:href="core-services-password-encodin">below</link>. </para>
</section>
</section>
<section>
<title><interfacename>UserDetailsService</interfacename> Implementations</title>
<para>As mentioned in the earlier in this reference guide, most authentication providers
take advantage of the <interfacename>UserDetails</interfacename> and
<interfacename>UserDetailsService</interfacename> interfaces. Recall that the
contract for <interfacename>UserDetailsService</interfacename> is a single
method:</para>
<interfacename>UserDetailsService</interfacename> interfaces. Recall that the contract
for <interfacename>UserDetailsService</interfacename> is a single method:</para>
<para>
<programlisting>
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
</programlisting>
</para>
</programlisting> </para>
<para>The returned <interfacename>UserDetails</interfacename> is an interface that provides
getters that guarantee non-null provision of authentication information such as the
username, password, granted authorities and whether the user account is enabled or
disabled. Most authentication providers will use a
<interfacename>UserDetailsService</interfacename>, even if the username and password
are not actually used as part of the authentication decision. They may use the returned
<interfacename>UserDetails</interfacename> object just for its
<literal>GrantedAuthority</literal> information, because some other system (like
LDAP or X.509 or CAS etc) has undertaken the responsibility of actually validating the
<interfacename>UserDetailsService</interfacename>, even if the username and password are
not actually used as part of the authentication decision. They may use the returned
<interfacename>UserDetails</interfacename> object just for its
<literal>GrantedAuthority</literal> information, because some other system (like LDAP or
X.509 or CAS etc) has undertaken the responsibility of actually validating the
credentials.</para>
<para>Given <interfacename>UserDetailsService</interfacename> is so simple to implement, it
should be easy for users to retrieve authentication information using a persistence
@ -133,8 +129,8 @@
many applications do not require such complexity. This is particularly true if
you're building a prototype application or just starting integrating Spring
Security, when you don't really want to spend time configuring databases or writing
<interfacename>UserDetailsService</interfacename> implementations. For this sort
of situation, a simple option is to use the <literal>user-service</literal> element
<interfacename>UserDetailsService</interfacename> implementations. For this sort of
situation, a simple option is to use the <literal>user-service</literal> element
from the security <link xlink:href="#ns-minimal">namespace</link>: <programlisting><![CDATA[
<user-service id="userDetailsService">
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
@ -158,11 +154,10 @@
Spring JDBC is used, so it avoids the complexity of a fully-featured object
relational mapper (ORM) just to store user details. If your application does use an
ORM tool, you might prefer to write a custom
<interfacename>UserDetailsService</interfacename> to reuse the mapping files
you've probably already created. Returning to <literal>JdbcDaoImpl</literal>, an
example configuration is shown below:</para>
<para>
<programlisting language="xml"><![CDATA[
<interfacename>UserDetailsService</interfacename> to reuse the mapping files you've
probably already created. Returning to <literal>JdbcDaoImpl</literal>, an example
configuration is shown below:</para>
<para> <programlisting language="xml"><![CDATA[
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
@ -173,19 +168,17 @@
<bean id="userDetailsService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> ]]> </programlisting>
</para>
</bean> ]]> </programlisting> </para>
<para>You can use different relational database management systems by modifying the
<literal>DriverManagerDataSource</literal> shown above. You can also use a
global data source obtained from JNDI, as with any other Spring
configuration.</para>
<literal>DriverManagerDataSource</literal> shown above. You can also use a global
data source obtained from JNDI, as with any other Spring configuration.</para>
<section>
<title>Authority Groups</title>
<para>By default, <classname>JdbcDaoImpl</classname> loads the authorities for a
single user with the assumption that the authorities are mapped directly to
users (see the <link xlink:href="#appendix-schema">database schema
appendix</link>). An alternative approach is to partition the authorities
into groups and assign groups to the user. Some people prefer this approach as a
appendix</link>). An alternative approach is to partition the authorities into
groups and assign groups to the user. Some people prefer this approach as a
means of administering user rights. See the <classname>JdbcDaoImpl</classname>
Javadoc for more information on how to enable the use of group authorities. The
group schema is also included in the appendix.</para>
@ -218,7 +211,7 @@
<programlisting>
5f4dcc3b5aa765d61d8327deb882cf99
</programlisting> A hash is
<quote>one-way</quote> in the sense that it is very difficult (effectively
<quote>one-way</quote> in the sense that it is very difficult (effectively
impossible) to obtain the original input given the hash value, or indeed any
possible input which would produce that hash value. This property makes hash values
very useful for authentication purposes. They can be stored in your user database as
@ -231,16 +224,16 @@
<para> One potential problem with the use of password hashes that it is relatively easy
to get round the one-way property of the hash if a common word is used for the
input. For example, if you search for the hash value
<literal>5f4dcc3b5aa765d61d8327deb882cf99</literal> using google, you will
quickly find the original word <quote>password</quote>. In a similar way, an
attacker can build a dictionary of hashes from a standard word list and use this to
lookup the original password. One way to help prevent this is to have a suitably
strong password policy to try to prevent common words from being used. Another is to
use a <quote>salt</quote> when calculating the hashes. This is an additional string
of known data for each user which is combined with the password before calculating
the hash. Ideally the data should be as random as possible, but in practice any salt
<literal>5f4dcc3b5aa765d61d8327deb882cf99</literal> using google, you will quickly
find the original word <quote>password</quote>. In a similar way, an attacker can
build a dictionary of hashes from a standard word list and use this to lookup the
original password. One way to help prevent this is to have a suitably strong
password policy to try to prevent common words from being used. Another is to use a
<quote>salt</quote> when calculating the hashes. This is an additional string of
known data for each user which is combined with the password before calculating the
hash. Ideally the data should be as random as possible, but in practice any salt
value is usually preferable to none. Spring Security has a
<interfacename>SaltSource</interfacename> interface which can be used by an
<interfacename>SaltSource</interfacename> interface which can be used by an
authentication provider to generate a salt value for a particular user. Using a salt
means that an attacker has to build a separate dictionary of hashes for each salt
value, making the attack more complicated (but not impossible).</para>
@ -248,32 +241,32 @@
<section>
<title> Hashing and Authentication</title>
<para>When an authentication provider (such as Spring Security's
<classname>DaoAuthenticationProvider</classname> needs to check the password in
a submitted authentication request against the known value for a user, and the
stored password is encoded in some way, then the submitted value must be encoded
using exactly the same algorithm. It's up to you to check that these are compatible
as Spring Security has no control over the persistent values. If you add password
<classname>DaoAuthenticationProvider</classname> needs to check the password in a
submitted authentication request against the known value for a user, and the stored
password is encoded in some way, then the submitted value must be encoded using
exactly the same algorithm. It's up to you to check that these are compatible as
Spring Security has no control over the persistent values. If you add password
hashing to your authentication configuration in Spring Security, and your database
contains plaintext passwords, then there is no way authentication can succeed. Even
if you are aware that your database is using MD5 to encode the passwords, for
example, and your application is configured to use Spring Security's
<classname>Md5PasswordEncoder</classname>, there are still things that can go
wrong. The database may have the passwords encoded in Base 64, for example while the
enocoder is using hexadecimal strings (the default)<footnote><para>You can configure
the encoder to use Base 64 instead of hex by setting the
<literal>encodeHashAsBase64</literal> property to
<literal>true</literal>. Check the Javadoc for
<classname>MessageDigestPasswordEncoder</classname> and its parent
classes for more information.</para></footnote>. Alternatively your database
may be using upper-case while the output from the encoder is lower-case. Make sure
you write a test to check the output from your configured password encoder with a
known password and salt combination and check that it matches the database value
before going further and attempting to authenticate through your application. For
more information on the default method for merging salt and password, see the
Javadoc for <classname>BasePasswordEncoder</classname>. If you want to generate
encoded passwords directly in Java for storage in your user database, then you can
use the <methodname>encodePassword</methodname> method on the
<interfacename>PasswordEncoder</interfacename>.</para>
<classname>Md5PasswordEncoder</classname>, there are still things that can go wrong.
The database may have the passwords encoded in Base 64, for example while the
enocoder is using hexadecimal strings (the default)<footnote>
<para>You can configure the encoder to use Base 64 instead of hex by setting the
<literal>encodeHashAsBase64</literal> property to <literal>true</literal>. Check
the Javadoc for <classname>MessageDigestPasswordEncoder</classname> and its
parent classes for more information.</para>
</footnote>. Alternatively your database may be using upper-case while the output
from the encoder is lower-case. Make sure you write a test to check the output from
your configured password encoder with a known password and salt combination and
check that it matches the database value before going further and attempting to
authenticate through your application. For more information on the default method
for merging salt and password, see the Javadoc for
<classname>BasePasswordEncoder</classname>. If you want to generate encoded
passwords directly in Java for storage in your user database, then you can use the
<methodname>encodePassword</methodname> method on the
<interfacename>PasswordEncoder</interfacename>.</para>
</section>
</section>
</chapter>

View File

@ -7,10 +7,10 @@
<title>Overview</title>
</info>
<para>Spring Security includes a production-quality
<classname>AuthenticationProvider</classname> implementation called
<literal>DaoAuthenticationProvider</literal>. This authentication provider is
compatible with all of the authentication mechanisms that generate a
<literal>UsernamePasswordAuthenticationToken</literal>, and is probably the most
<classname>AuthenticationProvider</classname> implementation called
<literal>DaoAuthenticationProvider</literal>. This authentication provider is compatible
with all of the authentication mechanisms that generate a
<literal>UsernamePasswordAuthenticationToken</literal>, and is probably the most
commonly used provider in the framework. Like most of the other authentication
providers, the DaoAuthenticationProvider leverages a UserDetailsService in order to
lookup the username, password and GrantedAuthority[]s. Unlike most of the other
@ -27,8 +27,7 @@
at the start of this part of the reference guide), and ensuring a suitable
authentication mechanism is configured to present a UsernamePasswordAuthenticationToken,
the configuration of the provider itself is rather simple:</para>
<para>
<programlisting>
<para> <programlisting>
<![CDATA[
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
@ -36,15 +35,14 @@
<property name="saltSource" ref bean="saltSource"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
</bean> ]]>
</programlisting>
</para>
</programlisting> </para>
<para>The <literal>PasswordEncoder</literal> and <literal>SaltSource</literal> are optional.
A <literal>PasswordEncoder</literal> provides encoding and decoding of passwords
presented in the <interfacename>UserDetails</interfacename> object that is returned from
the configured <interfacename>UserDetailsService</interfacename>. A
<literal>SaltSource</literal> enables the passwords to be populated with a "salt",
which enhances the security of the passwords in the authentication repository.
<literal>PasswordEncoder</literal> implementations are provided with Spring Security
<literal>SaltSource</literal> enables the passwords to be populated with a "salt", which
enhances the security of the passwords in the authentication repository.
<literal>PasswordEncoder</literal> implementations are provided with Spring Security
covering MD5, SHA and cleartext encodings. Two <literal>SaltSource</literal>
implementations are also provided: <literal>SystemWideSaltSource</literal> which encodes
all passwords with the same salt, and <literal>ReflectionSaltSource</literal>, which
@ -53,16 +51,14 @@
optional features.</para>
<para>In addition to the properties above, the <literal>DaoAuthenticationProvider</literal>
supports optional caching of <interfacename>UserDetails</interfacename> objects. The
<literal>UserCache</literal> interface enables the
<literal>DaoAuthenticationProvider</literal> to place a
<interfacename>UserDetails</interfacename> object into the cache, and retrieve it
from the cache upon subsequent authentication attempts for the same username. By default
the <literal>DaoAuthenticationProvider</literal> uses the
<literal>NullUserCache</literal>, which performs no caching. A usable caching
implementation is also provided, <literal>EhCacheBasedUserCache</literal>, which is
configured as follows:</para>
<para>
<programlisting><![CDATA[
<literal>UserCache</literal> interface enables the
<literal>DaoAuthenticationProvider</literal> to place a
<interfacename>UserDetails</interfacename> object into the cache, and retrieve it from
the cache upon subsequent authentication attempts for the same username. By default the
<literal>DaoAuthenticationProvider</literal> uses the <literal>NullUserCache</literal>,
which performs no caching. A usable caching implementation is also provided,
<literal>EhCacheBasedUserCache</literal>, which is configured as follows:</para>
<para> <programlisting><![CDATA[
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
@ -82,15 +78,14 @@
class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
<property name="cache" ref="userCacheBackend"/>
</bean>]]>
</programlisting>
</para>
</programlisting> </para>
<para>All Spring Security EH-CACHE implementations (including
<literal>EhCacheBasedUserCache</literal>) require an EH-CACHE
<literal>Cache</literal> object. The <literal>Cache</literal> object can be obtained
from wherever you like, although we recommend you use Spring's factory classes as shown
in the above configuration. If using Spring's factory classes, please refer to the
Spring documentation for further details on how to optimise the cache storage location,
memory usage, eviction policies, timeouts etc.</para>
<literal>EhCacheBasedUserCache</literal>) require an EH-CACHE <literal>Cache</literal>
object. The <literal>Cache</literal> object can be obtained from wherever you like,
although we recommend you use Spring's factory classes as shown in the above
configuration. If using Spring's factory classes, please refer to the Spring
documentation for further details on how to optimise the cache storage location, memory
usage, eviction policies, timeouts etc.</para>
<note>
<para>In the majority of cases, where your application is a stateful web application,
you don't need to use a cache as the user's authentication information will be

View File

@ -9,9 +9,9 @@
<para>Complex applications often will find the need to define access permissions not simply
at a web request or method invocation level. Instead, security decisions need to
comprise both who (<interfacename>Authentication</interfacename>), where
(<classname>MethodInvocation</classname>) and what (<literal>SomeDomainObject</literal>). In
other words, authorization decisions also need to consider the actual domain object
instance subject of a method invocation.</para>
(<classname>MethodInvocation</classname>) and what
(<literal>SomeDomainObject</literal>). In other words, authorization decisions also need
to consider the actual domain object instance subject of a method invocation.</para>
<para>Imagine you're designing an application for a pet clinic. There will be two main
groups of users of your Spring-based application: staff of the pet clinic, as well as
the pet clinic's customers. The staff will have access to all of the data, whilst your
@ -19,52 +19,52 @@
interesting, your customers can allow other users to see their customer records, such as
their "puppy preschool" mentor or president of their local "Pony Club". Using Spring
Security as the foundation, you have several approaches that can be used:<orderedlist
inheritnum="ignore" continuation="restarts">
<listitem>
<para>Write your business methods to enforce the security. You could consult a
collection within the <literal>Customer</literal> domain object instance to
determine which users have access. By using the
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
you'll be able to access the <interfacename>Authentication</interfacename>
inheritnum="ignore" continuation="restarts">
<listitem>
<para>Write your business methods to enforce the security. You could consult a
collection within the <literal>Customer</literal> domain object instance to
determine which users have access. By using the
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
you'll be able to access the <interfacename>Authentication</interfacename>
object.</para>
</listitem>
<listitem>
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the security
from the <literal>GrantedAuthority[]</literal>s stored in the
<interfacename>Authentication</interfacename> object. This would mean your
<interfacename>AuthenticationManager</interfacename> would need to populate the
<interfacename>Authentication</interfacename> with custom
<interfacename>GrantedAuthority</interfacename>[]s representing each of the
<literal>Customer</literal> domain object instances the principal has
access to.</para>
</listitem>
<listitem>
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the security
and open the target <literal>Customer</literal> domain object directly. This
would mean your voter needs access to a DAO that allows it to retrieve the
<literal>Customer</literal> object. It would then access the
<literal>Customer</literal> object's collection of approved users and
make the appropriate decision.</para>
</listitem>
</listitem>
<listitem>
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the
security from the <literal>GrantedAuthority[]</literal>s stored in the
<interfacename>Authentication</interfacename> object. This would mean your
<interfacename>AuthenticationManager</interfacename> would need to populate the
<interfacename>Authentication</interfacename> with custom
<interfacename>GrantedAuthority</interfacename>[]s representing each of the
<literal>Customer</literal> domain object instances the principal has access
to.</para>
</listitem>
<listitem>
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the
security and open the target <literal>Customer</literal> domain object directly.
This would mean your voter needs access to a DAO that allows it to retrieve the
<literal>Customer</literal> object. It would then access the
<literal>Customer</literal> object's collection of approved users and make the
appropriate decision.</para>
</listitem>
</orderedlist></para>
<para>Each one of these approaches is perfectly legitimate. However, the first couples your
authorization checking to your business code. The main problems with this include the
enhanced difficulty of unit testing and the fact it would be more difficult to reuse the
<literal>Customer</literal> authorization logic elsewhere. Obtaining the
<literal>GrantedAuthority[]</literal>s from the <interfacename>Authentication</interfacename>
object is also fine, but will not scale to large numbers of
<literal>Customer</literal>s. If a user might be able to access 5,000
<literal>Customer</literal> authorization logic elsewhere. Obtaining the
<literal>GrantedAuthority[]</literal>s from the
<interfacename>Authentication</interfacename> object is also fine, but will not scale to
large numbers of <literal>Customer</literal>s. If a user might be able to access 5,000
<literal>Customer</literal>s (unlikely in this case, but imagine if it were a popular
vet for a large Pony Club!) the amount of memory consumed and time required to construct
the <interfacename>Authentication</interfacename> object would be undesirable. The final method,
opening the <literal>Customer</literal> directly from external code, is probably the
best of the three. It achieves separation of concerns, and doesn't misuse memory or CPU
cycles, but it is still inefficient in that both the
<interfacename>AccessDecisionVoter</interfacename> and the eventual business method itself will
perform a call to the DAO responsible for retrieving the <literal>Customer</literal>
object. Two accesses per method invocation is clearly undesirable. In addition, with
every approach listed you'll need to write your own access control list (ACL)
persistence and business logic from scratch.</para>
the <interfacename>Authentication</interfacename> object would be undesirable. The final
method, opening the <literal>Customer</literal> directly from external code, is probably
the best of the three. It achieves separation of concerns, and doesn't misuse memory or
CPU cycles, but it is still inefficient in that both the
<interfacename>AccessDecisionVoter</interfacename> and the eventual business method
itself will perform a call to the DAO responsible for retrieving the
<literal>Customer</literal> object. Two accesses per method invocation is clearly
undesirable. In addition, with every approach listed you'll need to write your own
access control list (ACL) persistence and business logic from scratch.</para>
<para>Fortunately, there is another alternative, which we'll talk about below.</para>
</section>
<section xml:id="domain-acls-key-concepts">
@ -78,18 +78,18 @@
of an access control list (ACL). Every domain object instance in your system has its own
ACL, and the ACL records details of who can and can't work with that domain object. With
this in mind, Spring Security delivers three main ACL-related capabilities to your application:<itemizedlist>
<listitem>
<para>A way of efficiently retrieving ACL entries for all of your domain objects
(and modifying those ACLs)</para>
</listitem>
<listitem>
<para>A way of ensuring a given principal is permitted to work with your
objects, before methods are called</para>
</listitem>
<listitem>
<para>A way of ensuring a given principal is permitted to work with your objects
(or something they return), after methods are called</para>
</listitem>
<listitem>
<para>A way of efficiently retrieving ACL entries for all of your domain objects
(and modifying those ACLs)</para>
</listitem>
<listitem>
<para>A way of ensuring a given principal is permitted to work with your objects,
before methods are called</para>
</listitem>
<listitem>
<para>A way of ensuring a given principal is permitted to work with your objects (or
something they return), after methods are called</para>
</listitem>
</itemizedlist></para>
<para>As indicated by the first bullet point, one of the main capabilities of the Spring
Security ACL module is providing a high-performance way of retrieving ACLs. This ACL
@ -105,49 +105,46 @@
main tables used by default in the implementation. The tables are presented below in
order of size in a typical Spring Security ACL deployment, with the table with the most
rows listed last:</para>
<para>
<itemizedlist>
<listitem>
<para>ACL_SID allows us to uniquely identify any principal or authority in the
system ("SID" stands for "security identity"). The only columns are the ID,
a textual representation of the SID, and a flag to indicate whether the
textual representation refers to a principal name or a
<interfacename>GrantedAuthority</interfacename>. Thus, there is a single row for
each unique principal or <interfacename>GrantedAuthority</interfacename>. When used in
the context of receiving a permission, a SID is generally called a
"recipient".</para>
</listitem>
<listitem>
<para>ACL_CLASS allows us to uniquely identify any domain object class in the
system. The only columns are the ID and the Java class name. Thus, there is
a single row for each unique Class we wish to store ACL permissions
for.</para>
</listitem>
<listitem>
<para>ACL_OBJECT_IDENTITY stores information for each unique domain object
instance in the system. Columns include the ID, a foreign key to the
ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance
we're providing information for, the parent, a foreign key to the ACL_SID
table to represent the owner of the domain object instance, and whether we
allow ACL entries to inherit from any parent ACL. We have a single row for
every domain object instance we're storing ACL permissions for.</para>
</listitem>
<listitem>
<para>Finally, ACL_ENTRY stores the individual permissions assigned to each
recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the
recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not,
and the integer bit mask that represents the actual permission being granted
or denied. We have a single row for every recipient that receives a
permission to work with a domain object.</para>
</listitem>
</itemizedlist>
</para>
<para> <itemizedlist>
<listitem>
<para>ACL_SID allows us to uniquely identify any principal or authority in the
system ("SID" stands for "security identity"). The only columns are the ID, a
textual representation of the SID, and a flag to indicate whether the textual
representation refers to a principal name or a
<interfacename>GrantedAuthority</interfacename>. Thus, there is a single row for
each unique principal or <interfacename>GrantedAuthority</interfacename>. When
used in the context of receiving a permission, a SID is generally called a
"recipient".</para>
</listitem>
<listitem>
<para>ACL_CLASS allows us to uniquely identify any domain object class in the
system. The only columns are the ID and the Java class name. Thus, there is a
single row for each unique Class we wish to store ACL permissions for.</para>
</listitem>
<listitem>
<para>ACL_OBJECT_IDENTITY stores information for each unique domain object instance
in the system. Columns include the ID, a foreign key to the ACL_CLASS table, a
unique identifier so we know which ACL_CLASS instance we're providing
information for, the parent, a foreign key to the ACL_SID table to represent the
owner of the domain object instance, and whether we allow ACL entries to inherit
from any parent ACL. We have a single row for every domain object instance we're
storing ACL permissions for.</para>
</listitem>
<listitem>
<para>Finally, ACL_ENTRY stores the individual permissions assigned to each
recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the
recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not, and
the integer bit mask that represents the actual permission being granted or
denied. We have a single row for every recipient that receives a permission to
work with a domain object.</para>
</listitem>
</itemizedlist> </para>
<para>As mentioned in the last paragraph, the ACL system uses integer bit masking. Don't
worry, you need not be aware of the finer points of bit shifting to use the ACL system,
but suffice to say that we have 32 bits we can switch on or off. Each of these bits
represents a permission, and by default the permissions are read (bit 0), write (bit 1),
create (bit 2), delete (bit 3) and administer (bit 4). It's easy to implement your own
<literal>Permission</literal> instance if you wish to use other permissions, and the
<literal>Permission</literal> instance if you wish to use other permissions, and the
remainder of the ACL framework will operate without knowledge of your extensions.</para>
<para>It is important to understand that the number of domain objects in your system has
absolutely no bearing on the fact we've chosen to use integer bit masking. Whilst you
@ -162,16 +159,16 @@
<listitem>
<para><literal>Acl</literal>: Every domain object has one and only one
<literal>Acl</literal> object, which internally holds the
<literal>AccessControlEntry</literal>s as well as knows the owner of the
<literal>Acl</literal>. An Acl does not refer directly to the domain object,
but instead to an <literal>ObjectIdentity</literal>. The <literal>Acl</literal>
is stored in the ACL_OBJECT_IDENTITY table.</para>
<literal>AccessControlEntry</literal>s as well as knows the owner of the
<literal>Acl</literal>. An Acl does not refer directly to the domain object, but
instead to an <literal>ObjectIdentity</literal>. The <literal>Acl</literal> is
stored in the ACL_OBJECT_IDENTITY table.</para>
</listitem>
<listitem>
<para><literal>AccessControlEntry</literal>: An <literal>Acl</literal> holds
multiple <literal>AccessControlEntry</literal>s, which are often abbreviated as
ACEs in the framework. Each ACE refers to a specific tuple of
<literal>Permission</literal>, <literal>Sid</literal> and
<literal>Permission</literal>, <literal>Sid</literal> and
<literal>Acl</literal>. An ACE can also be granting or non-granting and contain
audit settings. The ACE is stored in the ACL_ENTRY table.</para>
</listitem>
@ -183,11 +180,11 @@
</listitem>
<listitem>
<para><literal>Sid</literal>: The ACL module needs to refer to principals and
<literal>GrantedAuthority[]</literal>s. A level of indirection is provided
by the <literal>Sid</literal> interface, which is an abbreviation of "security
<literal>GrantedAuthority[]</literal>s. A level of indirection is provided by
the <literal>Sid</literal> interface, which is an abbreviation of "security
identity". Common classes include <literal>PrincipalSid</literal> (to represent
the principal inside an <interfacename>Authentication</interfacename> object) and
<literal>GrantedAuthoritySid</literal>. The security identity information is
the principal inside an <interfacename>Authentication</interfacename> object)
and <literal>GrantedAuthoritySid</literal>. The security identity information is
stored in the ACL_SID table.</para>
</listitem>
<listitem>
@ -198,8 +195,8 @@
<listitem>
<para><literal>AclService</literal>: Retrieves the <literal>Acl</literal> applicable
for a given <literal>ObjectIdentity</literal>. In the included implementation
(<literal>JdbcAclService</literal>), retrieval operations are delegated to a
<literal>LookupStrategy</literal>. The <literal>LookupStrategy</literal>
(<literal>JdbcAclService</literal>), retrieval operations are delegated to a
<literal>LookupStrategy</literal>. The <literal>LookupStrategy</literal>
provides a highly optimized strategy for retrieving ACL information, using
batched retrievals <literal>(BasicLookupStrategy</literal>) and supporting
custom implementations that leverage materialized views, hierarchical queries
@ -227,16 +224,15 @@
ACL information somewhere. This necessitates the instantiation of a
<literal>DataSource</literal> using Spring. The <literal>DataSource</literal> is then
injected into a <literal>JdbcMutableAclService</literal> and
<literal>BasicLookupStrategy</literal> instance. The latter provides
high-performance ACL retrieval capabilities, and the former provides mutator
capabilities. Refer to one of the samples that ship with Spring Security for an example
configuration. You'll also need to populate the database with the four ACL-specific
tables listed in the last section (refer to the ACL samples for the appropriate SQL
statements).</para>
<literal>BasicLookupStrategy</literal> instance. The latter provides high-performance
ACL retrieval capabilities, and the former provides mutator capabilities. Refer to one
of the samples that ship with Spring Security for an example configuration. You'll also
need to populate the database with the four ACL-specific tables listed in the last
section (refer to the ACL samples for the appropriate SQL statements).</para>
<para>Once you've created the required schema and instantiated
<literal>JdbcMutableAclService</literal>, you'll next need to ensure your domain
model supports interoperability with the Spring Security ACL package. Hopefully
<literal>ObjectIdentityImpl</literal> will prove sufficient, as it provides a large
<literal>JdbcMutableAclService</literal>, you'll next need to ensure your domain model
supports interoperability with the Spring Security ACL package. Hopefully
<literal>ObjectIdentityImpl</literal> will prove sufficient, as it provides a large
number of ways in which it can be used. Most people will have domain objects that
contain a <literal>public Serializable getId()</literal> method. If the return type is
long, or compatible with long (eg an int), you will find you need not give further
@ -272,7 +268,8 @@ aclService.updateAcl(acl);
position in the Acl the new entry will be inserted. In the example above, we're just
putting the new ACE at the end of the existing ACEs. The final argument is a boolean
indicating whether the ACE is granting or denying. Most of the time it will be granting
(true), but if it is denying (false), the permissions are effectively being blocked.</para>
(true), but if it is denying (false), the permissions are effectively being
blocked.</para>
<para>Spring Security does not provide any special integration to automatically create,
update or delete ACLs as part of your DAO or repository operations. Instead, you will
need to write code like shown above for your individual domain objects. It's worth
@ -282,15 +279,15 @@ aclService.updateAcl(acl);
<para>Once you've used the above techniques to store some ACL information in the database,
the next step is to actually use the ACL information as part of authorization decision
logic. You have a number of choices here. You could write your own
<interfacename>AccessDecisionVoter</interfacename> or <literal>AfterInvocationProvider</literal>
that respectively fires before or after a method invocation. Such classes would use
<literal>AclService</literal> to retrieve the relevant ACL and then call
<literal>Acl.isGranted(Permission[] permission, Sid[] sids, boolean
administrativeMode)</literal> to decide whether permission is granted or denied.
<interfacename>AccessDecisionVoter</interfacename> or
<literal>AfterInvocationProvider</literal> that respectively fires before or after a
method invocation. Such classes would use <literal>AclService</literal> to retrieve the
relevant ACL and then call <literal>Acl.isGranted(Permission[] permission, Sid[] sids,
boolean administrativeMode)</literal> to decide whether permission is granted or denied.
Alternately, you could use our <literal>AclEntryVoter</literal>,
<literal>AclEntryAfterInvocationProvider</literal> or
<literal>AclEntryAfterInvocationCollectionFilteringProvider</literal> classes. All
of these classes provide a declarative-based approach to evaluating ACL information at
<literal>AclEntryAfterInvocationProvider</literal> or
<literal>AclEntryAfterInvocationCollectionFilteringProvider</literal> classes. All of
these classes provide a declarative-based approach to evaluating ACL information at
runtime, freeing you from needing to write any code. Please refer to the sample
applications to learn how to use these classes.</para>
</section>

View File

@ -18,8 +18,8 @@
<section xml:id="el-common-built-in">
<title>Common Built-In Expressions</title>
<para>The base class for expression root objects is
<classname>SecurityExpressionRoot</classname>. This provides some common
expressions which are available in both web and method security.</para>
<classname>SecurityExpressionRoot</classname>. This provides some common expressions
which are available in both web and method security.</para>
<table frame="none">
<title>Common built-in expressions</title>
<tgroup cols="2">
@ -51,8 +51,8 @@
<row>
<entry><literal>authentication</literal></entry>
<entry>Allows direct access to the current
<interfacename>Authentication</interfacename> object obtained
from the <interfacename>SecurityContext</interfacename></entry>
<interfacename>Authentication</interfacename> object obtained from
the <interfacename>SecurityContext</interfacename></entry>
</row>
<row>
<entry><literal>permitAll</literal></entry>
@ -90,9 +90,9 @@
<section xml:id="el-access-web">
<title>Web Security Expressions</title>
<para> To use expressions to secure individual URLs, you would first need to set the
<literal>use-expressions</literal> attribute in the <literal>&lt;http></literal>
element to <literal>true</literal>. Spring Security will then expect the
<literal>access</literal> attributes of the <literal>&lt;intercept-url></literal>
<literal>use-expressions</literal> attribute in the <literal>&lt;http></literal> element
to <literal>true</literal>. Spring Security will then expect the
<literal>access</literal> attributes of the <literal>&lt;intercept-url></literal>
elements to contain Spring EL expressions. The expressions should evaluate to a boolean,
defining whether access should be allowed or not. For example:<programlisting><![CDATA[
<http use-expressions="true">
@ -106,8 +106,8 @@
already seen the built-in <literal>hasRole</literal> expression in the previous section.
The expression <literal>hasIpAddress</literal> is an additional built-in expression
which is specific to web security. It is defined by the
<classname>WebSecurityExpressionRoot</classname> class, an instance of which is used
as the expression root object when evaluation web-access expressions. This object also
<classname>WebSecurityExpressionRoot</classname> class, an instance of which is used as
the expression root object when evaluation web-access expressions. This object also
directly exposed the <interfacename>HttpServletRequest</interfacename> object under the
name <literal>request</literal> so you can invoke the request directly in an
expression.</para>
@ -126,16 +126,16 @@
<para>There are four annotations which support expression attributes to allow pre and
post-invocation authorization checks and also to support filtering of submitted
collection arguments or return values. They are <literal>@PreAuthorize</literal>,
<literal>@PreFilter</literal>, <literal>@PostAuthorize</literal> and
<literal>@PostFilter</literal>. Their use is enabled through the
<literal>global-method-security</literal> namespace
<literal>@PreFilter</literal>, <literal>@PostAuthorize</literal> and
<literal>@PostFilter</literal>. Their use is enabled through the
<literal>global-method-security</literal> namespace
element:<programlisting><![CDATA[<global-method-security pre-post-annotations="enabled"/>]]></programlisting></para>
<section>
<title>Access Control using <literal>@PreAuthorize</literal> and
<literal>@PostAuthorize</literal></title>
<literal>@PostAuthorize</literal></title>
<para>The most obviously useful annotation is <literal>@PreAuthorize</literal> which
decides whether a method can actually be invoked or not. For example (from the
<quote>Contacts</quote> sample
<quote>Contacts</quote> sample
application)<programlisting>
@PreAuthorize("hasRole('ROLE_USER')")
public void create(Contact contact);</programlisting>which
@ -150,30 +150,30 @@
whether the current user has the <quote>admin</quote>permission for the given
contact. The built-in <literal>hasPermission()</literal> expression is linked
into the Spring Security ACL module through the application context, as we'll
<link xlink:href="#el-permission-evaluator">see below</link>. You can access
any of the method arguments by name as expression variables, provided your code
has debug information compiled in. Any Spring-EL functionality is available
within the expression, so you can also access properties on the arguments. For
example, if you wanted a particular method to only allow access to a user whose
username matched that of the contact, you could write</para>
<link xlink:href="#el-permission-evaluator">see below</link>. You can access any
of the method arguments by name as expression variables, provided your code has
debug information compiled in. Any Spring-EL functionality is available within
the expression, so you can also access properties on the arguments. For example,
if you wanted a particular method to only allow access to a user whose username
matched that of the contact, you could write</para>
<programlisting>
@PreAuthorize("#contact.name == principal.name)")
public void doSomething(Contact contact);</programlisting>
<para>Here we are accessing another builtin expression, which is the
<literal>principal</literal> of the current Spring Security
<interfacename>Authentication</interfacename> object obtained from the
security context. You can also access the
<interfacename>Authentication</interfacename> object itself directly using
the expression name <literal>authentication</literal>.</para>
<literal>principal</literal> of the current Spring Security
<interfacename>Authentication</interfacename> object obtained from the security
context. You can also access the <interfacename>Authentication</interfacename>
object itself directly using the expression name
<literal>authentication</literal>.</para>
<para>Less commonly, you may wish to perform an access-control check after the
method has been invoked. This can be achieved using the
<literal>@PostAuthorize</literal> annotation. To access the return value
from a method, use the builtin name <literal>returnObject</literal> in the
<literal>@PostAuthorize</literal> annotation. To access the return value from a
method, use the builtin name <literal>returnObject</literal> in the
expression.</para>
</section>
<section>
<title>Filtering using <literal>@PreFilter</literal> and
<literal>@PostFilter</literal></title>
<literal>@PostFilter</literal></title>
<para>As you may already be aware, Spring Security supports filtering of collections
and arrays and this can now be achieved using expressions. This is most commonly
performed on the return value of a method. For
@ -187,7 +187,7 @@
using <literal>@PreFilter</literal>, though this is a less common requirement.
The syntax is just the same, but if there is more than one argument which is a
collection type then you have to select one by name using the
<literal>filterTarget</literal> property of this annotation.</para>
<literal>filterTarget</literal> property of this annotation.</para>
<para>Note that filtering is obviously not a substitute for tuning your data
retrieval queries. If you are filtering large collections and removing many of
the entries then this is likely to be inefficient.</para>
@ -197,12 +197,12 @@
<title>Built-In Expressions</title>
<para>There are some built-in expressions which are specific to method security, which
we have already seen in use above. The <literal>filterTarget</literal> and
<literal>returnValue</literal> values are simple enough, but the use of the
<literal>hasPermission()</literal> expression warrants a closer look.</para>
<literal>returnValue</literal> values are simple enough, but the use of the
<literal>hasPermission()</literal> expression warrants a closer look.</para>
<section xml:id="el-permission-evaluator">
<title>The <interfacename>PermissionEvaluator</interfacename> interface</title>
<para><literal>hasPermission()</literal> expressions are delegated to an instance of
<interfacename>PermissionEvaluator</interfacename>. It is intended to bridge
<interfacename>PermissionEvaluator</interfacename>. It is intended to bridge
between the expression system and Spring Security's ACL system, allowing you to
specify authorization constraints on domain objects, based on abstract
permissions. It has no explicit dependencies on the ACL module, so you could
@ -227,8 +227,7 @@
long as it is consistent with how the permissions are loaded.</para>
<para>To use <literal>hasPermission()</literal> expressions, you have to explicitly
configure a <interfacename>PermissionEvaluator</interfacename> in your
application context. This would look something like this:
<programlisting language="xml"> <![CDATA[
application context. This would look something like this: <programlisting language="xml"> <![CDATA[
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
@ -239,9 +238,8 @@
</bean>]]></programlisting>Where <literal>myPermissionEvaluator</literal> is the bean which
implements <interfacename>PermissionEvaluator</interfacename>. Usually this will
be the implementation from the ACL module which is called
<classname>AclPermissionEvaluator</classname>. See the
<quote>Contacts</quote> sample application configuration for more
details.</para>
<classname>AclPermissionEvaluator</classname>. See the <quote>Contacts</quote>
sample application configuration for more details.</para>
</section>
</section>
</section>

View File

@ -1,67 +1,68 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="form">
<info><title>Form Authentication Mechanism</title></info>
<info>
<title>Form Authentication Mechanism</title>
</info>
<section xml:id="form-overview">
<info><title>Overview</title></info>
<info>
<title>Overview</title>
</info>
<para>HTTP Form Authentication involves using the
<literal>UsernamePasswordAuthenticationFilter</literal> to process a login
form. This is the most common way for an application to authenticate end
users. Form-based authentication is entirely compatible with the DAO, LDAP
and JAAS authentication providers.</para>
<literal>UsernamePasswordAuthenticationFilter</literal> to process a login form. This is
the most common way for an application to authenticate end users. Form-based
authentication is entirely compatible with the DAO, LDAP and JAAS authentication
providers.</para>
<para>This is also the mechanism used by the &lt;form-login&gt; element from the namespace
and it's recommended that you use that unless you have specific customization requirements.
</para>
and it's recommended that you use that unless you have specific customization
requirements. </para>
</section>
<section xml:id="form-config">
<info><title>Configuration</title></info>
<info>
<title>Configuration</title>
</info>
<para>The login form simply contains <literal>j_username</literal> and
<literal>j_password</literal> input fields, and posts to a URL that is
monitored by the filter (by default
<literal>/j_spring_security_check</literal>). You should add an
<literal>UsernamePasswordAuthenticationFilter</literal> to your application context:
<programlisting><![CDATA[
<literal>j_password</literal> input fields, and posts to a URL that is monitored by the
filter (by default <literal>/j_spring_security_check</literal>). You should add an
<literal>UsernamePasswordAuthenticationFilter</literal> to your application context: <programlisting><![CDATA[
<bean id="authenticationProcessingFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean> ]]>
</programlisting></para>
<para>
The configured <interfacename>AuthenticationManager</interfacename>
processes each authentication request. The destination following a successful authentication
or an authentication failure is controlled by the <interfacename>AuthenticationSuccessHandler</interfacename>
and <interfacename>AuthenticationFailureHandler</interfacename> interfaces, respectively.
The filter has properties which allow you to set these
<footnote><para>In versions prior to 3.0, the application flow at this point had evolved to a stage
was controlled by a mix of properties on this class and strategy plugins. The
decision was made for 3.0 to refactor the code to make these two strategies entirely responsible.
</para></footnote>.
Some standard implementations are supplied for these such as
<para> The configured <interfacename>AuthenticationManager</interfacename> processes each
authentication request. The destination following a successful authentication or an
authentication failure is controlled by the
<interfacename>AuthenticationSuccessHandler</interfacename> and
<interfacename>AuthenticationFailureHandler</interfacename> interfaces, respectively.
The filter has properties which allow you to set these <footnote>
<para>In versions prior to 3.0, the application flow at this point had evolved to a
stage was controlled by a mix of properties on this class and strategy plugins. The
decision was made for 3.0 to refactor the code to make these two strategies entirely
responsible. </para>
</footnote>. Some standard implementations are supplied for these such as
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at the Javadoc
for these classes to see how they work.
</para>
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at the
Javadoc for these classes to see how they work. </para>
<para>If authentication is successful, the resulting
<interfacename>Authentication</interfacename> object will be placed into the
<classname>SecurityContextHolder</classname>.
The configured AuthenticationSuccessHandler will then be called to either redirect or forward
the user to the appropriate destination. By default a <classname>SavedRequestAwareAuthenticationSuccessHandler</classname>
is used, which means that the user will be redirected to the original destination they requested before they were asked to
login.
<note>
<para>
The <classname>ExceptionTranslationFilter</classname> caches the original request a user makes.
When the user authenticates, the request handler makes use of this cached request to obtain the original
URL and redirect to it. The original request is then rebuilt and used as an alternative.
</para>
</note>
If authentication fails, the configured <interfacename>AuthenticationFailureHandler</interfacename> will be invoked.
</para>
<classname>SecurityContextHolder</classname>. The configured
AuthenticationSuccessHandler will then be called to either redirect or forward the user
to the appropriate destination. By default a
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname> is used, which
means that the user will be redirected to the original destination they requested before
they were asked to login. <note>
<para> The <classname>ExceptionTranslationFilter</classname> caches the original request
a user makes. When the user authenticates, the request handler makes use of this
cached request to obtain the original URL and redirect to it. The original request
is then rebuilt and used as an alternative. </para>
</note> If authentication fails, the configured
<interfacename>AuthenticationFailureHandler</interfacename> will be invoked. </para>
</section>
</chapter>
</chapter>

View File

@ -20,13 +20,13 @@
Security overcomes these problems, and also brings you dozens of other useful,
customisable security features.</para>
<para>As you probably know two major areas of application security are
<quote>authentication</quote> and <quote>authorization</quote> (or
<quote>access-control</quote>). These are the two main areas that Spring Security
<quote>authentication</quote> and <quote>authorization</quote> (or
<quote>access-control</quote>). These are the two main areas that Spring Security
targets. <quote>Authentication</quote> is the process of establishing a principal is who
they claim to be (a <quote>principal</quote> generally means a user, device or some
other system which can perform an action in your application).
<quote>Authorization</quote> refers to the process of deciding whether a principal
is allowed to perform an action within your application. To arrive at the point where an
<quote>Authorization</quote> refers to the process of deciding whether a principal is
allowed to perform an action within your application. To arrive at the point where an
authorization decision is needed, the identity of the principal has already been
established by the authentication process. These concepts are common, and not at all
specific to Spring Security. </para>
@ -134,8 +134,8 @@
</listitem>
</itemizedlist>
<para>(* Denotes provided by a third party; check our <link
xlink:href="http://acegisecurity.org/powering.html">integration page</link> for
links to the latest details)</para>
xlink:href="http://acegisecurity.org/powering.html">integration page</link> for links to
the latest details)</para>
<para>Many independent software vendors (ISVs) adopt Spring Security because of this
significant choice of flexible authentication models. Doing so allows them to quickly
integrate their solutions with whatever their end clients need, without undertaking a
@ -165,7 +165,7 @@
<section xml:id="history">
<title>History</title>
<para>Spring Security began in late 2003 as <quote>The Acegi Security System for
Spring</quote>. A question was posed on the Spring Developers' mailing list asking
Spring</quote>. A question was posed on the Spring Developers' mailing list asking
whether there had been any consideration given to a Spring-based security
implementation. At the time the Spring community was relatively small (especially
compared with the size today!), and indeed Spring itself had only existed as a
@ -202,21 +202,21 @@
you identify the effort (or lack thereof) involved in migrating to future releases of
the project. Officially, we use the Apache Portable Runtime Project versioning
guidelines, which can be viewed at
<literal>http://apr.apache.org/versioning.html</literal>. We quote the introduction
<literal>http://apr.apache.org/versioning.html</literal>. We quote the introduction
contained on that page for your convenience:</para>
<para><quote>Versions are denoted using a standard triplet of integers: MAJOR.MINOR.PATCH.
The basic intent is that MAJOR versions are incompatible, large-scale upgrades of
the API. MINOR versions retain source and binary compatibility with older minor
versions, and changes in the PATCH level are perfectly compatible, forwards and
backwards.</quote></para>
The basic intent is that MAJOR versions are incompatible, large-scale upgrades of the
API. MINOR versions retain source and binary compatibility with older minor versions,
and changes in the PATCH level are perfectly compatible, forwards and
backwards.</quote></para>
</section>
<section xml:id="get-spring-security">
<title>Getting Spring Security</title>
<para>You can get hold of Spring Security in several ways. You can download a packaged
distribution from the main Spring <link
xlink:href="http://www.springsource.com/download/community?project=Spring%20Security"
>download page</link>, download individual jars (and sample WAR files) from the
Maven Central repository (or a SpringSource Maven repository for snapshot and milestone
xlink:href="http://www.springsource.com/download/community?project=Spring%20Security"
>download page</link>, download individual jars (and sample WAR files) from the Maven
Central repository (or a SpringSource Maven repository for snapshot and milestone
releases) or, alternatively, you can build the project from source yourself. See the
project web site for more details. </para>
<section xml:id="modules">
@ -233,28 +233,43 @@
<para>Contains core authentication and access-contol classes and interfaces,
remoting support and basic provisioning APIs. Required by any application which
uses Spring Security. Supports standalone applications, remote clients, method
(service layer) security and JDBC user provisioning. Contains the top-level
packages:<itemizedlist><listitem><para><literal>org.springframework.security.core</literal></para></listitem><listitem><para><literal>org.springframework.security.access</literal></para></listitem><listitem><para><literal>org.springframework.security.authentication</literal></para></listitem><listitem><para><literal>org.springframework.security.provisioning</literal></para></listitem><listitem><para><literal>org.springframework.security.remoting</literal></para></listitem></itemizedlist></para>
(service layer) security and JDBC user provisioning. Contains the top-level packages:<itemizedlist>
<listitem>
<para><literal>org.springframework.security.core</literal></para>
</listitem>
<listitem>
<para><literal>org.springframework.security.access</literal></para>
</listitem>
<listitem>
<para><literal>org.springframework.security.authentication</literal></para>
</listitem>
<listitem>
<para><literal>org.springframework.security.provisioning</literal></para>
</listitem>
<listitem>
<para><literal>org.springframework.security.remoting</literal></para>
</listitem>
</itemizedlist></para>
</section>
<section xml:id="spring-security-web">
<title>Web - <literal>spring-security-web.jar</literal></title>
<para>Contains filters and related web-security infrastructure code. Anything with a
servlet API dependency. You'll need it if you require Spring Security web
authentication services and URL-based access-control. The main package is
<literal>org.springframework.security.web</literal>.</para>
<literal>org.springframework.security.web</literal>.</para>
</section>
<section xml:id="spring-security-config">
<title>Config - <literal>spring-security-config.jar</literal></title>
<para>Contains the security namespace parsing code (and hence nothing that you are
likely yo use directly in your application). You need it if you are using the
Spring Security XML namespace for configuration. The main package is
<literal>org.springframework.security.config</literal>.</para>
<literal>org.springframework.security.config</literal>.</para>
</section>
<section xml:id="spring-security-ldap">
<title>LDAP - <literal>spring-security-ldap.jar</literal></title>
<para>LDAP authentication and provisioning code. Required if you need to use LDAP
authentication or manage LDAP user entries. The top-level package is
<literal>org.springframework.security.ldap</literal>.</para>
<literal>org.springframework.security.ldap</literal>.</para>
</section>
<section xml:id="spring-security-acl">
<title>ACL - <literal>spring-security-acl.jar</literal></title>
@ -266,7 +281,7 @@
<title>CAS - <literal>spring-security-cas-client.jar</literal></title>
<para>Spring Security's CAS client integration. If you want to use Spring Security
web authentication with a CAS single sign-on server. The top-level package is
<literal>org.springframework.security.cas</literal>.</para>
<literal>org.springframework.security.cas</literal>.</para>
</section>
<section xml:id="spring-security-openid">
<title>OpenID - <literal>spring-security-openid.jar</literal></title>
@ -290,7 +305,7 @@
git clone git://git.springsource.org/spring-security/spring-security.git
</programlisting>
You can checkout specific versions from
<literal>https://src.springframework.org/svn/spring-security/tags/</literal>.
<literal>https://src.springframework.org/svn/spring-security/tags/</literal>.
</para>
</section>
</section>

View File

@ -1,36 +1,38 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="jaas">
<info><title>Java Authentication and Authorization Service (JAAS) Provider</title></info>
<info>
<title>Java Authentication and Authorization Service (JAAS) Provider</title>
</info>
<section xml:id="jaas-overview">
<info><title>Overview</title></info>
<para>Spring Security provides a package able to delegate
authentication requests to the Java Authentication and Authorization
Service (JAAS). This package is discussed in detail below.</para>
<info>
<title>Overview</title>
</info>
<para>Spring Security provides a package able to delegate authentication requests to the
Java Authentication and Authorization Service (JAAS). This package is discussed in
detail below.</para>
<para>Central to JAAS operation are login configuration files. To
learn more about JAAS login configuration files, consult the JAAS
reference documentation available from Sun Microsystems. We expect you
to have a basic understanding of JAAS and its login configuration file
syntax in order to understand this section.</para>
<para>Central to JAAS operation are login configuration files. To learn more about JAAS
login configuration files, consult the JAAS reference documentation available from Sun
Microsystems. We expect you to have a basic understanding of JAAS and its login
configuration file syntax in order to understand this section.</para>
</section>
<section xml:id="jaas-config">
<info><title>Configuration</title></info>
<para>The <literal>JaasAuthenticationProvider</literal> attempts to
authenticate a users principal and credentials through JAAS.</para>
<info>
<title>Configuration</title>
</info>
<para>The <literal>JaasAuthenticationProvider</literal> attempts to authenticate a users
principal and credentials through JAAS.</para>
<para>Lets assume we have a JAAS login configuration file,
<literal>/WEB-INF/login.conf</literal>, with the following
contents:
<programlisting>
<literal>/WEB-INF/login.conf</literal>, with the following contents:
<programlisting>
JAASTest {
sample.SampleLoginModule required;
};</programlisting></para>
<para>Like all Spring Security beans, the
<classname>JaasAuthenticationProvider</classname> is configured via the
application context. The following definitions would correspond to the
above JAAS login configuration file:
<programlisting><![CDATA[
<para>Like all Spring Security beans, the <classname>JaasAuthenticationProvider</classname>
is configured via the application context. The following definitions would correspond to
the above JAAS login configuration file: <programlisting><![CDATA[
<bean id="jaasAuthenticationProvider"
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="/WEB-INF/login.conf"/>
@ -55,82 +57,76 @@ JAASTest {
<interfacename>AuthorityGranter</interfacename>s are discussed below.</para>
<section xml:id="jaas-callbackhandler">
<info><title xml:id="jaas-callback-handler">JAAS CallbackHandler</title></info>
<info>
<title xml:id="jaas-callback-handler">JAAS CallbackHandler</title>
</info>
<para>Most JAAS <literal>LoginModule</literal>s require a callback
of some sort. These callbacks are usually used to obtain the
username and password from the user.</para>
<para>Most JAAS <literal>LoginModule</literal>s require a callback of some sort. These
callbacks are usually used to obtain the username and password from the user.</para>
<para>In a Spring Security deployment, Spring Security is
responsible for this user interaction (via the authentication
mechanism). Thus, by the time the authentication request is
delegated through to JAAS, Spring Security's authentication
mechanism will already have fully-populated an
<interfacename>Authentication</interfacename> object containing all the
information required by the JAAS
<para>In a Spring Security deployment, Spring Security is responsible for this user
interaction (via the authentication mechanism). Thus, by the time the authentication
request is delegated through to JAAS, Spring Security's authentication mechanism
will already have fully-populated an <interfacename>Authentication</interfacename>
object containing all the information required by the JAAS
<literal>LoginModule</literal>.</para>
<para>Therefore, the JAAS package for Spring Security provides two
default callback handlers,
<literal>JaasNameCallbackHandler</literal> and
<literal>JaasPasswordCallbackHandler</literal>. Each of these
callback handlers implement
<literal>JaasAuthenticationCallbackHandler</literal>. In most cases
these callback handlers can simply be used without understanding the
internal mechanics.</para>
<para>Therefore, the JAAS package for Spring Security provides two default callback
handlers, <literal>JaasNameCallbackHandler</literal> and
<literal>JaasPasswordCallbackHandler</literal>. Each of these callback handlers
implement <literal>JaasAuthenticationCallbackHandler</literal>. In most cases these
callback handlers can simply be used without understanding the internal
mechanics.</para>
<para>For those needing full control over the callback behavior,
internally <literal>JaasAuthenticationProvider</literal> wraps these
<para>For those needing full control over the callback behavior, internally
<literal>JaasAuthenticationProvider</literal> wraps these
<literal>JaasAuthenticationCallbackHandler</literal>s with an
<literal>InternalCallbackHandler</literal>. The
<literal>InternalCallbackHandler</literal> is the class that
actually implements JAAS normal <literal>CallbackHandler</literal>
interface. Any time that the JAAS <literal>LoginModule</literal> is
used, it is passed a list of application context configured
<literal>InternalCallbackHandler</literal>s. If the
<literal>InternalCallbackHandler</literal> is the class that actually implements
JAAS normal <literal>CallbackHandler</literal> interface. Any time that the JAAS
<literal>LoginModule</literal> is used, it is passed a list of application context
configured <literal>InternalCallbackHandler</literal>s. If the
<literal>LoginModule</literal> requests a callback against the
<literal>InternalCallbackHandler</literal>s, the callback is in-turn
passed to the <literal>JaasAuthenticationCallbackHandler</literal>s
being wrapped.</para>
<literal>InternalCallbackHandler</literal>s, the callback is in-turn passed to the
<literal>JaasAuthenticationCallbackHandler</literal>s being wrapped.</para>
</section>
<section xml:id="jaas-authoritygranter">
<info><title xml:id="jaas-authority-granter">JAAS AuthorityGranter</title></info>
<info>
<title xml:id="jaas-authority-granter">JAAS AuthorityGranter</title>
</info>
<para>JAAS works with principals. Even "roles" are represented as
principals in JAAS. Spring Security, on the other hand, works with
<para>JAAS works with principals. Even "roles" are represented as principals in JAAS.
Spring Security, on the other hand, works with
<interfacename>Authentication</interfacename> objects. Each
<interfacename>Authentication</interfacename> object contains a single
principal, and multiple <interfacename>GrantedAuthority</interfacename>[]s. To
facilitate mapping between these different concepts, Spring
Security's JAAS package includes an
<interfacename>Authentication</interfacename> object contains a single principal,
and multiple <interfacename>GrantedAuthority</interfacename>[]s. To facilitate
mapping between these different concepts, Spring Security's JAAS package includes an
<literal>AuthorityGranter</literal> interface.</para>
<para>An <literal>AuthorityGranter</literal> is responsible for
inspecting a JAAS principal and returning a set of
<literal>String</literal>s, representing the authorities assigned to the principal.
For each returned authority string, the
<para>An <literal>AuthorityGranter</literal> is responsible for inspecting a JAAS
principal and returning a set of <literal>String</literal>s, representing the
authorities assigned to the principal. For each returned authority string, the
<classname>JaasAuthenticationProvider</classname> creates a
<classname>JaasGrantedAuthority</classname> (which implements Spring
Securitys <interfacename>GrantedAuthority</interfacename> interface) containing
the authority string and the JAAS principal that the
<classname>JaasGrantedAuthority</classname> (which implements Spring Securitys
<interfacename>GrantedAuthority</interfacename> interface) containing the authority
string and the JAAS principal that the
<interfacename>AuthorityGranter</interfacename> was passed. The
<classname>JaasAuthenticationProvider</classname> obtains the JAAS
principals by firstly successfully authenticating the users
credentials using the JAAS <literal>LoginModule</literal>, and then
accessing the <literal>LoginContext</literal> it returns. A call to
<literal>LoginContext.getSubject().getPrincipals()</literal> is
made, with each resulting principal passed to each
<interfacename>AuthorityGranter</interfacename> defined against the
<classname>JaasAuthenticationProvider</classname> obtains the JAAS principals by
firstly successfully authenticating the users credentials using the JAAS
<literal>LoginModule</literal>, and then accessing the
<literal>LoginContext</literal> it returns. A call to
<literal>LoginContext.getSubject().getPrincipals()</literal> is made, with each
resulting principal passed to each <interfacename>AuthorityGranter</interfacename>
defined against the
<literal>JaasAuthenticationProvider.setAuthorityGranters(List)</literal>
property.</para>
<para>Spring Security does not include any production
<interfacename>AuthorityGranter</interfacename>s given that every JAAS principal
has an implementation-specific meaning. However, there is a
<literal>TestAuthorityGranter</literal> in the unit tests that
demonstrates a simple <literal>AuthorityGranter</literal>
implementation.</para>
<interfacename>AuthorityGranter</interfacename>s given that every JAAS principal has
an implementation-specific meaning. However, there is a
<literal>TestAuthorityGranter</literal> in the unit tests that demonstrates a simple
<literal>AuthorityGranter</literal> implementation.</para>
</section>
</section>
</chapter>
</chapter>

View File

@ -16,13 +16,12 @@
<para>You should be familiar with LDAP before trying to use it with Spring Security. The
following link provides a good introduction to the concepts involved and a guide to
setting up a directory using the free LDAP server OpenLDAP: <uri
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://www.zytrax.com/books/ldap/"
>http://www.zytrax.com/books/ldap/</uri>. Some familiarity with the JNDI APIs used
to access LDAP from Java may also be useful. We don't use any third-party LDAP libraries
(Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so
some familiarity with that project may be useful if you plan on adding your own
customizations.</para>
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://www.zytrax.com/books/ldap/">http://www.zytrax.com/books/ldap/</uri>.
Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. We
don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but
extensive use is made of Spring LDAP, so some familiarity with that project may be
useful if you plan on adding your own customizations.</para>
</section>
<section>
<info>
@ -30,19 +29,19 @@
</info>
<para> LDAP authentication in Spring Security can be roughly divided into the following
stages. <orderedlist inheritnum="ignore" continuation="restarts">
<listitem>
<para>Obtaining the unique LDAP <quote>Distinguished Name</quote>, or DN, from
the login name. This will often mean performing a search in the directory,
unless the exact mapping of usernames to DNs is known in advance.</para>
</listitem>
<listitem>
<para>Authenticating the user, either by binding as that user or by performing a
remote <quote>compare</quote> operation of the user's password against the
password attribute in the directory entry for the DN.</para>
</listitem>
<listitem>
<para>Loading the list of authorities for the user.</para>
</listitem>
<listitem>
<para>Obtaining the unique LDAP <quote>Distinguished Name</quote>, or DN, from the
login name. This will often mean performing a search in the directory, unless
the exact mapping of usernames to DNs is known in advance.</para>
</listitem>
<listitem>
<para>Authenticating the user, either by binding as that user or by performing a
remote <quote>compare</quote> operation of the user's password against the
password attribute in the directory entry for the DN.</para>
</listitem>
<listitem>
<para>Loading the list of authorities for the user.</para>
</listitem>
</orderedlist> The exception is when the LDAP directory is just being used to retrieve
user information and authenticate against it locally. This may not be possible as
directories are often set up with limited read access for attributes such as user
@ -72,8 +71,8 @@
<ldap-server root="dc=springframework,dc=org"/>
]]>
</programlisting> Here we've specified that the root DIT of the directory should be
<quote>dc=springframework,dc=org</quote>, which is the default. Used this way,
the namespace parser will create an embedded Apache Directory server and scan the
<quote>dc=springframework,dc=org</quote>, which is the default. Used this way, the
namespace parser will create an embedded Apache Directory server and scan the
classpath for any LDIF files, which it will attempt to load into the server. You can
customize this behaviour using the <literal>ldif</literal> attribute, which defines
an LDIF resource to be loaded: <programlisting><![CDATA[
@ -102,7 +101,7 @@
perform a search under the DN <literal>ou=people,dc=springframework,dc=org</literal>
using the value of the <literal>user-search-filter</literal> attribute as a filter.
Again the user login name is substituted for the parameter in the filter name. If
<literal>user-search-base</literal> isn't supplied, the search will be performed
<literal>user-search-base</literal> isn't supplied, the search will be performed
from the root. </para>
</section>
<section>
@ -111,41 +110,37 @@
</info>
<para> How authorities are loaded from groups in the LDAP directory is controlled by the
following attributes. <itemizedlist>
<listitem>
<para>
<literal>group-search-base</literal>. Defines the part of the directory
tree under which group searches should be performed.</para>
</listitem>
<listitem>
<para>
<literal>group-role-attribute</literal>. The attribute which contains
the name of the authority defined by the group entry. Defaults to
<literal>cn</literal>
</para>
</listitem>
<listitem>
<para>
<literal>group-search-filter</literal>. The filter which is used to
search for group membership. The default is
<literal>uniqueMember={0}</literal>, corresponding to the
<literal>groupOfUniqueMembers</literal> LDAP class. In this case,
the substituted parameter is the full distinguished name of the user.
The parameter <literal>{1}</literal> can be used if you want to filter
on the login name.</para>
</listitem>
<listitem>
<para> <literal>group-search-base</literal>. Defines the part of the directory
tree under which group searches should be performed.</para>
</listitem>
<listitem>
<para> <literal>group-role-attribute</literal>. The attribute which contains the
name of the authority defined by the group entry. Defaults to
<literal>cn</literal> </para>
</listitem>
<listitem>
<para> <literal>group-search-filter</literal>. The filter which is used to
search for group membership. The default is
<literal>uniqueMember={0}</literal>, corresponding to the
<literal>groupOfUniqueMembers</literal> LDAP class. In this case, the
substituted parameter is the full distinguished name of the user. The
parameter <literal>{1}</literal> can be used if you want to filter on the
login name.</para>
</listitem>
</itemizedlist> So if we used the following configuration <programlisting><![CDATA[
<ldap-authentication-provider user-dn-pattern="uid={0},ou=people"
group-search-base="ou=groups" />
]]></programlisting> and authenticated successfully as user <quote>ben</quote>, the subsequent
loading of authorities would perform a search under the directory entry
<literal>ou=groups,dc=springframework,dc=org</literal>, looking for entries
which contain the attribute <literal>uniqueMember</literal> with value
<literal>uid=ben,ou=people,dc=springframework,dc=org</literal>. By default the
<literal>ou=groups,dc=springframework,dc=org</literal>, looking for entries which
contain the attribute <literal>uniqueMember</literal> with value
<literal>uid=ben,ou=people,dc=springframework,dc=org</literal>. By default the
authority names will have the prefix <literal>ROLE_</literal> prepended. You can
change this using the <literal>role-prefix</literal> attribute. If you don't want
any prefix, use <literal>role-prefix="none"</literal>. For more information on
loading authorities, see the Javadoc for the
<classname>DefaultLdapAuthoritiesPopulator</classname> class. </para>
<classname>DefaultLdapAuthoritiesPopulator</classname> class. </para>
</section>
</section>
<section>
@ -159,10 +154,10 @@
using namespace configuration then you can skip this section and the next one. </para>
<para> The main LDAP provider class, <classname>LdapAuthenticationProvider</classname>,
doesn't actually do much itself but delegates the work to two other beans, an
<interfacename>LdapAuthenticator</interfacename> and an
<interfacename>LdapAuthoritiesPopulator</interfacename> which are responsible for
<interfacename>LdapAuthenticator</interfacename> and an
<interfacename>LdapAuthoritiesPopulator</interfacename> which are responsible for
authenticating the user and retrieving the user's set of
<interfacename>GrantedAuthority</interfacename>s respectively.</para>
<interfacename>GrantedAuthority</interfacename>s respectively.</para>
<section xml:id="ldap-ldap-authenticators">
<info>
<title>LdapAuthenticator Implementations</title>
@ -172,18 +167,16 @@
authentication being used. For example, if binding as the user, it may be necessary
to read them with the user's own permissions.</para>
<para>There are currently two authentication strategies supplied with Spring Security: <itemizedlist>
<listitem>
<para>Authentication directly to the LDAP server ("bind"
authentication).</para>
</listitem>
<listitem>
<para>Password comparison, where the password supplied by the user is
compared with the one stored in the repository. This can either be done
by retrieving the value of the password attribute and checking it
locally or by performing an LDAP "compare" operation, where the supplied
password is passed to the server for comparison and the real password
value is never retrieved.</para>
</listitem>
<listitem>
<para>Authentication directly to the LDAP server ("bind" authentication).</para>
</listitem>
<listitem>
<para>Password comparison, where the password supplied by the user is compared
with the one stored in the repository. This can either be done by retrieving
the value of the password attribute and checking it locally or by performing
an LDAP "compare" operation, where the supplied password is passed to the
server for comparison and the real password value is never retrieved.</para>
</listitem>
</itemizedlist></para>
<section xml:id="ldap-ldap-authenticators-common">
<info>
@ -192,33 +185,32 @@
<para>Before it is possible to authenticate a user (by either strategy), the
distinguished name (DN) has to be obtained from the login name supplied to the
application. This can be done either by simple pattern-matching (by setting the
<property>setUserDnPatterns</property> array property) or by setting the
<property>userSearch</property> property. For the DN pattern-matching
approach, a standard Java pattern format is used, and the login name will be
substituted for the parameter <parameter>{0}</parameter>. The pattern should be
relative to the DN that the configured
<interfacename>SpringSecurityContextSource</interfacename> will bind to (see
the section on <link linkend="ldap-context-source">connecting to the LDAP
server</link> for more information on this). For example, if you are using
an LDAP server with the URL
<literal>ldap://monkeymachine.co.uk/dc=springframework,dc=org</literal>, and
<property>setUserDnPatterns</property> array property) or by setting the
<property>userSearch</property> property. For the DN pattern-matching approach,
a standard Java pattern format is used, and the login name will be substituted
for the parameter <parameter>{0}</parameter>. The pattern should be relative to
the DN that the configured
<interfacename>SpringSecurityContextSource</interfacename> will bind to (see the
section on <link linkend="ldap-context-source">connecting to the LDAP
server</link> for more information on this). For example, if you are using an
LDAP server with the URL
<literal>ldap://monkeymachine.co.uk/dc=springframework,dc=org</literal>, and
have a pattern <literal>uid={0},ou=greatapes</literal>, then a login name of
"gorilla" will map to a DN
<literal>uid=gorilla,ou=greatapes,dc=springframework,dc=org</literal>. Each
<literal>uid=gorilla,ou=greatapes,dc=springframework,dc=org</literal>. Each
configured DN pattern will be tried in turn until a match is found. For
information on using a search, see the section on <link
linkend="ldap-searchobjects">search objects</link> below. A combination of
the two approaches can also be used - the patterns will be checked first and if
no matching DN is found, the search will be used.</para>
linkend="ldap-searchobjects">search objects</link> below. A combination of the
two approaches can also be used - the patterns will be checked first and if no
matching DN is found, the search will be used.</para>
</section>
<section xml:id="ldap-ldap-authenticators-bind">
<info>
<title>BindAuthenticator</title>
</info>
<para>The class <classname>BindAuthenticator</classname> in the package
<filename>org.springframework.security.ldap.authentication</filename>
implements the bind authentication strategy. It simply attempts to bind as the
user.</para>
<filename>org.springframework.security.ldap.authentication</filename> implements
the bind authentication strategy. It simply attempts to bind as the user.</para>
</section>
<section xml:id="ldap-ldap-authenticators-password">
<info>
@ -243,7 +235,7 @@
to be supplied with a <interfacename>SpringSecurityContextSource</interfacename>
which is an extension of Spring LDAP's <interfacename>ContextSource</interfacename>.
Unless you have special requirements, you will usually configure a
<classname>DefaultSpringSecurityContextSource</classname> bean, which can be
<classname>DefaultSpringSecurityContextSource</classname> bean, which can be
configured with the URL of your LDAP server and optionally with the username and
password of a "manager" user which will be used by default when binding to the
server (instead of binding anonymously). For more information read the Javadoc for
@ -254,38 +246,37 @@
<info>
<title>LDAP Search Objects</title>
</info>
<para>Often a more complicated strategy than simple DN-matching is required to
locate a user entry in the directory. This can be encapsulated in an
<interfacename>LdapUserSearch</interfacename> instance which can be supplied to
the authenticator implementations, for example, to allow them to locate a user. The
<para>Often a more complicated strategy than simple DN-matching is required to locate a
user entry in the directory. This can be encapsulated in an
<interfacename>LdapUserSearch</interfacename> instance which can be supplied to the
authenticator implementations, for example, to allow them to locate a user. The
supplied implementation is <classname>FilterBasedLdapUserSearch</classname>.</para>
<section xml:id="ldap-searchobjects-filter">
<info>
<title xml:id="ldap-searchobjects-filter-based">
<classname>FilterBasedLdapUserSearch</classname>
</title>
<classname>FilterBasedLdapUserSearch</classname> </title>
</info>
<para>This bean uses an LDAP filter to match the user object in the directory. The
process is explained in the Javadoc for the corresponding search method on the
<link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)"
>JDK DirContext class</link>. As explained there, the search filter can be
<link xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)"
>JDK DirContext class</link>. As explained there, the search filter can be
supplied with parameters. For this class, the only valid parameter is
<parameter>{0}</parameter> which will be replaced with the user's login
<parameter>{0}</parameter> which will be replaced with the user's login
name.</para>
</section>
</section>
<section xml:id="ldap-authorities">
<title>LdapAuthoritiesPopulator</title>
<para> After authenticating the user successfully, the
<classname>LdapAuthenticationProvider</classname> will attempt to load a set of
<classname>LdapAuthenticationProvider</classname> will attempt to load a set of
authorities for the user by calling the configured
<interfacename>LdapAuthoritiesPopulator</interfacename> bean. The
<classname>DefaultLdapAuthoritiesPopulator</classname> is an implementation
which will load the authorities by searching the directory for groups of which the
user is a member (typically these will be <literal>groupOfNames</literal> or
<literal>groupOfUniqueNames</literal> entries in the directory). Consult the
Javadoc for this class for more details on how it works. </para>
<interfacename>LdapAuthoritiesPopulator</interfacename> bean. The
<classname>DefaultLdapAuthoritiesPopulator</classname> is an implementation which
will load the authorities by searching the directory for groups of which the user is
a member (typically these will be <literal>groupOfNames</literal> or
<literal>groupOfUniqueNames</literal> entries in the directory). Consult the Javadoc
for this class for more details on how it works. </para>
<para>If you want to use LDAP only for authentication, but load the authorities from a
difference source (such as a database) then you can provide your own implementation
of this interface and inject that instead.</para>
@ -325,14 +316,14 @@
</programlisting> This would set up the provider to access an LDAP server
with URL <literal>ldap://monkeymachine:389/dc=springframework,dc=org</literal>.
Authentication will be performed by attempting to bind with the DN
<literal>uid=&lt;user-login-name&gt;,ou=people,dc=springframework,dc=org</literal>.
<literal>uid=&lt;user-login-name&gt;,ou=people,dc=springframework,dc=org</literal>.
After successful authentication, roles will be assigned to the user by searching
under the DN <literal>ou=groups,dc=springframework,dc=org</literal> with the default
filter <literal>(member=&lt;user's-DN&gt;)</literal>. The role name will be taken
from the <quote>ou</quote> attribute of each match.</para>
<para>To configure a user search object, which uses the filter
<literal>(uid=&lt;user-login-name&gt;)</literal> for use instead of the
DN-pattern (or in addition to it), you would configure the following bean <programlisting><![CDATA[
<literal>(uid=&lt;user-login-name&gt;)</literal> for use instead of the DN-pattern
(or in addition to it), you would configure the following bean <programlisting><![CDATA[
<bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value=""/>
@ -340,40 +331,40 @@
<constructor-arg index="2" ref="contextSource" />
</bean> ]]>
</programlisting> and use it by setting the
<classname>BindAuthenticator</classname> bean's <property>userSearch</property>
<classname>BindAuthenticator</classname> bean's <property>userSearch</property>
property. The authenticator would then call the search object to obtain the correct
user's DN before attempting to bind as this user.</para>
</section>
<section xml:id="ldap-custom-user-details">
<title>LDAP Attributes and Customized UserDetails</title>
<para> The net result of an authentication using
<classname>LdapAuthenticationProvider</classname> is the same as a normal Spring
<classname>LdapAuthenticationProvider</classname> is the same as a normal Spring
Security authentication using the standard
<interfacename>UserDetailsService</interfacename> interface. A
<interfacename>UserDetails</interfacename> object is created and stored in the
<interfacename>UserDetailsService</interfacename> interface. A
<interfacename>UserDetails</interfacename> object is created and stored in the
returned <interfacename>Authentication</interfacename> object. As with using a
<interfacename>UserDetailsService</interfacename>, a common requirement is to be
<interfacename>UserDetailsService</interfacename>, a common requirement is to be
able to customize this implementation and add extra properties. When using LDAP,
these will normally be attributes from the user entry. The creation of the
<interfacename>UserDetails</interfacename> object is controlled by the
provider's <interfacename>UserDetailsContextMapper</interfacename> strategy, which
is responsible for mapping user objects to and from LDAP context data: <programlisting><![CDATA[
<interfacename>UserDetails</interfacename> object is controlled by the provider's
<interfacename>UserDetailsContextMapper</interfacename> strategy, which is
responsible for mapping user objects to and from LDAP context data: <programlisting><![CDATA[
public interface UserDetailsContextMapper {
UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<GrantedAuthority> authorities);
void mapUserToContext(UserDetails user, DirContextAdapter ctx);
}]]>
</programlisting> Only the first method is relevant for
authentication. If you provide an implementation of this interface, you can control
exactly how the UserDetails object is created. The first parameter is an instance of
Spring LDAP's <interfacename>DirContextOperations</interfacename> which gives you
access to the LDAP attributes which were loaded. The <literal>username</literal>
parameter is the name used to authenticate and the final parameter is the collection
of authorities loaded for the user. </para>
</programlisting> Only the first method is relevant for authentication. If you
provide an implementation of this interface, you can control exactly how the
UserDetails object is created. The first parameter is an instance of Spring LDAP's
<interfacename>DirContextOperations</interfacename> which gives you access to the
LDAP attributes which were loaded. The <literal>username</literal> parameter is the
name used to authenticate and the final parameter is the collection of authorities
loaded for the user. </para>
<para> The way the context data is loaded varies slightly depending on the type of
authentication you are using. With the <classname>BindAuthenticator</classname>,
the context returned from the bind operation will be used to read the attributes,
authentication you are using. With the <classname>BindAuthenticator</classname>, the
context returned from the bind operation will be used to read the attributes,
otherwise the data will be read using the standard context obtained from the
configured <interfacename>ContextSource</interfacename> (when a search is configured
to locate the user, this will be the data returned by the search object). </para>

File diff suppressed because it is too large Load Diff

View File

@ -1,142 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="preauth"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Pre-Authentication Scenarios</title>
</info>
<para> There are situations where you want to use Spring Security for authorization, but the user
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>
<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 configuration 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>
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Pre-Authentication Scenarios</title>
</info>
<para> There are situations where you want to use Spring Security for authorization, but the
user 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>
<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">
<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 configuration 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">
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>
</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>
<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>
</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">
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>
<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>
</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">
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>
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>
</section>
</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>
</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>
<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 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 username they wished. </para>
</tip>
<section>
<title>Siteminder Example Configuration</title>
<para> A typical configuration using this filter would look like this: <programlisting><![CDATA[
<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>
<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
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
username they wished. </para>
</tip>
<section>
<title>Siteminder Example Configuration</title>
<para> A typical configuration using this filter would look like this: <programlisting><![CDATA[
<security:http>
<!-- Additional http configuration omitted -->
<security:custom-filter ref="siteminderFilter" />
@ -162,27 +174,28 @@ class="org.springframework.security.web.authentication.preauth.PreAuthenticatedA
<security:authentication-provider ref="preauthAuthProvider" />
</security-authentication-manager>
]]>
</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>
</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>
</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>
</section>
</section>
</chapter>

View File

@ -15,11 +15,10 @@
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.
<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">
@ -46,7 +45,7 @@
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
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>
...
@ -56,26 +55,27 @@
</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>
<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[
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
<literal>persistent_logins</literal> table, created using the following SQL (or
equivalent):
<programlisting>
create table persistent_logins (username varchar(64) not null,
@ -91,10 +91,10 @@
</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:
<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);
@ -105,9 +105,9 @@
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
<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
@ -116,18 +116,18 @@
<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
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
<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>
@ -151,26 +151,30 @@
</bean>
]]>
</programlisting>Don't forget to add your
<interfacename>RememberMeServices</interfacename> implementation to your
<literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal>
<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>
<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>
<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>

View File

@ -1,92 +1,84 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="runas"><info><title>Run-As Authentication Replacement</title></info>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="runas">
<info>
<title>Run-As Authentication Replacement</title>
</info>
<section xml:id="runas-overview">
<info><title>Overview</title></info>
<info>
<title>Overview</title>
</info>
<para>The <classname>AbstractSecurityInterceptor</classname> is able to
temporarily replace the <interfacename>Authentication</interfacename> object in
the <interfacename>SecurityContext</interfacename> and
<classname>SecurityContextHolder</classname> during the secure object
callback phase. This only occurs if the original
<interfacename>Authentication</interfacename> object was successfully processed by
the <interfacename>AuthenticationManager</interfacename> and
<interfacename>AccessDecisionManager</interfacename>. The
<para>The <classname>AbstractSecurityInterceptor</classname> is able to temporarily replace
the <interfacename>Authentication</interfacename> object in the
<interfacename>SecurityContext</interfacename> and
<classname>SecurityContextHolder</classname> during the secure object callback phase.
This only occurs if the original <interfacename>Authentication</interfacename> object
was successfully processed by the <interfacename>AuthenticationManager</interfacename>
and <interfacename>AccessDecisionManager</interfacename>. The
<literal>RunAsManager</literal> will indicate the replacement
<interfacename>Authentication</interfacename> object, if any, that should be used
during the <literal>SecurityInterceptorCallback</literal>.</para>
<interfacename>Authentication</interfacename> object, if any, that should be used during
the <literal>SecurityInterceptorCallback</literal>.</para>
<para>By temporarily replacing the <interfacename>Authentication</interfacename>
object during the secure object callback phase, the secured invocation
will be able to call other objects which require different
authentication and authorization credentials. It will also be able to
perform any internal security checks for specific
<para>By temporarily replacing the <interfacename>Authentication</interfacename> object
during the secure object callback phase, the secured invocation will be able to call
other objects which require different authentication and authorization credentials. It
will also be able to perform any internal security checks for specific
<interfacename>GrantedAuthority</interfacename> objects. Because Spring Security
provides a number of helper classes that automatically configure
remoting protocols based on the contents of the
<classname>SecurityContextHolder</classname>, these run-as replacements
are particularly useful when calling remote web services</para>
provides a number of helper classes that automatically configure remoting protocols
based on the contents of the <classname>SecurityContextHolder</classname>, these run-as
replacements are particularly useful when calling remote web services</para>
</section>
<section xml:id="runas-config">
<info><title>Configuration</title></info>
<info>
<title>Configuration</title>
</info>
<para>A <literal>RunAsManager</literal> interface is provided by Spring Security:
<programlisting>
Authentication buildRunAs(Authentication authentication, Object object,
List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
</programlisting>
</para>
</programlisting> </para>
<para>The first method returns the <interfacename>Authentication</interfacename>
object that should replace the existing
<interfacename>Authentication</interfacename> object for the duration of the
method invocation. If the method returns <literal>null</literal>, it
indicates no replacement should be made. The second method is used by
the <classname>AbstractSecurityInterceptor</classname> as part of its
startup validation of configuration attributes. The
<literal>supports(Class)</literal> method is called by a security
interceptor implementation to ensure the configured
<literal>RunAsManager</literal> supports the type of secure object
that the security interceptor will present.</para>
<para>The first method returns the <interfacename>Authentication</interfacename> object that
should replace the existing <interfacename>Authentication</interfacename> object for the
duration of the method invocation. If the method returns <literal>null</literal>, it
indicates no replacement should be made. The second method is used by the
<classname>AbstractSecurityInterceptor</classname> as part of its startup validation of
configuration attributes. The <literal>supports(Class)</literal> method is called by a
security interceptor implementation to ensure the configured
<literal>RunAsManager</literal> supports the type of secure object that the security
interceptor will present.</para>
<para>One concrete implementation of a <literal>RunAsManager</literal>
is provided with Spring Security. The
<literal>RunAsManagerImpl</literal> class returns a replacement
<literal>RunAsUserToken</literal> if any
<literal>ConfigAttribute</literal> starts with
<literal>RUN_AS_</literal>. If any such
<literal>ConfigAttribute</literal> is found, the replacement
<literal>RunAsUserToken</literal> will contain the same principal,
<para>One concrete implementation of a <literal>RunAsManager</literal> is provided with
Spring Security. The <literal>RunAsManagerImpl</literal> class returns a replacement
<literal>RunAsUserToken</literal> if any <literal>ConfigAttribute</literal> starts with
<literal>RUN_AS_</literal>. If any such <literal>ConfigAttribute</literal> is found, the
replacement <literal>RunAsUserToken</literal> will contain the same principal,
credentials and granted authorities as the original
<interfacename>Authentication</interfacename> object, along with a new
<literal>GrantedAuthorityImpl</literal> for each
<literal>RUN_AS_</literal> <literal>ConfigAttribute</literal>. Each
new <literal>GrantedAuthorityImpl</literal> will be prefixed with
<literal>ROLE_</literal>, followed by the <literal>RUN_AS</literal>
<literal>ConfigAttribute</literal>. For example, a
<literal>GrantedAuthorityImpl</literal> for each <literal>RUN_AS_</literal>
<literal>ConfigAttribute</literal>. Each new <literal>GrantedAuthorityImpl</literal>
will be prefixed with <literal>ROLE_</literal>, followed by the
<literal>RUN_AS</literal> <literal>ConfigAttribute</literal>. For example, a
<literal>RUN_AS_SERVER</literal> will result in the replacement
<literal>RunAsUserToken</literal> containing a
<literal>ROLE_RUN_AS_SERVER</literal> granted authority.</para>
<literal>RunAsUserToken</literal> containing a <literal>ROLE_RUN_AS_SERVER</literal>
granted authority.</para>
<para>The replacement <literal>RunAsUserToken</literal> is just like
any other <interfacename>Authentication</interfacename> object. It needs to be
authenticated by the <interfacename>AuthenticationManager</interfacename>,
probably via delegation to a suitable
<classname>AuthenticationProvider</classname>. The
<literal>RunAsImplAuthenticationProvider</literal> performs such
authentication. It simply accepts as valid any
<literal>RunAsUserToken</literal> presented.</para>
<para>The replacement <literal>RunAsUserToken</literal> is just like any other
<interfacename>Authentication</interfacename> object. It needs to be authenticated by
the <interfacename>AuthenticationManager</interfacename>, probably via delegation to a
suitable <classname>AuthenticationProvider</classname>. The
<literal>RunAsImplAuthenticationProvider</literal> performs such authentication. It
simply accepts as valid any <literal>RunAsUserToken</literal> presented.</para>
<para>To ensure malicious code does not create a
<literal>RunAsUserToken</literal> and present it for guaranteed
acceptance by the <literal>RunAsImplAuthenticationProvider</literal>,
the hash of a key is stored in all generated tokens. The
<literal>RunAsManagerImpl</literal> and
<literal>RunAsImplAuthenticationProvider</literal> is created in the
bean context with the same key:
<programlisting>
<para>To ensure malicious code does not create a <literal>RunAsUserToken</literal> and
present it for guaranteed acceptance by the
<literal>RunAsImplAuthenticationProvider</literal>, the hash of a key is stored in all
generated tokens. The <literal>RunAsManagerImpl</literal> and
<literal>RunAsImplAuthenticationProvider</literal> is created in the bean context with
the same key: <programlisting>
<![CDATA[
<bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl">
@ -97,10 +89,9 @@
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
<property name="key" value="my_run_as_password"/>
</bean>]]></programlisting></para>
<para>By using the same key, each <literal>RunAsUserToken</literal>
can be validated it was created by an approved
<literal>RunAsManagerImpl</literal>. The
<literal>RunAsUserToken</literal> is immutable after creation for
security reasons</para>
<para>By using the same key, each <literal>RunAsUserToken</literal> can be validated it was
created by an approved <literal>RunAsManagerImpl</literal>. The
<literal>RunAsUserToken</literal> is immutable after creation for security
reasons</para>
</section>
</chapter>

View File

@ -9,23 +9,23 @@
files individually from the central Maven repository. We'd recommend the former. You can get
the source as described in <link xlink:href="#get-source">the introduction</link> and it's
easy to build the project using Maven. There is more information on the project web site at
<link xlink:href="http://www.springsource.org/security/">
http://www.springsource.org/security/ </link> if you need it. All paths referred to in
this chapter are relative to the project source directory. </para>
<link xlink:href="http://www.springsource.org/security/">
http://www.springsource.org/security/ </link> if you need it. All paths referred to in this
chapter are relative to the project source directory. </para>
<section xml:id="tutorial-sample">
<title>Tutorial Sample</title>
<para> The tutorial sample is a nice basic example to get you started. It uses simple
namespace configuration throughout. The compiled application is included in the
distribution zip file, ready to be deployed into your web container
(<filename>spring-security-samples-tutorial-3.0.x.war</filename>). The <link
xlink:href="#ns-form-and-basic">form-based</link> authentication mechanism is used
in combination with the commonly-used <link xlink:href="#remember-me">remember-me</link>
(<filename>spring-security-samples-tutorial-3.0.x.war</filename>). The <link
xlink:href="#ns-form-and-basic">form-based</link> authentication mechanism is used in
combination with the commonly-used <link xlink:href="#remember-me">remember-me</link>
authentication provider to automatically remember the login using cookies.</para>
<para>We recommend you start with the tutorial sample, as the XML is minimal and easy to
follow. Most importantly, you can easily add this one XML file (and its corresponding
<literal>web.xml</literal> entries) to your existing application. Only when this
basic integration is achieved do we suggest you attempt adding in method authorization
or domain object security.</para>
<literal>web.xml</literal> entries) to your existing application. Only when this basic
integration is achieved do we suggest you attempt adding in method authorization or
domain object security.</para>
</section>
<section xml:id="contacts-sample">
<title>Contacts</title>
@ -35,11 +35,11 @@
administer a simple database of contacts (the domain objects).</para>
<para>To deploy, simply copy the WAR file from Spring Security distribution into your
containers <literal>webapps</literal> directory. The war should be called
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended
version number will vary depending on what release you are using). </para>
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended version
number will vary depending on what release you are using). </para>
<para>After starting your container, check the application can load. Visit
<literal>http://localhost:8080/contacts</literal> (or whichever URL is appropriate
for your web container and the WAR you deployed). </para>
<literal>http://localhost:8080/contacts</literal> (or whichever URL is appropriate for
your web container and the WAR you deployed). </para>
<para>Next, click "Debug". You will be prompted to authenticate, and a series of usernames
and passwords are suggested on that page. Simply authenticate with any of these and view
the resulting page. It should contain a success message similar to the following:
@ -71,8 +71,8 @@ Success! Your web filters appear to be properly configured!
<para>Once you successfully receive the above message, return to the sample application's
home page and click "Manage". You can then try out the application. Notice that only the
contacts available to the currently logged on user are displayed, and only users with
<literal>ROLE_SUPERVISOR</literal> are granted access to delete their contacts.
Behind the scenes, the <classname>MethodSecurityInterceptor</classname> is securing the
<literal>ROLE_SUPERVISOR</literal> are granted access to delete their contacts. Behind
the scenes, the <classname>MethodSecurityInterceptor</classname> is securing the
business objects. </para>
<para>The application allows you to modify the access control lists associated with
different contacts. Be sure to give this a try and understand how it works by reviewing
@ -103,17 +103,17 @@ Success! Your web filters appear to be properly configured!
<title>CAS Sample</title>
<para> The CAS sample requires that you run both a CAS server and CAS client. It isn't
included in the distribution so you should check out the project code as described in
<link xlink:href="get-source">the introduction</link>. You'll find the relevant
files under the <filename>sample/cas</filename> directory. There's also a
<filename>Readme.txt</filename> file in there which explains how to run both the
server and the client directly from the source tree, complete with SSL support. You have
to download the CAS Server web application (a war file) from the CAS site and drop it
into the <filename>samples/cas/server</filename> directory. </para>
<link xlink:href="get-source">the introduction</link>. You'll find the relevant files
under the <filename>sample/cas</filename> directory. There's also a
<filename>Readme.txt</filename> file in there which explains how to run both the server
and the client directly from the source tree, complete with SSL support. You have to
download the CAS Server web application (a war file) from the CAS site and drop it into
the <filename>samples/cas/server</filename> directory. </para>
</section>
<section xml:id="preauth-sample">
<title>Pre-Authentication Sample</title>
<para> This sample application demonstrates how to wire up beans from the <link
xlink:href="#preauth">pre-authentication</link> framework to make use of login
xlink:href="#preauth">pre-authentication</link> framework to make use of login
information from a J2EE container. The user name and roles are those setup by the
container. </para>
<para> The code is in <filename>samples/preauth</filename>. </para>

View File

@ -1,32 +1,34 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Secure Object Implementations</title>
</info>
<section xml:id="aop-alliance">
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
<title>Secure Object Implementations</title>
</info>
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed
quite a lot of boiler plate configuration. Now the recommended approach for method security is
to use <link xlink:href="#ns-method-security">namespace configuration</link>. This way the
method security infrastructure beans are configured automatically for you so you don't really
need to know about the implementation classes. We'll just provide a quick overview of the
classes that are involved here. </para>
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
which secures <classname>MethodInvocation</classname>s. Depending on the configuration
approach, an interceptor may be specific to a single bean or shared between multiple beans.
The interceptor uses a <interfacename>MethodSecurityMetadataSource</interfacename> instance to
obtain the configuration attributes that apply to a particular method invocation.
<classname>MapBasedMethodSecurityMetadataSource</classname> is used to store configuration
attributes keyed by method names (which can be wildcarded) and will be used internally when
the attributes are defined in the application context using the
<literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal>
elements. Other implementations will be used to handle annotation-based configuration. </para>
<section>
<title>Explicit MethodSecurityInterceptor Configuration</title>
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname> directly
in your application context for use with one of Spring AOP's proxying mechanisms: <programlisting><![CDATA[
<section xml:id="aop-alliance">
<info>
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
</info>
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s
needed quite a lot of boiler plate configuration. Now the recommended approach for
method security is to use <link xlink:href="#ns-method-security">namespace
configuration</link>. This way the method security infrastructure beans are configured
automatically for you so you don't really need to know about the implementation classes.
We'll just provide a quick overview of the classes that are involved here. </para>
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
which secures <classname>MethodInvocation</classname>s. Depending on the configuration
approach, an interceptor may be specific to a single bean or shared between multiple
beans. The interceptor uses a
<interfacename>MethodSecurityMetadataSource</interfacename> instance to obtain the
configuration attributes that apply to a particular method invocation.
<classname>MapBasedMethodSecurityMetadataSource</classname> is used to store
configuration attributes keyed by method names (which can be wildcarded) and will be
used internally when the attributes are defined in the application context using the
<literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal>
elements. Other implementations will be used to handle annotation-based configuration. </para>
<section>
<title>Explicit MethodSecurityInterceptor Configuration</title>
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname>
directly in your application context for use with one of Spring AOP's proxying
mechanisms: <programlisting><![CDATA[
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
@ -40,26 +42,27 @@
</property>
</bean> ]]>
</programlisting></para>
</section>
</section>
</section>
<section xml:id="aspectj">
<info>
<title>AspectJ (JoinPoint) Security Interceptor</title>
</info>
<para>The AspectJ security interceptor is very similar to the AOP Alliance security interceptor
discussed in the previous section. Indeed we will only discuss the differences in this
section.</para>
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike the
AOP Alliance security interceptor, which relies on the Spring application context to weave in
the security interceptor via proxying, the <literal>AspectJSecurityInterceptor</literal> is
weaved in via the AspectJ compiler. It would not be uncommon to use both types of security
interceptors in the same application, with <literal>AspectJSecurityInterceptor</literal> being
used for domain object instance security and the AOP Alliance
<classname>MethodSecurityInterceptor</classname> being used for services layer
security.</para>
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is configured
in the Spring application context:</para>
<programlisting><![CDATA[
<section xml:id="aspectj">
<info>
<title>AspectJ (JoinPoint) Security Interceptor</title>
</info>
<para>The AspectJ security interceptor is very similar to the AOP Alliance security
interceptor discussed in the previous section. Indeed we will only discuss the
differences in this section.</para>
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike
the AOP Alliance security interceptor, which relies on the Spring application context to
weave in the security interceptor via proxying, the
<literal>AspectJSecurityInterceptor</literal> is weaved in via the AspectJ compiler. It
would not be uncommon to use both types of security interceptors in the same
application, with <literal>AspectJSecurityInterceptor</literal> being used for domain
object instance security and the AOP Alliance
<classname>MethodSecurityInterceptor</classname> being used for services layer
security.</para>
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is
configured in the Spring application context:</para>
<programlisting><![CDATA[
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
@ -72,18 +75,18 @@
</value>
</property>
</bean>]]> </programlisting>
<para>As you can see, aside from the class name, the
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
security interceptor. Indeed the two interceptors can share the same
<literal>securityMetadataSource</literal>, as the
<interfacename>SecurityMetadataSource</interfacename> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class. Of
course, your access decisions have access to the relevant AOP library-specific invocation (ie
<classname>MethodInvocation</classname> or <literal>JoinPoint</literal>) and as such can
consider a range of addition criteria when making access decisions (such as method
arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
<programlisting language="java">
<para>As you can see, aside from the class name, the
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
security interceptor. Indeed the two interceptors can share the same
<literal>securityMetadataSource</literal>, as the
<interfacename>SecurityMetadataSource</interfacename> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class.
Of course, your access decisions have access to the relevant AOP library-specific
invocation (ie <classname>MethodInvocation</classname> or <literal>JoinPoint</literal>)
and as such can consider a range of addition criteria when making access decisions (such
as method arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
<programlisting language="java">
package org.springframework.security.samples.aspectj;
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
@ -126,25 +129,26 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
}
}
</programlisting>
<para>In the above example, the security interceptor will be applied to every instance of
<literal>PersistableEntity</literal>, which is an abstract class not shown (you can use any
other class or <literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
statement has special meaning only within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target object to continue.</para>
<para>You will need to configure Spring to load the aspect and wire it with the
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
shown below:</para>
<programlisting><![CDATA[
<para>In the above example, the security interceptor will be applied to every instance of
<literal>PersistableEntity</literal>, which is an abstract class not shown (you can use
any other class or <literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
statement has special meaning only within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target object to
continue.</para>
<para>You will need to configure Spring to load the aspect and wire it with the
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
shown below:</para>
<programlisting><![CDATA[
<bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>]]>
</programlisting>
<para>That's it! Now you can create your beans from anywhere within your application, using
whatever means you think fit (eg <literal>new Person();</literal>) and they will have the
security interceptor applied.</para>
</section>
<para>That's it! Now you can create your beans from anywhere within your application, using
whatever means you think fit (eg <literal>new Person();</literal>) and they will have
the security interceptor applied.</para>
</section>
</chapter>

View File

@ -1,32 +1,32 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="security-filter-chain"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>The Security Filter Chain</title>
</info>
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so
it has no strong links to any particular web technology. It deals in
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s and
doesn't care whether the requests come from a browser, a web service client, an
<classname>HttpInvoker</classname> or an AJAX application. </para>
<para> Spring Security maintains a filter chain internally where each of the filters has a
particular responsibility and filters are added or removed from the configuration depending on
which services are required. The ordering of the filters is important as there are dependencies
between them. If you have been using <link xlink:href="#ns-config">namespace
configuration</link>, then the filters are automatically configured for you and you don't have
to define any Spring beans explicitly but here may be times when you want full control over the
security filter chain, either because you are using features which aren't supported in the
namespace, or you are using your own customized versions of classes.</para>
<section xml:id="delegating-filter-proxy">
<title><classname>DelegatingFilterProxy</classname></title>
<para> When using servlet filters, you obviously need to declare them in your
<filename>web.xml</filename>, or they will be ignored by the servlet container. In Spring
Security, the filter classes are also Spring beans defined in the application context and thus
able to take advantage of Spring's rich dependency-injection facilities and lifecycle
interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides the link between
<filename>web.xml</filename> and the application context. </para>
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like this
in the <filename>web.xml</filename> file: <programlisting><![CDATA[
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>The Security Filter Chain</title>
</info>
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally,
so it has no strong links to any particular web technology. It deals in
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
and doesn't care whether the requests come from a browser, a web service client, an
<classname>HttpInvoker</classname> or an AJAX application. </para>
<para> Spring Security maintains a filter chain internally where each of the filters has a
particular responsibility and filters are added or removed from the configuration depending
on which services are required. The ordering of the filters is important as there are
dependencies between them. If you have been using <link xlink:href="#ns-config">namespace
configuration</link>, then the filters are automatically configured for you and you don't
have to define any Spring beans explicitly but here may be times when you want full control
over the security filter chain, either because you are using features which aren't supported
in the namespace, or you are using your own customized versions of classes.</para>
<section xml:id="delegating-filter-proxy">
<title><classname>DelegatingFilterProxy</classname></title>
<para> When using servlet filters, you obviously need to declare them in your
<filename>web.xml</filename>, or they will be ignored by the servlet container. In
Spring Security, the filter classes are also Spring beans defined in the application
context and thus able to take advantage of Spring's rich dependency-injection facilities
and lifecycle interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides
the link between <filename>web.xml</filename> and the application context. </para>
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like
this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
@ -37,29 +37,29 @@
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting> Notice that the filter is actually a
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement the
logic of the filter. What <classname>DelegatingFilterProxy</classname> does is delegate the
<interfacename>Filter</interfacename>'s methods through to a bean which is obtained from the
Spring application context. This enables the bean to benefit from the Spring web application
context lifecycle support and configuration flexibility. The bean must implement
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that
in the <literal>filter-name</literal> element. Read the Javadoc for
<classname>DelegatingFilterProxy</classname> for more information</para>
</section>
<section xml:id="filter-chain-proxy">
<title><classname>FilterChainProxy</classname></title>
<para> It should now be clear that you can declare each Spring Security filter bean that you
require in your application context file and add a corresponding
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for each
filter, making sure that they are ordered correctly. This is a cumbersome approach and
clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We
would prefer to just add a single entry to <filename>web.xml</filename> and deal entirely with
the application context file for managing our web security beans. This is where Spring
Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with the
<literal>filter-name</literal> set to the bean name <quote>filterChainProxy</quote>. The
filter chain is then declared in the application context with the same bean name. Here's an
example: <programlisting language="xml"><![CDATA[
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement
the logic of the filter. What <classname>DelegatingFilterProxy</classname> does is
delegate the <interfacename>Filter</interfacename>'s methods through to a bean which is
obtained from the Spring application context. This enables the bean to benefit from the
Spring web application context lifecycle support and configuration flexibility. The bean
must implement <interfacename>javax.servlet.Filter</interfacename> and it must have the
same name as that in the <literal>filter-name</literal> element. Read the Javadoc for
<classname>DelegatingFilterProxy</classname> for more information</para>
</section>
<section xml:id="filter-chain-proxy">
<title><classname>FilterChainProxy</classname></title>
<para> It should now be clear that you can declare each Spring Security filter bean that you
require in your application context file and add a corresponding
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for
each filter, making sure that they are ordered correctly. This is a cumbersome approach
and clutters up the <filename>web.xml</filename> file quickly if we have a lot of
filters. We would prefer to just add a single entry to <filename>web.xml</filename> and
deal entirely with the application context file for managing our web security beans.
This is where Spring Secuirity's <classname>FilterChainProxy</classname> comes in. It is
wired using a <literal>DelegatingFilterProxy</literal>, just like in the example above,
but with the <literal>filter-name</literal> set to the bean name
<quote>filterChainProxy</quote>. The filter chain is then declared in the application
context with the same bean name. Here's an example: <programlisting language="xml"><![CDATA[
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters="
@ -75,106 +75,116 @@
</sec:filter-chain-map>
</bean>
]]>
</programlisting> The namespace element <literal>filter-chain-map</literal> is used
to set up the security filter chain(s) which are required within the
application<footnote><para>Note that you'll need to include the security namespace in your
application context XML file in order to use this syntax.</para></footnote>. It maps a
particular URL pattern to a chain of filters built up from the bean names specified in the
<literal>filters</literal> element. Both regular expressions and Ant Paths are supported,
and the most specific URIs appear first. At runtime the
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches the
current web request and the list of filter beans specified by the <literal>filters</literal>
attribute will be applied to that request. The filters will be invoked in the order they are
defined, so you have complete control over the filter chain which is applied to a particular
URL.</para>
<para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property of
<classname>SecurityContextPersistenceFilter</classname>). As web services will never present
a <literal>jsessionid</literal> on future requests, creating <literal>HttpSession</literal>s
for such user agents would be wasteful. If you had a high-volume application which required
maximum scalability, we recommend you use the approach shown above. For smaller applications,
using a single <classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para>
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will always
delegate <methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
methods through to the underlaying <interfacename>Filter</interfacename>s if such methods are
called against <classname>FilterChainProxy</classname> itself. In this case,
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy each
<literal>Filter</literal> bean once, no matter how many times it is declared in the filter
chain(s). You control the overall choice as to whether these methods are called or not via the
<literal>targetFilterLifecycle</literal> initialization parameter of
<literal>DelegatingFilterProxy</literal>. By default this property is
<literal>false</literal> and servlet container lifecycle invocations are not delegated
through <literal>DelegatingFilterProxy</literal>.</para>
<para> When we looked at how to set up web security using <link xlink:href="#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>
</programlisting> The namespace element <literal>filter-chain-map</literal> is used to set
up the security filter chain(s) which are required within the application<footnote>
<para>Note that you'll need to include the security namespace in your application
context XML file in order to use this syntax.</para>
</footnote>. It maps a particular URL pattern to a chain of filters built up from the
bean names specified in the <literal>filters</literal> element. Both regular expressions
and Ant Paths are supported, and the most specific URIs appear first. At runtime the
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches
the current web request and the list of filter beans specified by the
<literal>filters</literal> attribute will be applied to that request. The filters will
be invoked in the order they are defined, so you have complete control over the filter
chain which is applied to a particular URL.</para>
<para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property
of <classname>SecurityContextPersistenceFilter</classname>). As web services will never
present a <literal>jsessionid</literal> on future requests, creating
<literal>HttpSession</literal>s for such user agents would be wasteful. If you had a
high-volume application which required maximum scalability, we recommend you use the
approach shown above. For smaller applications, using a single
<classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para>
<para> 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>
</section>
</section>
</section>
<section>
<title>Filter Ordering</title>
<para>The order that filters are defined in the chain is very important. Irrespective of which
filters you are actually using, the order should be as follows:
<orderedlist><listitem><para><classname>ChannelProcessingFilter</classname>, because
it might need to redirect to a different
protocol</para></listitem><listitem><para><classname>ConcurrentSessionFilter</classname>,
because it doesn't use any <classname>SecurityContextHolder</classname> functionality
but needs to update the <interfacename>SessionRegistry</interfacename> to reflect
ongoing requests from the
principal</para></listitem><listitem><para><classname>SecurityContextPersistenceFilter</classname>,
so a <interfacename>SecurityContext</interfacename> can be set up in the
<classname>SecurityContextHolder</classname> at the beginning of a web request, and
any changes to the <interfacename>SecurityContext</interfacename> can be copied to the
<literal>HttpSession</literal> when the web request ends (ready for use with the next
web request)</para></listitem><listitem><para>Authentication processing mechanisms -
<classname>UsernamePasswordAuthenticationFilter</classname>,
<classname>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>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>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>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using some other framework that is also filter-based, then you need to make sure
that the Spring Security filters come first. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for use by the other
filters. Examples are the use of SiteMesh to decorate your web pages or a web framework like
Wicket which uses a filter to handle its requests. </para>
</section>
<!--
<section>
<title>Filter Ordering</title>
<para>The order that filters are defined in the chain is very important. Irrespective of
which filters you are actually using, the order should be as follows: <orderedlist>
<listitem>
<para><classname>ChannelProcessingFilter</classname>, because it might need to
redirect to a different protocol</para>
</listitem>
<listitem>
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
<classname>SecurityContextHolder</classname> functionality but needs to update
the <interfacename>SessionRegistry</interfacename> to reflect ongoing requests
from the principal</para>
</listitem>
<listitem>
<para><classname>SecurityContextPersistenceFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be set up in the
<classname>SecurityContextHolder</classname> at the beginning of a web request,
and any changes to the <interfacename>SecurityContext</interfacename> can be
copied to the <literal>HttpSession</literal> when the web request ends (ready
for use with the next web request)</para>
</listitem>
<listitem>
<para>Authentication processing mechanisms -
<classname>UsernamePasswordAuthenticationFilter</classname>,
<classname>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>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>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>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using some other framework that is also filter-based, then you need to make
sure that the Spring Security filters come first. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for use by the
other filters. Examples are the use of SiteMesh to decorate your web pages or a web
framework like Wicket which uses a filter to handle its requests. </para>
</section>
<!--
<section xml:id="taglib">
<info>
<title>Tag Libraries</title>

View File

@ -1,43 +1,46 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="session-mgmt"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Session Management</title>
</info>
<para>HTTP session related functonality is handled by a combination of the
<classname>SessionManagementFilter</classname> and the
<interfacename>SessionAuthenticationStrategy</interfacename> interface, which the filter
delegates to. Typical usage includes session-fixation protection attack prevention, detection of
session timeouts and restrictions on how many sessions an authenticated user may have open
concurrently.</para>
<section>
<title>SessionManagementFilter</title>
<para>The <classname>SessionManagementFilter</classname> checks the contents of the
<interfacename>SecurityContextRepository</interfacename> against the current contents of the
<classname>SecurityContextHolder</classname> to determine whether a user has been
authenticated during the current request, typically by a non-interactive authentication
mechanism, such as pre-authentication or remember-me <footnote><para>Authentication by
mechanisms which perform a redirect after authenticating (such as form-login) will not be
detected by <classname>SessionManagementFilter</classname>, as the filter will not be
invoked during the authenticating request. Session-management functionality has to be
handled separately in these cases. </para></footnote>. If the repository contains a
security context, the filter does nothing. If it doesn't, and the thread-local
<interfacename>SecurityContext</interfacename> contains a (non-anonymous)
<interfacename>Authentication</interfacename> object, the filter assumes they have been
authenticated by a previous filter in the stack. It will then invoke the configured
<interfacename>SessionAuthenticationStrategy</interfacename>.</para>
<para>If the user is not currently authenticated, the filter will check whether an invalid
session ID has been requested (because of a timeout, for example) and will redirect to the
configured <literal>invalidSessionUrl</literal> if set. The easiest way to configure this is
through the namespace, <link xlink:href="#ns-session-mgmt">as described earlier</link>.</para>
</section>
<section>
<title><interfacename>SessionAuthenticationStrategy</interfacename></title>
<para>
<interfacename>SessionAuthenticationStrategy</interfacename> is used by both
<classname>SessionManagementFilter</classname> and
<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[
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Session Management</title>
</info>
<para>HTTP session related functonality is handled by a combination of the
<classname>SessionManagementFilter</classname> and the
<interfacename>SessionAuthenticationStrategy</interfacename> interface, which the filter
delegates to. Typical usage includes session-fixation protection attack prevention,
detection of session timeouts and restrictions on how many sessions an authenticated user
may have open concurrently.</para>
<section>
<title>SessionManagementFilter</title>
<para>The <classname>SessionManagementFilter</classname> checks the contents of the
<interfacename>SecurityContextRepository</interfacename> against the current contents of
the <classname>SecurityContextHolder</classname> to determine whether a user has been
authenticated during the current request, typically by a non-interactive authentication
mechanism, such as pre-authentication or remember-me <footnote>
<para>Authentication by mechanisms which perform a redirect after authenticating (such
as form-login) will not be detected by
<classname>SessionManagementFilter</classname>, as the filter will not be invoked
during the authenticating request. Session-management functionality has to be
handled separately in these cases. </para>
</footnote>. If the repository contains a security context, the filter does nothing. If
it doesn't, and the thread-local <interfacename>SecurityContext</interfacename> contains
a (non-anonymous) <interfacename>Authentication</interfacename> object, the filter
assumes they have been authenticated by a previous filter in the stack. It will then
invoke the configured
<interfacename>SessionAuthenticationStrategy</interfacename>.</para>
<para>If the user is not currently authenticated, the filter will check whether an invalid
session ID has been requested (because of a timeout, for example) and will redirect to
the configured <literal>invalidSessionUrl</literal> if set. The easiest way to configure
this is through the namespace, <link xlink:href="#ns-session-mgmt">as described
earlier</link>.</para>
</section>
<section>
<title><interfacename>SessionAuthenticationStrategy</interfacename></title>
<para> <interfacename>SessionAuthenticationStrategy</interfacename> is used by both
<classname>SessionManagementFilter</classname> and
<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="FORM_LOGIN_FILTER" ref="myAuthFilter" />
<session-management session-authentication-strategy-ref="sas"/>
@ -56,46 +59,51 @@
</beans:bean>
]]>
</programlisting></para>
</section>
<section xml:id="concurrent-sessions">
<title>Concurrency Control</title>
<para>Spring Security is able to prevent a principal from concurrently authenticating to the
same application more than a specified number of times. Many ISVs take advantage of this to
enforce licensing, whilst network administrators like this feature because it helps prevent
people from sharing login names. You can, for example, stop user <quote>Batman</quote> from
logging onto the web application from two different sessions. You can either expire their
previous login or you can report an error when they try to log in again, preventing the second
login. Note that if you are using the second approach, a user who has not explicitly logged
out (but who has just closed their browser, for example) will not be able to log in again
until their original session expires.</para>
<para>Concurrency control is supported by the namespace, so please check the earlier namespace
chapter for the simplest configuration. Sometimes you need to customize things though. </para>
<para>The implementation uses a specialized version of
<interfacename>SessionAuthenticationStrategy</interfacename>, called
<classname>ConcurrentSessionControlStrategy</classname>. <note><para>Previously the
concurrent authentication check was made by the <classname>ProviderManager</classname>,
which could be injected with a <literal>ConcurrentSessionController</literal>. The latter
would check if the user was attempting to exceed the number of permitted sessions.
However, this approach required that an HTTP session be created in advance, which is
undesirable. In Spring Security 3, the user is first authenticated by the
<interfacename>AuthenticationManager</interfacename> and once they are successfully
authenticated, a session is created and the check is made whether they are allowed to have
another session open.</para></note></para>
<para>To use concurrent session support, you'll need to add the following to
<literal>web.xml</literal>: <programlisting><![CDATA[
</section>
<section xml:id="concurrent-sessions">
<title>Concurrency Control</title>
<para>Spring Security is able to prevent a principal from concurrently authenticating to the
same application more than a specified number of times. Many ISVs take advantage of this
to enforce licensing, whilst network administrators like this feature because it helps
prevent people from sharing login names. You can, for example, stop user
<quote>Batman</quote> from logging onto the web application from two different sessions.
You can either expire their previous login or you can report an error when they try to
log in again, preventing the second login. Note that if you are using the second
approach, a user who has not explicitly logged out (but who has just closed their
browser, for example) will not be able to log in again until their original session
expires.</para>
<para>Concurrency control is supported by the namespace, so please check the earlier
namespace chapter for the simplest configuration. Sometimes you need to customize things
though. </para>
<para>The implementation uses a specialized version of
<interfacename>SessionAuthenticationStrategy</interfacename>, called
<classname>ConcurrentSessionControlStrategy</classname>. <note>
<para>Previously the concurrent authentication check was made by the
<classname>ProviderManager</classname>, which could be injected with a
<literal>ConcurrentSessionController</literal>. The latter would check if the user
was attempting to exceed the number of permitted sessions. However, this approach
required that an HTTP session be created in advance, which is undesirable. In Spring
Security 3, the user is first authenticated by the
<interfacename>AuthenticationManager</interfacename> and once they are successfully
authenticated, a session is created and the check is made whether they are allowed
to have another session open.</para>
</note></para>
<para>To use concurrent session support, you'll need to add the following to
<literal>web.xml</literal>: <programlisting><![CDATA[
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener> ]]>
</programlisting></para>
<para>In addition, you will need to add the <literal>ConcurrentSessionFilter</literal> to your
<classname>FilterChainProxy</classname>. The <classname>ConcurrentSessionFilter</classname>
requires two properties, <literal>sessionRegistry</literal>, which generally points to an
instance of <classname>SessionRegistryImpl</classname>, and <literal>expiredUrl</literal>, which
points to the page to display when a session has expired. A configuration using the namespace
to create the <classname>FilterChainProxy</classname> and other default beans might look like
this: <programlisting><![CDATA[
<para>In addition, you will need to add the <literal>ConcurrentSessionFilter</literal> to
your <classname>FilterChainProxy</classname>. The
<classname>ConcurrentSessionFilter</classname> requires two properties,
<literal>sessionRegistry</literal>, which generally points to an instance of
<classname>SessionRegistryImpl</classname>, and <literal>expiredUrl</literal>, which
points to the page to display when a session has expired. A configuration using the
namespace to create the <classname>FilterChainProxy</classname> and other default beans
might look like this: <programlisting><![CDATA[
<http>
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
@ -125,12 +133,12 @@
class="org.springframework.security.core.session.SessionRegistryImpl" />
]]>
</programlisting></para>
<para>Adding the listener to <filename>web.xml</filename> causes an
<literal>ApplicationEvent</literal> to be published to the Spring
<literal>ApplicationContext</literal> every time a <literal>HttpSession</literal> commences
or terminates. This is critical, as it allows the <classname>SessionRegistryImpl</classname>
to be notified when a session ends. Without it, a user will never be able to log back in again
once they have exceeded their session allowance, even if they log out of another session or it
times out.</para>
</section>
<para>Adding the listener to <filename>web.xml</filename> causes an
<literal>ApplicationEvent</literal> to be published to the Spring
<literal>ApplicationContext</literal> every time a <literal>HttpSession</literal>
commences or terminates. This is critical, as it allows the
<classname>SessionRegistryImpl</classname> to be notified when a session ends. Without
it, a user will never be able to log back in again once they have exceeded their session
allowance, even if they log out of another session or it times out.</para>
</section>
</chapter>

View File

@ -1,126 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<book version="5.0" xml:id="spring-security-reference-guide" xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<info><title>Spring Security</title><subtitle>Reference Documentation</subtitle><authorgroup>
<author>
<personname>Ben Alex</personname>
</author>
<author>
<personname>Luke Taylor</personname>
</author>
</authorgroup>
<productname>Spring Security</productname>
<releaseinfo>3.0.2.RELEASE</releaseinfo>
</info>
<toc/>
<preface xml:id="preface">
<title>Preface</title>
<para>Spring Security provides a comprehensive security solution for J2EE-based enterprise
software applications. As you will discover as you venture through this reference guide, we
have tried to provide you a useful and highly configurable security system.</para>
<para>Security is an ever-moving target, and it's important to pursue a comprehensive,
system-wide approach. In security circles we encourage you to adopt "layers of security", so
that each layer tries to be as secure as possible in its own right, with successive layers
providing additional security. The "tighter" the security of each layer, the more robust and
safe your application will be. At the bottom level you'll need to deal with issues such as
transport security and system identification, in order to mitigate man-in-the-middle attacks.
Next you'll generally utilise firewalls, perhaps with VPNs or IP security to ensure only
authorised systems can attempt to connect. In corporate environments you may deploy a DMZ to
separate public-facing servers from backend database and application servers. Your operating
system will also play a critical part, addressing issues such as running processes as
non-privileged users and maximising file system security. An operating system will usually
also be configured with its own firewall. Hopefully somewhere along the way you'll be trying
to prevent denial of service and brute force attacks against the system. An intrusion
detection system will also be especially useful for monitoring and responding to attacks, with
such systems able to take protective action such as blocking offending TCP/IP addresses in
real-time. Moving to the higher layers, your Java Virtual Machine will hopefully be configured
to minimize the permissions granted to different Java types, and then your application will
add its own problem domain-specific security configuration. Spring Security makes this latter
area - application security - much easier. </para>
<para>Of course, you will need to properly address all security layers mentioned above, together
with managerial factors that encompass every layer. A non-exhaustive list of such managerial
factors would include security bulletin monitoring, patching, personnel vetting, audits,
change control, engineering management systems, data backup, disaster recovery, performance
benchmarking, load monitoring, centralised logging, incident response procedures etc.</para>
<para>With Spring Security being focused on helping you with the enterprise application security
layer, you will find that there are as many different requirements as there are business
problem domains. A banking application has different needs from an ecommerce application. An
ecommerce application has different needs from a corporate sales force automation tool. These
custom requirements make application security interesting, challenging and rewarding. </para>
<para>Please read <xref linkend="getting-started"/>, in its entirety to begin with. This will
introduce you to the framework and the namespace-based configuration system with which you can
get up and running quite quickly. To get more of an understanding of how Spring Security
works, and some of the classes you might need to use, you should then read <xref
linkend="overall-architecture"/>. The remaining parts of this guide are structured in a more
traditional reference style, designed to be read on an as-required basis. We'd also recommend
that you read up as much as possible on application security issues in general. Spring
Security is not a panacea which will solve all security issues. It is important that the
application is designed with security in mind from the start. Attempting to retrofit it is not
a good idea. In particular, if you are building a web application, you should be aware of the
many potential vulnerabilities such as cross-site scripting, request-forgery and
session-hijacking which you should be taking into account from the start. The OWASP web site
(http://www.owasp.org/) maintains a top ten list of web application vulnerabilities as well as
a lot of useful reference information. </para>
<para>We hope that you find this reference guide useful, and we welcome your feedback and <link
xlink:href="#jira">suggestions</link>. </para>
<para>Finally, welcome to the Spring Security <link xlink:href="#community">community</link>.
</para>
</preface>
<part xml:id="getting-started">
<title>Getting Started</title>
<partintro>
<para>The later parts of this guide provide an in-depth discussion of the framework
architecture and implementation classes, which you need to understand if you want to do any
serious customization. In this part, we'll introduce Spring Security 3.0, give a brief
overview of the project's history and take a slightly gentler look at how to get started
using the framework. In particular, we'll look at namespace configuration which provides a
much simpler way of securing your application compared to the traditional Spring bean
approach where you have to wire up all the implementation classes individually. </para>
<para> We'll also take a look at the sample applications that are available. It's worth trying
to run these and experimenting with them a bit even before you read the later sections - you
can dip back into them as your understanding of the framework increases. Please also check
out the <link xlink:href="http://static.springsource.org/spring-security/site/index.html"
>project website</link> as it has useful information on building the project, plus links
to articles, videos and tutorials. </para>
</partintro>
<xi:include href="introduction.xml"/>
<xi:include href="namespace-config.xml"/>
<xi:include href="samples.xml"/>
<xi:include href="community.xml"/>
</part>
<part xml:id="overall-architecture">
<title>Architecture and Implementation</title>
<partintro>
<para>Once you are familiar with setting up and running some namespace-configuration based
applications, you may wish to develop more of an understanding of how the framework actually
works behind the namespace facade. Like most software, Spring Security has certain central
interfaces, classes and conceptual abstractions that are commonly used throughout the
framework. In this part of the reference guide we will look at some of these and see how
they work together to support authentication and access-control within Spring
Security.</para>
</partintro>
<xi:include href="technical-overview.xml"/>
<xi:include href="core-services.xml"/>
</part>
<part xml:id="web-app-security">
<title>Web Application Security</title>
<partintro>
<para> Most Spring Security users will be using the framework in applications which make user
of HTTP and the Servlet API. In this part, we'll take a look at how Spring Security provides
authentication and access-control features for the web layer of an application. We'll look
behind the facade of the namespace and see which classes and interfaces are actually
assembled to provide web-layer security. In some situations it is necessary to use
traditional bean configuration to provide full control over the configuration, so we'll also
see how to configure these classes directly without the namespace.</para>
</partintro>
<xi:include href="security-filter-chain.xml"/>
<xi:include href="core-filters.xml"/>
<xi:include href="basic-and-digest-auth.xml"/>
<xi:include href="remember-me-authentication.xml"/>
<xi:include href="session-mgmt.xml"/>
<xi:include href="anon-auth-provider.xml"/>
</part>
<!--
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>Spring Security</title>
<subtitle>Reference Documentation</subtitle>
<authorgroup>
<author>
<personname>Ben Alex</personname>
</author>
<author>
<personname>Luke Taylor</personname>
</author>
</authorgroup>
<productname>Spring Security</productname>
<releaseinfo>3.0.2.RELEASE</releaseinfo>
</info>
<toc/>
<preface xml:id="preface">
<title>Preface</title>
<para>Spring Security provides a comprehensive security solution for J2EE-based enterprise
software applications. As you will discover as you venture through this reference guide,
we have tried to provide you a useful and highly configurable security system.</para>
<para>Security is an ever-moving target, and it's important to pursue a comprehensive,
system-wide approach. In security circles we encourage you to adopt "layers of
security", so that each layer tries to be as secure as possible in its own right, with
successive layers providing additional security. The "tighter" the security of each
layer, the more robust and safe your application will be. At the bottom level you'll
need to deal with issues such as transport security and system identification, in order
to mitigate man-in-the-middle attacks. Next you'll generally utilise firewalls, perhaps
with VPNs or IP security to ensure only authorised systems can attempt to connect. In
corporate environments you may deploy a DMZ to separate public-facing servers from
backend database and application servers. Your operating system will also play a
critical part, addressing issues such as running processes as non-privileged users and
maximising file system security. An operating system will usually also be configured
with its own firewall. Hopefully somewhere along the way you'll be trying to prevent
denial of service and brute force attacks against the system. An intrusion detection
system will also be especially useful for monitoring and responding to attacks, with
such systems able to take protective action such as blocking offending TCP/IP addresses
in real-time. Moving to the higher layers, your Java Virtual Machine will hopefully be
configured to minimize the permissions granted to different Java types, and then your
application will add its own problem domain-specific security configuration. Spring
Security makes this latter area - application security - much easier. </para>
<para>Of course, you will need to properly address all security layers mentioned above,
together with managerial factors that encompass every layer. A non-exhaustive list of
such managerial factors would include security bulletin monitoring, patching, personnel
vetting, audits, change control, engineering management systems, data backup, disaster
recovery, performance benchmarking, load monitoring, centralised logging, incident
response procedures etc.</para>
<para>With Spring Security being focused on helping you with the enterprise application
security layer, you will find that there are as many different requirements as there are
business problem domains. A banking application has different needs from an ecommerce
application. An ecommerce application has different needs from a corporate sales force
automation tool. These custom requirements make application security interesting,
challenging and rewarding. </para>
<para>Please read <xref linkend="getting-started"/>, in its entirety to begin with. This
will introduce you to the framework and the namespace-based configuration system with
which you can get up and running quite quickly. To get more of an understanding of how
Spring Security works, and some of the classes you might need to use, you should then
read <xref linkend="overall-architecture"/>. The remaining parts of this guide are
structured in a more traditional reference style, designed to be read on an as-required
basis. We'd also recommend that you read up as much as possible on application security
issues in general. Spring Security is not a panacea which will solve all security
issues. It is important that the application is designed with security in mind from the
start. Attempting to retrofit it is not a good idea. In particular, if you are building
a web application, you should be aware of the many potential vulnerabilities such as
cross-site scripting, request-forgery and session-hijacking which you should be taking
into account from the start. The OWASP web site (http://www.owasp.org/) maintains a top
ten list of web application vulnerabilities as well as a lot of useful reference
information. </para>
<para>We hope that you find this reference guide useful, and we welcome your feedback and
<link xlink:href="#jira">suggestions</link>. </para>
<para>Finally, welcome to the Spring Security <link xlink:href="#community"
>community</link>. </para>
</preface>
<part xml:id="getting-started">
<title>Getting Started</title>
<partintro>
<para>The later parts of this guide provide an in-depth discussion of the framework
architecture and implementation classes, which you need to understand if you want to
do any serious customization. In this part, we'll introduce Spring Security 3.0,
give a brief overview of the project's history and take a slightly gentler look at
how to get started using the framework. In particular, we'll look at namespace
configuration which provides a much simpler way of securing your application
compared to the traditional Spring bean approach where you have to wire up all the
implementation classes individually. </para>
<para> We'll also take a look at the sample applications that are available. It's worth
trying to run these and experimenting with them a bit even before you read the later
sections - you can dip back into them as your understanding of the framework
increases. Please also check out the <link
xlink:href="http://static.springsource.org/spring-security/site/index.html"
>project website</link> as it has useful information on building the project,
plus links to articles, videos and tutorials. </para>
</partintro>
<xi:include href="introduction.xml"/>
<xi:include href="namespace-config.xml"/>
<xi:include href="samples.xml"/>
<xi:include href="community.xml"/>
</part>
<part xml:id="overall-architecture">
<title>Architecture and Implementation</title>
<partintro>
<para>Once you are familiar with setting up and running some namespace-configuration
based applications, you may wish to develop more of an understanding of how the
framework actually works behind the namespace facade. Like most software, Spring
Security has certain central interfaces, classes and conceptual abstractions that
are commonly used throughout the framework. In this part of the reference guide we
will look at some of these and see how they work together to support authentication
and access-control within Spring Security.</para>
</partintro>
<xi:include href="technical-overview.xml"/>
<xi:include href="core-services.xml"/>
</part>
<part xml:id="web-app-security">
<title>Web Application Security</title>
<partintro>
<para> Most Spring Security users will be using the framework in applications which make
user of HTTP and the Servlet API. In this part, we'll take a look at how Spring
Security provides authentication and access-control features for the web layer of an
application. We'll look behind the facade of the namespace and see which classes and
interfaces are actually assembled to provide web-layer security. In some situations
it is necessary to use traditional bean configuration to provide full control over
the configuration, so we'll also see how to configure these classes directly without
the namespace.</para>
</partintro>
<xi:include href="security-filter-chain.xml"/>
<xi:include href="core-filters.xml"/>
<xi:include href="basic-and-digest-auth.xml"/>
<xi:include href="remember-me-authentication.xml"/>
<xi:include href="session-mgmt.xml"/>
<xi:include href="anon-auth-provider.xml"/>
</part>
<!--
<part xml:id="authentication">
<title>Authentication</title>
<partintro>
@ -145,42 +155,43 @@
<xi:include href="dao-auth-provider.xml"/>
</part>
-->
<part xml:id="authorization">
<title>Authorization</title>
<partintro>
<para>The advanced authorization capabilities within Spring Security represent one of the most
compelling reasons for its popularity. Irrespective of how you choose to authenticate -
whether using a Spring Security-provided mechanism and provider, or integrating with a
container or other non-Spring Security authentication authority - you will find the
authorization services can be used within your application in a consistent and simple
way.</para>
<para>In this part we'll explore the different
<classname>AbstractSecurityInterceptor</classname> implementations, which were introduced
in Part I. We then move on to explore how to fine-tune authorization through use of domain
access control lists.</para>
</partintro>
<xi:include href="authorization-common.xml"/>
<xi:include href="secured-objects.xml"/>
<xi:include href="el-access.xml"/>
</part>
<part xml:id="advanced-topics">
<title>Additional Topics</title>
<!--
<part xml:id="authorization">
<title>Authorization</title>
<partintro>
<para>The advanced authorization capabilities within Spring Security represent one of
the most compelling reasons for its popularity. Irrespective of how you choose to
authenticate - whether using a Spring Security-provided mechanism and provider, or
integrating with a container or other non-Spring Security authentication authority -
you will find the authorization services can be used within your application in a
consistent and simple way.</para>
<para>In this part we'll explore the different
<classname>AbstractSecurityInterceptor</classname> implementations, which were
introduced in Part I. We then move on to explore how to fine-tune authorization
through use of domain access control lists.</para>
</partintro>
<xi:include href="authorization-common.xml"/>
<xi:include href="secured-objects.xml"/>
<xi:include href="el-access.xml"/>
</part>
<part xml:id="advanced-topics">
<title>Additional Topics</title>
<!--
Essentially standalone features which do not have to follow on directly from earlier chapters
-->
<partintro>
<para> In this part we cover features which require a knowledge of previous chapters as well
as some of the more advanced and less-commonly used features of the framework.</para>
</partintro>
<xi:include href="domain-acls.xml"/>
<xi:include href="preauth.xml"/>
<xi:include href="ldap-auth-provider.xml"/>
<xi:include href="taglibs.xml"/>
<xi:include href="jaas-auth-provider.xml"/>
<xi:include href="cas-auth-provider.xml"/>
<xi:include href="x509-auth-provider.xml"/>
<xi:include href="runas-auth-provider.xml"/>
</part>
<xi:include href="appendix-db-schema.xml"/>
<xi:include href="appendix-namespace.xml"/>
<partintro>
<para> In this part we cover features which require a knowledge of previous chapters as
well as some of the more advanced and less-commonly used features of the
framework.</para>
</partintro>
<xi:include href="domain-acls.xml"/>
<xi:include href="preauth.xml"/>
<xi:include href="ldap-auth-provider.xml"/>
<xi:include href="taglibs.xml"/>
<xi:include href="jaas-auth-provider.xml"/>
<xi:include href="cas-auth-provider.xml"/>
<xi:include href="x509-auth-provider.xml"/>
<xi:include href="runas-auth-provider.xml"/>
</part>
<xi:include href="appendix-db-schema.xml"/>
<xi:include href="appendix-namespace.xml"/>
</book>

View File

@ -14,15 +14,15 @@
<title>The <literal>authorize</literal> Tag</title>
<para> This tag is used to determine whether its contents should be evaluated or not. In
Spring Security 3.0, it can be used in two ways <footnote>
<para>The legacy options from Spring Security 2.0 are also supported, but
discouraged.</para>
<para>The legacy options from Spring Security 2.0 are also supported, but
discouraged.</para>
</footnote>. The first approach uses a <link xlink:href="el-access-we">web-security
expression</link>, specified in the <literal>access</literal> attribute of the tag.
The expression evaluation will be delegated to the
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the
application context (you should have web expressions enabled in your
<literal>&lt;http></literal> namespace configuration to make sure this service is
available). So, for example, you might
expression</link>, specified in the <literal>access</literal> attribute of the tag. The
expression evaluation will be delegated to the
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the application
context (you should have web expressions enabled in your <literal>&lt;http></literal>
namespace configuration to make sure this service is available). So, for example, you
might
have<programlisting>&lt;sec:authorize access="hasRole('supervisor')">
This content will only be visible to users who have
@ -40,7 +40,7 @@ This content will only be visible to users who are authorized to send requests t
&lt;/sec:authorize></programlisting>To
use this tag there must also be an instance of
<interfacename>WebInvocationPrivilegeEvaluator</interfacename> in your application
<interfacename>WebInvocationPrivilegeEvaluator</interfacename> in your application
context. If you are using the namespace, one will automatically be registered. This is
an instance of <classname>DefaultWebInvocationPrivilegeEvaluator</classname>, which
creates a dummy web request for the supplied URL and invokes the security interceptor to
@ -56,15 +56,15 @@ This content will only be visible to users who are authorized to send requests t
<para>This tag allows access to the current <interfacename>Authentication</interfacename>
object stored in the security context. It renders a property of the object directly in
the JSP. So, for example, if the <literal>principal</literal> property of the
<interfacename>Authentication</interfacename> is an instance of Spring Security's
<interfacename>UserDetails</interfacename> object, then using
<literal>&lt;sec:authentication property="principal.username" /></literal> will
render the name of the current user.</para>
<interfacename>Authentication</interfacename> is an instance of Spring Security's
<interfacename>UserDetails</interfacename> object, then using
<literal>&lt;sec:authentication property="principal.username" /></literal> will render
the name of the current user.</para>
<para>Of course, it isn't necessary to use JSP tags for this kind of thing and some people
prefer to keep as little logic as possible in the view. You can access the
<interfacename>Authentication</interfacename> object in your MVC controller (by
calling <code>SecurityContextHolder.getContext().getAuthentication()</code>) and add the
data directly to your model for rendering by the view.</para>
<interfacename>Authentication</interfacename> object in your MVC controller (by calling
<code>SecurityContextHolder.getContext().getAuthentication()</code>) and add the data
directly to your model for rendering by the view.</para>
</section>
<section>
<title>The <literal>accesscontrollist</literal> Tag</title>
@ -80,14 +80,14 @@ represented by the values "1" or "2" on the given object.
&lt;/sec:accesscontrollist></programlisting></para>
<para>The permissions are passed to the <interfacename>PermissionFactory</interfacename>
defined in the application context, converting them to ACL
<interfacename>Permission</interfacename> instances, so they may be any format which
is supported by the factory - they don't have to be integers, they could be strings like
<literal>READ</literal> or <literal>WRITE</literal>. If no
<interfacename>PermissionFactory</interfacename> is found, an instance of
<classname>DefaultPermissionFactory</classname> will be used. The
<interfacename>AclService</interfacename>from the application context will be used
to load the <interfacename>Acl</interfacename> instance for the supplied object. The
<interfacename>Acl</interfacename> will be invoked with the required permissions to
<interfacename>Permission</interfacename> instances, so they may be any format which is
supported by the factory - they don't have to be integers, they could be strings like
<literal>READ</literal> or <literal>WRITE</literal>. If no
<interfacename>PermissionFactory</interfacename> is found, an instance of
<classname>DefaultPermissionFactory</classname> will be used. The
<interfacename>AclService</interfacename>from the application context will be used to
load the <interfacename>Acl</interfacename> instance for the supplied object. The
<interfacename>Acl</interfacename> will be invoked with the required permissions to
check if any of them are granted.</para>
</section>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +1,38 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Web Application Infrastructure</title>
</info>
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Web Application Infrastructure</title>
</info>
<section xml:id="filters">
<title>The Security Filter Chain</title>
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so
it has no strong links to any particular web technology. It deals in
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
and doesn't care whether the requests come from a browser, a web service client, an
<classname>HttpInvoker</classname> or an AJAX application. </para>
<para> Spring Security maintains a filter chain internally where each of the filters has a
particular responsibility and filters are added or removed from the configuration depending on
which services are required. The ordering of the filters is important as there are
dependencies between them. If you have been using <link xlink:href="#ns-config">namespace
configuration</link>, then the filters are automatically configured for you and you don't
have to define any Spring beans explicitly but here may be times when you want full control
over the security filter chain, either because you are using features which aren't supported
in the namespace, or you are using your own customized versions of classes.</para>
<section xml:id="delegating-filter-proxy">
<title><classname>DelegatingFilterProxy</classname></title>
<para> When using servlet filters, you obviously need to declare them in your
<filename>web.xml</filename>, or they will be ignored by the servlet container. In Spring
Security, the filter classes are also Spring beans defined in the application context and
thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle
interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides the link between
<filename>web.xml</filename> and the application context. </para>
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like
this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
<section xml:id="filters">
<title>The Security Filter Chain</title>
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC)
internally, so it has no strong links to any particular web technology. It deals in
<classname>HttpServletRequest</classname>s and
<classname>HttpServletResponse</classname>s and doesn't care whether the requests come
from a browser, a web service client, an <classname>HttpInvoker</classname> or an AJAX
application. </para>
<para> Spring Security maintains a filter chain internally where each of the filters has a
particular responsibility and filters are added or removed from the configuration
depending on which services are required. The ordering of the filters is important as
there are dependencies between them. If you have been using <link
xlink:href="#ns-config">namespace configuration</link>, then the filters are
automatically configured for you and you don't have to define any Spring beans
explicitly but here may be times when you want full control over the security filter
chain, either because you are using features which aren't supported in the namespace, or
you are using your own customized versions of classes.</para>
<section xml:id="delegating-filter-proxy">
<title><classname>DelegatingFilterProxy</classname></title>
<para> When using servlet filters, you obviously need to declare them in your
<filename>web.xml</filename>, or they will be ignored by the servlet container. In
Spring Security, the filter classes are also Spring beans defined in the application
context and thus able to take advantage of Spring's rich dependency-injection
facilities and lifecycle interfaces. Spring's
<classname>DelegatingFilterProxy</classname> provides the link between
<filename>web.xml</filename> and the application context. </para>
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something
like this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
@ -40,29 +43,31 @@
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting> Notice that the filter is actually a
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement
the logic of the filter. What <classname>DelegatingFilterProxy</classname> does is delegate
the <interfacename>Filter</interfacename>'s methods through to a bean which is obtained from
the Spring application context. This enables the bean to benefit from the Spring web
application context lifecycle support and configuration flexibility. The bean must implement
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that
in the <literal>filter-name</literal> element. Read the Javadoc for
<classname>DelegatingFilterProxy</classname> for more information</para>
</section>
<section xml:id="filter-chain-proxy">
<title><classname>FilterChainProxy</classname></title>
<para> It should now be clear that you can declare each Spring Security filter bean that you
require in your application context file and add a corresponding
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for
each filter, making sure that they are ordered correctly. This is a cumbersome approach and
clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We
would prefer to just add a single entry to <filename>web.xml</filename> and deal entirely
with the application context file for managing our web security beans. This is where Spring
Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with the
<literal>filter-name</literal> set to the bean name <quote>filterChainProxy</quote>. The
filter chain is then declared in the application context with the same bean name. Here's an
example: <programlisting language="xml"><![CDATA[
<literal>DelegatingFilterProxy</literal>, and not the class that will actually
implement the logic of the filter. What <classname>DelegatingFilterProxy</classname>
does is delegate the <interfacename>Filter</interfacename>'s methods through to a
bean which is obtained from the Spring application context. This enables the bean to
benefit from the Spring web application context lifecycle support and configuration
flexibility. The bean must implement
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name
as that in the <literal>filter-name</literal> element. Read the Javadoc for
<classname>DelegatingFilterProxy</classname> for more information</para>
</section>
<section xml:id="filter-chain-proxy">
<title><classname>FilterChainProxy</classname></title>
<para> It should now be clear that you can declare each Spring Security filter bean that
you require in your application context file and add a corresponding
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename>
for each filter, making sure that they are ordered correctly. This is a cumbersome
approach and clutters up the <filename>web.xml</filename> file quickly if we have a
lot of filters. We would prefer to just add a single entry to
<filename>web.xml</filename> and deal entirely with the application context file for
managing our web security beans. This is where Spring Secuiryt's
<classname>FilterChainProxy</classname> comes in. It is wired using a
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with
the <literal>filter-name</literal> set to the bean name
<quote>filterChainProxy</quote>. The filter chain is then declared in the
application context with the same bean name. Here's an example: <programlisting language="xml"><![CDATA[
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters="
@ -78,127 +83,134 @@
</sec:filter-chain-map>
</bean>
]]>
</programlisting> The namespace element <literal>filter-chain-map</literal> is
used to set up the security filter chain(s) which are required within the application<footnote>
<para>Note that you'll need to include the security namespace in your application context
XML file in order to use this syntax.</para>
</footnote>. It maps a particular URL pattern to a chain of filters built up from the bean
names specified in the <literal>filters</literal> element. Both regular expressions and Ant
Paths are supported, and the most specific URIs appear first. At runtime the
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches the
current web request and the list of filter beans specified by the <literal>filters</literal>
attribute will be applied to that request. The filters will be invoked in the order they are
defined, so you have complete control over the filter chain which is applied to a particular
URL.</para>
<para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property
of <classname>SecurityContextPersistenceFilter</classname>). As web services will never
present a <literal>jsessionid</literal> on future requests, creating
<literal>HttpSession</literal>s for such user agents would be wasteful. If you had a
high-volume application which required maximum scalability, we recommend you use the
approach shown above. For smaller applications, using a single
<classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para>
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will always
delegate <methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
methods through to the underlaying <interfacename>Filter</interfacename>s if such methods
are called against <classname>FilterChainProxy</classname> itself. In this case,
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy each
<literal>Filter</literal> bean once, no matter how many times it is declared in the filter
chain(s). You control the overall choice as to whether these methods are called or not via
the <literal>targetFilterLifecycle</literal> initialization parameter of
<literal>DelegatingFilterProxy</literal>. By default this property is
<literal>false</literal> and servlet container lifecycle invocations are not delegated
through <literal>DelegatingFilterProxy</literal>.</para>
<para> When we looked at how to set up web security using <link
xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
<literal>DelegatingFilterProxy</literal> with the name
<quote>springSecurityFilterChain</quote>. You should now be able to see that this is the
name of the <classname>FilterChainProxy</classname> which is created by the namespace. </para>
<section>
<title>Bypassing the Filter Chain</title>
<para> As with the namespace, you can use the attribute <literal>filters = "none"</literal>
as an alternative to supplying a filter bean list. This will omit the request pattern from
the security filter chain entirely. Note that anything matching this path will then have
no authentication or authorization services applied and will be freely accessible. If you
want to make use of the contents of the <classname>SecurityContext</classname> contents
during a request, then it must have passed through the security filter chain. Otherwise
the <classname>SecurityContextHolder</classname> will not have been populated and the
contents will be null.</para>
</section>
</programlisting> The namespace element <literal>filter-chain-map</literal> is used to set
up the security filter chain(s) which are required within the application<footnote>
<para>Note that you'll need to include the security namespace in your application
context XML file in order to use this syntax.</para>
</footnote>. It maps a particular URL pattern to a chain of filters built up from
the bean names specified in the <literal>filters</literal> element. Both regular
expressions and Ant Paths are supported, and the most specific URIs appear first. At
runtime the <classname>FilterChainProxy</classname> will locate the first URI
pattern that matches the current web request and the list of filter beans specified
by the <literal>filters</literal> attribute will be applied to that request. The
filters will be invoked in the order they are defined, so you have complete control
over the filter chain which is applied to a particular URL.</para>
<para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a
property of <classname>SecurityContextPersistenceFilter</classname>). As web
services will never present a <literal>jsessionid</literal> on future requests,
creating <literal>HttpSession</literal>s for such user agents would be wasteful. If
you had a high-volume application which required maximum scalability, we recommend
you use the approach shown above. For smaller applications, using a single
<classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para>
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will
always delegate <methodname>init(FilterConfig)</methodname> and
<methodname>destroy()</methodname> methods through to the underlaying
<interfacename>Filter</interfacename>s if such methods are called against
<classname>FilterChainProxy</classname> itself. In this case,
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy
each <literal>Filter</literal> bean once, no matter how many times it is declared in
the filter chain(s). You control the overall choice as to whether these methods are
called or not via the <literal>targetFilterLifecycle</literal> initialization
parameter of <literal>DelegatingFilterProxy</literal>. By default this property is
<literal>false</literal> and servlet container lifecycle invocations are not
delegated through <literal>DelegatingFilterProxy</literal>.</para>
<para> When we looked at how to set up web security using <link
xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
<literal>DelegatingFilterProxy</literal> with the name
<quote>springSecurityFilterChain</quote>. You should now be able to see that this is
the name of the <classname>FilterChainProxy</classname> which is created by the
namespace. </para>
<section>
<title>Bypassing the Filter Chain</title>
<para> As with the namespace, you can use the attribute <literal>filters =
"none"</literal> as an alternative to supplying a filter bean list. This will
omit the request pattern from the security filter chain entirely. Note that
anything matching this path will then have no authentication or authorization
services applied and will be freely accessible. If you want to make use of the
contents of the <classname>SecurityContext</classname> contents during a
request, then it must have passed through the security filter chain. Otherwise
the <classname>SecurityContextHolder</classname> will not have been populated
and the contents will be null.</para>
</section>
</section>
<section>
<title>Filter Ordering</title>
<para>The order that filters are defined in the chain is very important. Irrespective of
which filters you are actually using, the order should be as follows: <orderedlist>
<listitem>
<para><classname>ChannelProcessingFilter</classname>, because it might need to
redirect to a different protocol</para>
</listitem>
<listitem>
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
<classname>SecurityContextHolder</classname> functionality but needs to
update the <interfacename>SessionRegistry</interfacename> to reflect ongoing
requests from the principal</para>
</listitem>
<listitem>
<para><classname>SecurityContextPersistenceFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be set up in the
<classname>SecurityContextHolder</classname> at the beginning of a web
request, and any changes to the
<interfacename>SecurityContext</interfacename> can be copied to the
<literal>HttpSession</literal> when the web request ends (ready for use with
the next web request)</para>
</listitem>
<listitem>
<para>Authentication processing mechanisms -
<classname>UsernamePasswordAuthenticationFilter</classname>,
<classname>CasProcessingFilter</classname>,
<classname>BasicProcessingFilter</classname> etc - so that the
<classname>SecurityContextHolder</classname> can be modified to contain a
valid <interfacename>Authentication</interfacename> request token</para>
</listitem>
<listitem>
<para>The <literal>SecurityContextHolderAwareRequestFilter</literal>, if you are
using it to install a Spring Security aware
<literal>HttpServletRequestWrapper</literal> into your servlet
container</para>
</listitem>
<listitem>
<para><classname>RememberMeProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, and the request presents a
cookie that enables remember-me services to take place, a suitable
remembered <interfacename>Authentication</interfacename> object will be put
there</para>
</listitem>
<listitem>
<para><classname>AnonymousProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, an anonymous
<interfacename>Authentication</interfacename> object will be put
there</para>
</listitem>
<listitem>
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring
Security exceptions so that either an HTTP error response can be returned or
an appropriate <interfacename>AuthenticationEntryPoint</interfacename> can
be launched</para>
</listitem>
<listitem>
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and
raise exceptions when access is denied</para>
</listitem>
</orderedlist></para>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using some other framework that is also filter-based, then you need to
make sure that the Spring Security filters come first. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for use by the
other filters. Examples are the use of SiteMesh to decorate your web pages or a web
framework like Wicket which uses a filter to handle its requests. </para>
</section>
</section>
<section>
<title>Filter Ordering</title>
<para>The order that filters are defined in the chain is very important. Irrespective of which
filters you are actually using, the order should be as follows:
<orderedlist>
<listitem>
<para><classname>ChannelProcessingFilter</classname>, because it might need to redirect
to a different protocol</para>
</listitem>
<listitem>
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
<classname>SecurityContextHolder</classname> functionality but needs to update the
<interfacename>SessionRegistry</interfacename> to reflect ongoing requests from the
principal</para>
</listitem>
<listitem>
<para><classname>SecurityContextPersistenceFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be set up in the
<classname>SecurityContextHolder</classname> at the beginning of a web request, and
any changes to the <interfacename>SecurityContext</interfacename> can be copied to the
<literal>HttpSession</literal> when the web request ends (ready for use with the
next web request)</para>
</listitem>
<listitem>
<para>Authentication processing mechanisms -
<classname>UsernamePasswordAuthenticationFilter</classname>,
<classname>CasProcessingFilter</classname>,
<classname>BasicProcessingFilter</classname> etc - so that the
<classname>SecurityContextHolder</classname> can be modified to contain a valid
<interfacename>Authentication</interfacename> request token</para>
</listitem>
<listitem>
<para>The <literal>SecurityContextHolderAwareRequestFilter</literal>, if you are using
it to install a Spring Security aware <literal>HttpServletRequestWrapper</literal>
into your servlet container</para>
</listitem>
<listitem>
<para><classname>RememberMeProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, and the request presents a cookie that
enables remember-me services to take place, a suitable remembered
<interfacename>Authentication</interfacename> object will be put there</para>
</listitem>
<listitem>
<para><classname>AnonymousProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, an anonymous
<interfacename>Authentication</interfacename> object will be put there</para>
</listitem>
<listitem>
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring Security
exceptions so that either an HTTP error response can be returned or an appropriate
<interfacename>AuthenticationEntryPoint</interfacename> can be launched</para>
</listitem>
<listitem>
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and raise
exceptions when access is denied</para>
</listitem>
</orderedlist></para>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using some other framework that is also filter-based, then you need to make
sure that the Spring Security filters come first. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for use by the other
filters. Examples are the use of SiteMesh to decorate your web pages or a web framework like
Wicket which uses a filter to handle its requests. </para>
</section>
</section>
<!--
<!--
<section xml:id="taglib">
<info>
<title>Tag Libraries</title>

View File

@ -1,7 +1,12 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="x509">
<info><title>X.509 Authentication</title></info>
<info>
<title>X.509 Authentication</title>
</info>
<section xml:id="x509-overview"><info><title>Overview</title></info>
<section xml:id="x509-overview">
<info>
<title>Overview</title>
</info>
<para>The most common use of X.509 certificate authentication is in verifying the identity
of a server when using SSL, most commonly when using HTTPS from a browser. The browser
@ -10,38 +15,47 @@
maintains.</para>
<para>You can also use SSL with <quote>mutual authentication</quote>; the server will then
request a valid certificate from the client as part of the SSL handshake. The server
will authenticate the client by checking that its certificate is signed by an
acceptable authority. If a valid certificate has been provided, it can be obtained
through the servlet API in an application. Spring Security X.509 module extracts the
certificate using a filter. It maps the certificate to an application user and loads that
user's set of granted authorities for use with the standard Spring Security infrastructure.</para>
will authenticate the client by checking that its certificate is signed by an acceptable
authority. If a valid certificate has been provided, it can be obtained through the
servlet API in an application. Spring Security X.509 module extracts the certificate
using a filter. It maps the certificate to an application user and loads that user's set
of granted authorities for use with the standard Spring Security infrastructure.</para>
<para>You should be familiar with using certificates and setting up client authentication
for your servlet container before attempting to use it with Spring Security. Most of the
work is in creating and installing suitable certificates and keys. For example, if
you're using Tomcat then read the instructions here <uri xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html">http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html</uri>. It's important that
you get this working before trying it out with Spring Security</para>
you're using Tomcat then read the instructions here <uri
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html"
>http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html</uri>. It's important that you
get this working before trying it out with Spring Security</para>
</section>
<section><info><title>Adding X.509 Authentication to Your Web Application</title></info>
<section>
<info>
<title>Adding X.509 Authentication to Your Web Application</title>
</info>
<para> Enabling X.509 client authentication is very straightforward. Just add the <literal>&lt;x509/&gt;</literal> element to your http security namespace configuration. <programlisting>
<para> Enabling X.509 client authentication is very straightforward. Just add the
<literal>&lt;x509/&gt;</literal> element to your http security namespace configuration.
<programlisting>
&lt;http&gt;
...
&lt;x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/&gt;
...
&lt;/http&gt;
</programlisting> The element has two optional attributes: <itemizedlist>
<listitem>
<para><literal>subject-principal-regex</literal>. The regular expression used to
extract a username from the certificate's subject name. The default value is
shown above. This is the username which will be passed to the <interfacename>UserDetailsService</interfacename> to load the authorities for the
user.</para>
</listitem>
<listitem>
<para><literal>user-service-ref</literal>. This is the bean Id of the
<interfacename>UserDetailsService</interfacename> to be used with X.509.
It isn't needed if there is only one defined in your application
context.</para>
</listitem>
</programlisting>
The element has two optional attributes: <itemizedlist>
<listitem>
<para><literal>subject-principal-regex</literal>. The regular expression used to
extract a username from the certificate's subject name. The default value is
shown above. This is the username which will be passed to the
<interfacename>UserDetailsService</interfacename> to load the authorities for
the user.</para>
</listitem>
<listitem>
<para><literal>user-service-ref</literal>. This is the bean Id of the
<interfacename>UserDetailsService</interfacename> to be used with X.509. It
isn't needed if there is only one defined in your application context.</para>
</listitem>
</itemizedlist> The <literal>subject-principal-regex</literal> should contain a single
group. For example the default expression "CN=(.*?)," matches the common name field. So
if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this will give a
@ -54,21 +68,21 @@
authentication with other options such as a form-based login. </para>
</section>
<section xml:id="x509-ssl-config">
<info><title>Setting up SSL in Tomcat</title></info>
<info>
<title>Setting up SSL in Tomcat</title>
</info>
<para>There are some pre-generated certificates in the
<filename>samples/certificate</filename> directory in the Spring Security project.
You can use these to enable SSL for testing if you don't want to generate your own. The file
<filename>server.jks</filename> contains the server certificate, private key and the
<filename>samples/certificate</filename> directory in the Spring Security project. You
can use these to enable SSL for testing if you don't want to generate your own. The file
<filename>server.jks</filename> contains the server certificate, private key and the
issuing certificate authority certificate. There are also some client certificate files
for the users from the sample applications. You can install these in your browser to enable
SSL client authentication.
</para>
<para>
To run tomcat with SSL support, drop the <filename>server.jks</filename> file into the
tomcat <filename>conf</filename> directory and add the following connector to the
for the users from the sample applications. You can install these in your browser to
enable SSL client authentication. </para>
<para> To run tomcat with SSL support, drop the <filename>server.jks</filename> file into
the tomcat <filename>conf</filename> directory and add the following connector to the
<filename>server.xml</filename> file
<programlisting>
<programlisting>
&lt;Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="${catalina.home}/conf/server.jks"
@ -77,10 +91,10 @@
truststoreType="JKS" truststorePass="password"
/&gt;
</programlisting>
<parameter>clientAuth</parameter> can also be set to <parameter>want</parameter> if you still
want SSL connections to succeed even if the client doesn't provide a certificate.
<parameter>clientAuth</parameter> can also be set to <parameter>want</parameter> if you
still want SSL connections to succeed even if the client doesn't provide a certificate.
Clients which don't present a certificate won't be able to access any objects secured by
Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication.
</para>
Spring Security unless you use a non-X.509 authentication mechanism, such as form
authentication. </para>
</section>
</chapter>
</chapter>