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> <title>Overview</title>
</info> </info>
<para>It's generally considered good security practice to adopt a <para>It's generally considered good security practice to adopt a
<quote>deny-by-default</quote> where you explicitly specify what is allowed and <quote>deny-by-default</quote> where you explicitly specify what is allowed and disallow
disallow everything else. Defining what is accessible to unauthenticated users is a everything else. Defining what is accessible to unauthenticated users is a similar
similar situation, particularly for web applications. Many sites require that users must situation, particularly for web applications. Many sites require that users must be
be authenticated for anything other than a few URLs (for example the home and login authenticated for anything other than a few URLs (for example the home and login pages).
pages). In this case it is easiest to define access configuration attributes for these In this case it is easiest to define access configuration attributes for these specific
specific URLs rather than have for every secured resource. Put differently, sometimes it URLs rather than have for every secured resource. Put differently, sometimes it is nice
is nice to say <literal>ROLE_SOMETHING</literal> is required by default and only allow to say <literal>ROLE_SOMETHING</literal> is required by default and only allow certain
certain exceptions to this rule, such as for login, logout and home pages of an exceptions to this rule, such as for login, logout and home pages of an application. You
application. You could also omit these pages from the filter chain entirely, thus could also omit these pages from the filter chain entirely, thus bypassing the access
bypassing the access control checks, but this may be undesirable for other reasons, control checks, but this may be undesirable for other reasons, particularly if the pages
particularly if the pages behave differently for authenticated users.</para> behave differently for authenticated users.</para>
<para>This is what we mean by anonymous authentication. Note that there is no real <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 conceptual difference between a user who is <quote>anonymously authenticated</quote> and
an unauthenticated user. Spring Security's anonymous authentication just gives you a 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 more convenient way to configure your access-control attributes. Calls to servlet API
calls such as <methodname>getCallerPrincipal</methodname>, for example, will still calls such as <methodname>getCallerPrincipal</methodname>, for example, will still
return null even though there is actually an anonymous authentication object in the 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 <para>There are other situations where anonymous authentication is useful, such as when an
auditing interceptor queries the <classname>SecurityContextHolder</classname> to auditing interceptor queries the <classname>SecurityContextHolder</classname> to
identify which principal was responsible for a given operation. Classes can be authored identify which principal was responsible for a given operation. Classes can be authored
more robustly if they know the <classname>SecurityContextHolder</classname> always more robustly if they know the <classname>SecurityContextHolder</classname> always
contains an <interfacename>Authentication</interfacename> object, and never contains an <interfacename>Authentication</interfacename> object, and never
<literal>null</literal>.</para> <literal>null</literal>.</para>
</section> </section>
<section xml:id="anonymous-config"> <section xml:id="anonymous-config">
<info> <info>
@ -39,23 +39,22 @@
</info> </info>
<para>Anonymous authentication support is provided automatically when using the HTTP <para>Anonymous authentication support is provided automatically when using the HTTP
configuration Spring Security 3.0 and can be customized (or disabled) using the 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> described here unless you are using traditional bean configuration.</para>
<para>Three classes that together provide the anonymous authentication feature. <para>Three classes that together provide the anonymous authentication feature.
<literal>AnonymousAuthenticationToken</literal> is an implementation of <literal>AnonymousAuthenticationToken</literal> is an implementation of
<interfacename>Authentication</interfacename>, and stores the <interfacename>Authentication</interfacename>, and stores the
<interfacename>GrantedAuthority</interfacename>s which apply to the anonymous <interfacename>GrantedAuthority</interfacename>s which apply to the anonymous principal.
principal. There is a corresponding <literal>AnonymousAuthenticationProvider</literal>, There is a corresponding <literal>AnonymousAuthenticationProvider</literal>, which is
which is chained into the <literal>ProviderManager</literal> so that chained into the <literal>ProviderManager</literal> so that
<literal>AnonymousAuthenticationToken</literal>s are accepted. Finally, there is an <literal>AnonymousAuthenticationToken</literal>s are accepted. Finally, there is an
<classname>AnonymousAuthenticationFilter</classname>, which is chained after the <classname>AnonymousAuthenticationFilter</classname>, which is chained after the normal
normal authentication mechanisms and automatically adds an authentication mechanisms and automatically adds an
<literal>AnonymousAuthenticationToken</literal> to the <literal>AnonymousAuthenticationToken</literal> to the
<classname>SecurityContextHolder</classname> if there is no existing <classname>SecurityContextHolder</classname> if there is no existing
<interfacename>Authentication</interfacename> held there. The definition of the <interfacename>Authentication</interfacename> held there. The definition of the filter
filter and authentication provider appears as follows:</para> and authentication provider appears as follows:</para>
<para> <para> <programlisting>
<programlisting>
<![CDATA[ <![CDATA[
<bean id="anonymousAuthFilter" <bean id="anonymousAuthFilter"
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter"> class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
@ -67,32 +66,30 @@
class="org.springframework.security.authentication.AnonymousAuthenticationProvider"> class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/> <property name="key" value="foobar"/>
</bean>]]> </bean>]]>
</programlisting> </programlisting> </para>
</para>
<para>The <literal>key</literal> is shared between the filter and authentication provider, <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 so that tokens created by the former are accepted by the latter<footnote>
of the <literal>key</literal> property should not be regarded as providing any <para>The use of the <literal>key</literal> property should not be regarded as providing
real security here. It is merely a book-keeping exercise. If you are sharing a any real security here. It is merely a book-keeping exercise. If you are sharing a
<classname>ProviderManager</classname> which contains an <classname>ProviderManager</classname> which contains an
<classname>AnonymousAuthenticationProvider</classname> in a scenario where <classname>AnonymousAuthenticationProvider</classname> in a scenario where it is
it is possible for an authenticating client to construct the possible for an authenticating client to construct the
<interfacename>Authentication</interfacename> object (such as with RMI <interfacename>Authentication</interfacename> object (such as with RMI invocations),
invocations), then a malicious client could submit an then a malicious client could submit an
<classname>AnonymousAuthenticationToken</classname> which it had created <classname>AnonymousAuthenticationToken</classname> which it had created itself
itself (with chosen username and authority list). If the <literal>key</literal> (with chosen username and authority list). If the <literal>key</literal> is
is guessable or can be found out, then the token would be accepted by the guessable or can be found out, then the token would be accepted by the anonymous
anonymous provider. This isn't a problem with normal usage but if you are using provider. This isn't a problem with normal usage but if you are using RMI you would
RMI you would be best to use a customized <classname>ProviderManager</classname> be best to use a customized <classname>ProviderManager</classname> which omits the
which omits the anonymous provider rather than sharing the one you use for your anonymous provider rather than sharing the one you use for your HTTP authentication
HTTP authentication mechanisms.</para></footnote>. The mechanisms.</para>
<literal>userAttribute</literal> is expressed in the form of </footnote>. The <literal>userAttribute</literal> is expressed in the form of
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>. <literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
This is the same syntax as used after the equals sign for 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 <para>As explained earlier, the benefit of anonymous authentication is that all URI patterns
can have security applied to them. For example:</para> can have security applied to them. For example:</para>
<para> <para> <programlisting>
<programlisting>
<![CDATA[ <![CDATA[
<bean id="filterSecurityInterceptor" <bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
@ -108,19 +105,18 @@
</security:filter-security-metadata-source>" + </security:filter-security-metadata-source>" +
</property> </property>
</bean>]]> </bean>]]>
</programlisting> </programlisting> </para>
</para>
</section> </section>
<section xml:id="anonymous-auth-trust-resolver"> <section xml:id="anonymous-auth-trust-resolver">
<title><interfacename>AuthenticationTrustResolver</interfacename></title> <title><interfacename>AuthenticationTrustResolver</interfacename></title>
<para> Rounding out the anonymous authentication discussion is the <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 corresponding <literal>AuthenticationTrustResolverImpl</literal> implementation. This
interface provides an <literal>isAnonymous(Authentication)</literal> method, which interface provides an <literal>isAnonymous(Authentication)</literal> method, which
allows interested classes to take into account this special type of authentication allows interested classes to take into account this special type of authentication
status. The <classname>ExceptionTranslationFilter</classname> uses this interface in status. The <classname>ExceptionTranslationFilter</classname> uses this interface in
processing <literal>AccessDeniedException</literal>s. If an 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 anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead
commence the <interfacename>AuthenticationEntryPoint</interfacename> so the principal commence the <interfacename>AuthenticationEntryPoint</interfacename> so the principal
can authenticate properly. This is a necessary distinction, otherwise principals would can authenticate properly. This is a necessary distinction, otherwise principals would
@ -130,13 +126,13 @@
interceptor configuration replaced with <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>, interceptor configuration replaced with <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>,
which is effectively the same thing when defining access controls. This is an example of 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 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 xlink:href="#authz-authenticated-voter">authorization chapter</link>. It uses an
<interfacename>AuthenticationTrustResolver</interfacename> to process this <interfacename>AuthenticationTrustResolver</interfacename> to process this particular
particular configuration attribute and grant access to anonymous users. The configuration attribute and grant access to anonymous users. The
<classname>AuthenticatedVoter</classname> approach is more powerful, since it allows <classname>AuthenticatedVoter</classname> approach is more powerful, since it allows you
you to differentiate between anonymous, remember-me and fully-authenticated users. If to differentiate between anonymous, remember-me and fully-authenticated users. If you
you don't need this functionality though, then you can stick with don't need this functionality though, then you can stick with
<literal>ROLE_ANONYMOUS</literal>, which will be processed by Spring Security's <literal>ROLE_ANONYMOUS</literal>, which will be processed by Spring Security's standard
standard <classname>RoleVoter</classname>. </para> <classname>RoleVoter</classname>. </para>
</section> </section>
</chapter> </chapter>

View File

@ -1,20 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<appendix version="5.0" xml:id="appendix-schema" xmlns="http://docbook.org/ns/docbook" <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"> xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<info> <info>
<title>Security Database Schema</title> <title>Security Database Schema</title>
</info> </info>
<para> There are various database schema used by the framework and this appendix provides a single <para> There are various database schema used by the framework and this appendix provides a
reference point to them all. You only need to provide the tables for the areas of functonality single reference point to them all. You only need to provide the tables for the areas of
you require. </para> functonality you require. </para>
<para> DDL statements are given for the HSQLDB database. You can use these as a guideline for <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> defining the schema for the database you are using. </para>
<section> <section>
<title>User Schema</title> <title>User Schema</title>
<para> The standard JDBC implementation of the <interfacename>UserDetailsService</interfacename> <para> The standard JDBC implementation of the
(<classname>JdbcDaoImpl</classname>) requires tables to load the password, account status <interfacename>UserDetailsService</interfacename> (<classname>JdbcDaoImpl</classname>)
(enabled or disabled) and a list of authorities (roles) for the user. requires tables to load the password, account status (enabled or disabled) and a list of
<programlisting xml:id="db_schema_users_authorities"> authorities (roles) for the user.
<programlisting xml:id="db_schema_users_authorities">
create table users( create table users(
username varchar_ignorecase(50) not null primary key, username varchar_ignorecase(50) not null primary key,
password varchar_ignorecase(50) not null, password varchar_ignorecase(50) not null,
@ -26,11 +27,11 @@
constraint fk_authorities_users foreign key(username) references users(username)); constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority); create unique index ix_auth_username on authorities (username,authority);
</programlisting></para> </programlisting></para>
<section> <section>
<title>Group Authorities</title> <title>Group Authorities</title>
<para> Spring Security 2.0 introduced support for group authorities in <para> Spring Security 2.0 introduced support for group authorities in
<classname>JdbcDaoImpl</classname>. The table structure if groups are enabled is as <classname>JdbcDaoImpl</classname>. The table structure if groups are enabled is as
follows:<programlisting xml:id="db-schema-groups"> follows:<programlisting xml:id="db-schema-groups">
create table groups ( create table groups (
id bigint generated by default as identity(start with 0) primary key, id bigint generated by default as identity(start with 0) primary key,
group_name varchar_ignorecase(50) not null); group_name varchar_ignorecase(50) not null);
@ -46,55 +47,57 @@ create table group_members (
group_id bigint not null, group_id bigint not null,
constraint fk_group_members_group foreign key(group_id) references groups(id)); constraint fk_group_members_group foreign key(group_id) references groups(id));
</programlisting></para> </programlisting></para>
</section>
</section> </section>
</section> <section>
<section> <title>Persistent Login (Remember-Me) Schema</title>
<title>Persistent Login (Remember-Me) Schema</title> <para> This table is used to store data used by the more secure <link
<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
xlink:href="#remember-me-persistent-token">persistent token</link> remember-me implementation. If you are using <classname>JdbcTokenRepositoryImpl</classname> either
implementation. If you are using <classname>JdbcTokenRepositoryImpl</classname> either directly or through the namespace, then you will need this table.
directly or through the namespace, then you will need this table. <programlisting xml:id="db-schema-remeber-me">
<programlisting xml:id="db-schema-remeber-me">
create table persistent_logins ( create table persistent_logins (
username varchar(64) not null, username varchar(64) not null,
series varchar(64) primary key, series varchar(64) primary key,
token varchar(64) not null, token varchar(64) not null,
last_used timestamp not null); last_used timestamp not null);
</programlisting></para> </programlisting></para>
</section> </section>
<section xml:id="dbschema-acl"> <section xml:id="dbschema-acl">
<title>ACL Schema</title> <title>ACL Schema</title>
<para>There are four tables used by the Spring Security <link xlink:href="#domain-acls" <para>There are four tables used by the Spring Security <link xlink:href="#domain-acls"
>ACL</link> implementation. <orderedlist> >ACL</link> implementation. <orderedlist>
<listitem> <listitem>
<para><literal>acl_sid</literal> stores the security identities recognised by the ACL <para><literal>acl_sid</literal> stores the security identities recognised by the
system. These can be unique principals or authorities which may apply to multiple ACL system. These can be unique principals or authorities which may apply to
principals.</para> multiple principals.</para>
</listitem> </listitem>
<listitem> <listitem>
<para><literal>acl_class</literal> defines the domain object types to which ACLs apply. <para><literal>acl_class</literal> defines the domain object types to which ACLs
The <literal>class</literal> column stores the Java class name of the object. </para> apply. The <literal>class</literal> column stores the Java class name of the
</listitem> object. </para>
<listitem> </listitem>
<para><literal>acl_object_identity</literal> stores the object identity definitions of <listitem>
specific domai objects.</para> <para><literal>acl_object_identity</literal> stores the object identity definitions
</listitem> of specific domai objects.</para>
<listitem> </listitem>
<para><literal>acl_entry</literal> stores the ACL permissions which apply to a specific <listitem>
object identity and security identity.</para> <para><literal>acl_entry</literal> stores the ACL permissions which apply to a
</listitem> specific object identity and security identity.</para>
</orderedlist></para> </listitem>
<para>It is assumed that the database will auto-generate the primary keys for each of the </orderedlist></para>
identities. The <literal>JdbcMutableAclService</literal> has to be able to retrieve these when <para>It is assumed that the database will auto-generate the primary keys for each of the
it has created a new row in the <literal>acl_sid</literal> or <literal>acl_class</literal> identities. The <literal>JdbcMutableAclService</literal> has to be able to retrieve
tables. It has two properties which define the SQL needed to retrieve these values these when it has created a new row in the <literal>acl_sid</literal> or
<literal>classIdentityQuery</literal> and <literal>sidIdentityQuery</literal>. Both of these <literal>acl_class</literal> tables. It has two properties which define the SQL needed
default to <literal>call identity()</literal></para> to retrieve these values <literal>classIdentityQuery</literal> and
<section> <literal>sidIdentityQuery</literal>. Both of these default to <literal>call
<title>Hypersonic SQL</title> identity()</literal></para>
<para>The default schema works with the embedded HSQLDB database that is used in unit tests <section>
within the <title>Hypersonic SQL</title>
framework.<programlisting xml:id="dbschema-acl-hsql"> <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 ( create table acl_sid (
id bigint generated by default as identity(start with 100) not null primary key, id bigint generated by default as identity(start with 100) not null primary key,
principal boolean not null, principal boolean not null,
@ -129,10 +132,10 @@ create table acl_entry (
constraint foreign_fk_5 foreign key(sid) references acl_sid(id) ); constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );
</programlisting></para> </programlisting></para>
<section> <section>
<title>PostgreSQL</title> <title>PostgreSQL</title>
<para> <para>
<programlisting>create table acl_sid( <programlisting>create table acl_sid(
id bigserial not null primary key, id bigserial not null primary key,
principal boolean not null, principal boolean not null,
sid varchar(100) not null, sid varchar(100) not null,
@ -168,21 +171,21 @@ create table acl_entry(
constraint foreign_fk_4 foreign key(acl_object_identity) constraint foreign_fk_4 foreign key(acl_object_identity)
references acl_object_identity(id), references acl_object_identity(id),
constraint foreign_fk_5 foreign key(sid) references acl_sid(id)); constraint foreign_fk_5 foreign key(sid) references acl_sid(id));
</programlisting> </programlisting> </para>
</para> <para>You will have to set the <literal>classIdentityQuery</literal> and
<para>You will have to set the <literal>classIdentityQuery</literal> and <literal>sidIdentityQuery</literal> properties of
<literal>sidIdentityQuery</literal> properties of <classname>JdbcMutableAclService</classname> to the following values,
<classname>JdbcMutableAclService</classname> to the following values, respectively: <itemizedlist> respectively: <itemizedlist>
<listitem> <listitem>
<para><literal>select currval(pg_get_serial_sequence('acl_class', <para><literal>select currval(pg_get_serial_sequence('acl_class',
'id'))</literal></para> 'id'))</literal></para>
</listitem> </listitem>
<listitem> <listitem>
<para><literal>select currval(pg_get_serial_sequence('acl_sid', <para><literal>select currval(pg_get_serial_sequence('acl_sid',
'id'))</literal></para> 'id'))</literal></para>
</listitem> </listitem>
</itemizedlist></para> </itemizedlist></para>
</section> </section>
</section>
</section> </section>
</section>
</appendix> </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" <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authz-arch"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Authorization Architecture</title>
</info>
<section xml:id="authz-authorities">
<info> <info>
<title>Authorities</title> <title>Authorization Architecture</title>
</info> </info>
<para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>, all <section xml:id="authz-authorities">
<interfacename>Authentication</interfacename> implementations store a list of <info>
<interfacename>GrantedAuthority</interfacename> objects. These represent the authorities <title>Authorities</title>
that have been granted to the principal. The <interfacename>GrantedAuthority</interfacename> </info>
objects are inserted into the <interfacename>Authentication</interfacename> object by the <para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>,
<interfacename>AuthenticationManager</interfacename> and are later read by all <interfacename>Authentication</interfacename> implementations store a list of
<interfacename>AccessDecisionManager</interfacename>s when making authorization <interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
decisions.</para> that have been granted to the principal. The
<para><interfacename>GrantedAuthority</interfacename> is an interface with only one method: <interfacename>GrantedAuthority</interfacename> objects are inserted into the
<programlisting> <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(); String getAuthority();
</programlisting> This method allows </programlisting> This method allows
<interfacename>AccessDecisionManager</interfacename>s to obtain a precise <interfacename>AccessDecisionManager</interfacename>s to obtain a precise
<literal>String</literal> representation of the <literal>String</literal> representation of the
<interfacename>GrantedAuthority</interfacename>. By returning a representation as a <interfacename>GrantedAuthority</interfacename>. By returning a representation as a
<literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be easily <literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be
<quote>read</quote> by most <interfacename>AccessDecisionManager</interfacename>s. If a easily <quote>read</quote> by most
<interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a <interfacename>AccessDecisionManager</interfacename>s. If a
<literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is considered <interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
<quote>complex</quote> and <literal>getAuthority()</literal> must return <literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is
<literal>null</literal>.</para> considered <quote>complex</quote> and <literal>getAuthority()</literal> must return
<para>An example of a <quote>complex</quote> <literal>null</literal>.</para>
<interfacename>GrantedAuthority</interfacename> would be an implementation that stores a list <para>An example of a <quote>complex</quote> <interfacename>GrantedAuthority</interfacename>
of operations and authority thresholds that apply to different customer account numbers. would be an implementation that stores a list of operations and authority thresholds
Representing this complex <interfacename>GrantedAuthority</interfacename> as a that apply to different customer account numbers. Representing this complex
<literal>String</literal> would be quite difficult, and as a result the <interfacename>GrantedAuthority</interfacename> as a <literal>String</literal> would be
<literal>getAuthority()</literal> method should return <literal>null</literal>. This will quite difficult, and as a result the <literal>getAuthority()</literal> method should
indicate to any <interfacename>AccessDecisionManager</interfacename> that it will need to return <literal>null</literal>. This will indicate to any
specifically support the <interfacename>GrantedAuthority</interfacename> implementation in <interfacename>AccessDecisionManager</interfacename> that it will need to specifically
order to understand its contents.</para> support the <interfacename>GrantedAuthority</interfacename> implementation in order to
<para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename> understand its contents.</para>
implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified <para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
<literal>String</literal> to be converted into a implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified
<interfacename>GrantedAuthority</interfacename>. All <literal>String</literal> to be converted into a
<classname>AuthenticationProvider</classname>s included with the security architecture use <interfacename>GrantedAuthority</interfacename>. All
<literal>GrantedAuthorityImpl</literal> to populate the <classname>AuthenticationProvider</classname>s included with the security architecture
<interfacename>Authentication</interfacename> object.</para> use <literal>GrantedAuthorityImpl</literal> to populate the
</section> <interfacename>Authentication</interfacename> object.</para>
<section xml:id="authz-pre-invocation"> </section>
<info> <section xml:id="authz-pre-invocation">
<title>Pre-Invocation Handling</title> <info>
</info> <title>Pre-Invocation Handling</title>
<para> As we've also seen in the <link xlink:href="#secure-objects">Technical Overview</link> </info>
chapter, Spring Security provides interceptors which control access to secure objects such as <para> As we've also seen in the <link xlink:href="#secure-objects">Technical
method invocations or web requests. A pre-invocation decision on whether the invocation is Overview</link> chapter, Spring Security provides interceptors which control access to
allowed to proceed is made by the <interfacename>AccessDecisionManager</interfacename>. </para> secure objects such as method invocations or web requests. A pre-invocation decision on
<section xml:id="authz-access-decision-manager"> whether the invocation is allowed to proceed is made by the
<title>The AccessDecisionManager</title> <interfacename>AccessDecisionManager</interfacename>. </para>
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the <section xml:id="authz-access-decision-manager">
<classname>AbstractSecurityInterceptor</classname> and is responsible for making final <title>The AccessDecisionManager</title>
access control decisions. The <interfacename>AccessDecisionManager</interfacename> interface <para>The <interfacename>AccessDecisionManager</interfacename> is called by the
contains three methods: <classname>AbstractSecurityInterceptor</classname> and is responsible for making
<programlisting> final access control decisions. The
<interfacename>AccessDecisionManager</interfacename> interface contains three
methods:
<programlisting>
void decide(Authentication authentication, Object secureObject, void decide(Authentication authentication, Object secureObject,
List&lt;ConfigAttribute&gt; config) throws AccessDeniedException; List&lt;ConfigAttribute&gt; config) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute); boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz); boolean supports(Class clazz);
</programlisting> </programlisting>
The <interfacename>AccessDecisionManager</interfacename>'s <methodname>decide</methodname> The <interfacename>AccessDecisionManager</interfacename>'s
method is passed all the relevant information it needs in order to make an authorization <methodname>decide</methodname> method is passed all the relevant information it
decision. In particular, passing the secure <literal>Object</literal> enables those needs in order to make an authorization decision. In particular, passing the secure
arguments contained in the actual secure object invocation to be inspected. For example, <literal>Object</literal> enables those arguments contained in the actual secure
let's assume the secure object was a <classname>MethodInvocation</classname>. It would be object invocation to be inspected. For example, let's assume the secure object was a
easy to query the <classname>MethodInvocation</classname> for any <classname>MethodInvocation</classname>. It would be easy to query the
<literal>Customer</literal> argument, and then implement some sort of security logic in <classname>MethodInvocation</classname> for any <literal>Customer</literal>
the <interfacename>AccessDecisionManager</interfacename> to ensure the principal is argument, and then implement some sort of security logic in the
permitted to operate on that customer. Implementations are expected to throw an <interfacename>AccessDecisionManager</interfacename> to ensure the principal is
<literal>AccessDeniedException</literal> if access is denied.</para> permitted to operate on that customer. Implementations are expected to throw an
<para>The <literal>supports(ConfigAttribute)</literal> method is called by the <literal>AccessDeniedException</literal> if access is denied.</para>
<classname>AbstractSecurityInterceptor</classname> at startup time to determine if the <para>The <literal>supports(ConfigAttribute)</literal> method is called by the
<interfacename>AccessDecisionManager</interfacename> can process the passed <classname>AbstractSecurityInterceptor</classname> at startup time to determine if
<literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is the <interfacename>AccessDecisionManager</interfacename> can process the passed
called by a security interceptor implementation to ensure the configured <literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
<interfacename>AccessDecisionManager</interfacename> supports the type of secure object called by a security interceptor implementation to ensure the configured
that the security interceptor will present.</para> <interfacename>AccessDecisionManager</interfacename> supports the type of secure
</section> object that the security interceptor will present.</para>
<section xml:id="authz-voting-based"> </section>
<title>Voting-Based AccessDecisionManager Implementations</title> <section xml:id="authz-voting-based">
<para>Whilst users can implement their own <title>Voting-Based AccessDecisionManager Implementations</title>
<interfacename>AccessDecisionManager</interfacename> to control all aspects of <para>Whilst users can implement their own
authorization, Spring Security includes several <interfacename>AccessDecisionManager</interfacename> to control all aspects of
<interfacename>AccessDecisionManager</interfacename> implementations that are based on authorization, Spring Security includes several
voting. <xref linkend="authz-access-voting"/> illustrates the relevant classes.</para> <interfacename>AccessDecisionManager</interfacename> implementations that are based
<figure xml:id="authz-access-voting"> on voting. <xref linkend="authz-access-voting"/> illustrates the relevant
<title>Voting Decision Manager</title> classes.</para>
<mediaobject> <figure xml:id="authz-access-voting">
<imageobject> <title>Voting Decision Manager</title>
<imagedata align="center" fileref="images/access-decision-voting.png" <mediaobject>
format="PNG" scale="75"/> <imageobject>
</imageobject> <imagedata align="center" fileref="images/access-decision-voting.png"
</mediaobject> format="PNG" scale="75"/>
</figure> </imageobject>
<para>Using this approach, a series of <interfacename>AccessDecisionVoter</interfacename> </mediaobject>
implementations are polled on an authorization decision. The </figure>
<interfacename>AccessDecisionManager</interfacename> then decides whether or not to throw <para>Using this approach, a series of
an <literal>AccessDeniedException</literal> based on its assessment of the votes.</para> <interfacename>AccessDecisionVoter</interfacename> implementations are polled on an
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three methods: authorization decision. The <interfacename>AccessDecisionManager</interfacename>
<programlisting> 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); int vote(Authentication authentication, Object object, List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute); boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz); boolean supports(Class clazz);
</programlisting> </programlisting>
Concrete implementations return an <literal>int</literal>, with possible values being Concrete implementations return an <literal>int</literal>, with possible values
reflected in the <interfacename>AccessDecisionVoter</interfacename> static fields being reflected in the <interfacename>AccessDecisionVoter</interfacename> static
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and fields <literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
<literal>ACCESS_GRANTED</literal>. A voting implementation will return <literal>ACCESS_GRANTED</literal>. A voting implementation will return
<literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision. If it <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision.
does have an opinion, it must return either <literal>ACCESS_DENIED</literal> or If it does have an opinion, it must return either <literal>ACCESS_DENIED</literal>
<literal>ACCESS_GRANTED</literal>.</para> or <literal>ACCESS_GRANTED</literal>.</para>
<para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s provided <para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s
with Spring Security that tally the votes. The <literal>ConsensusBased</literal> provided with Spring Security that tally the votes. The
implementation will grant or deny access based on the consensus of non-abstain votes. <literal>ConsensusBased</literal> implementation will grant or deny access based on
Properties are provided to control behavior in the event of an equality of votes or if all the consensus of non-abstain votes. Properties are provided to control behavior in
votes are abstain. The <literal>AffirmativeBased</literal> implementation will grant access the event of an equality of votes or if all votes are abstain. The
if one or more <literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny vote will <literal>AffirmativeBased</literal> implementation will grant access if one or more
be ignored, provided there was at least one grant vote). Like the <literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny vote will be
<literal>ConsensusBased</literal> implementation, there is a parameter that controls the ignored, provided there was at least one grant vote). Like the
behavior if all voters abstain. The <literal>UnanimousBased</literal> provider expects <literal>ConsensusBased</literal> implementation, there is a parameter that controls
unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access, ignoring the behavior if all voters abstain. The <literal>UnanimousBased</literal> provider
abstains. It will deny access if there is any <literal>ACCESS_DENIED</literal> vote. Like expects unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access,
the other implementations, there is a parameter that controls the behaviour if all voters ignoring abstains. It will deny access if there is any
abstain.</para> <literal>ACCESS_DENIED</literal> vote. Like the other implementations, there is a
<para>It is possible to implement a custom parameter that controls the behaviour if all voters abstain.</para>
<interfacename>AccessDecisionManager</interfacename> that tallies votes differently. For <para>It is possible to implement a custom
example, votes from a particular <interfacename>AccessDecisionVoter</interfacename> might <interfacename>AccessDecisionManager</interfacename> that tallies votes differently.
receive additional weighting, whilst a deny vote from a particular voter may have a veto For example, votes from a particular
effect.</para> <interfacename>AccessDecisionVoter</interfacename> might receive additional
<section xml:id="authz-role-voter"> weighting, whilst a deny vote from a particular voter may have a veto effect.</para>
<title><classname>RoleVoter</classname></title> <section xml:id="authz-role-voter">
<para> The most commonly used <interfacename>AccessDecisionVoter</interfacename> provided <title><classname>RoleVoter</classname></title>
with Spring Security is the simple <classname>RoleVoter</classname>, which treats <para> The most commonly used <interfacename>AccessDecisionVoter</interfacename>
configuration attributes as simple role names and votes to grant access if the user has provided with Spring Security is the simple <classname>RoleVoter</classname>,
been assigned that role.</para> which treats configuration attributes as simple role names and votes to grant
<para>It will vote if any <interfacename>ConfigAttribute</interfacename> begins with the access if the user has been assigned that role.</para>
prefix <literal>ROLE_</literal>. It will vote to grant access if there is a <para>It will vote if any <interfacename>ConfigAttribute</interfacename> begins with
<interfacename>GrantedAuthority</interfacename> which returns a the prefix <literal>ROLE_</literal>. It will vote to grant access if there is a
<literal>String</literal> representation (via the <literal>getAuthority()</literal> <interfacename>GrantedAuthority</interfacename> which returns a
method) exactly equal to one or more <literal>ConfigAttributes</literal> starting with the <literal>String</literal> representation (via the
prefix <literal>ROLE_</literal>. If there is no exact match of any <literal>getAuthority()</literal> method) exactly equal to one or more
<literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the <literal>ConfigAttributes</literal> starting with the prefix
<literal>RoleVoter</literal> will vote to deny access. If no <literal>ROLE_</literal>. If there is no exact match of any
<literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the voter will <literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
abstain.</para> <literal>RoleVoter</literal> will vote to deny access. If no
</section> <literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the
<section xml:id="authz-authenticated-voter"> voter will abstain.</para>
<title><classname>AuthenticatedVoter</classname></title> </section>
<para> Another voter which we've implicitly seen is the <section xml:id="authz-authenticated-voter">
<classname>AuthenticatedVoter</classname>, which can be used to differentiate between <title><classname>AuthenticatedVoter</classname></title>
anonymous, fully-authenticated and remember-me authenticated users. Many sites allow <para> Another voter which we've implicitly seen is the
certain limited access under remember-me authentication, but require a user to confirm <classname>AuthenticatedVoter</classname>, which can be used to differentiate
their identity by logging in for full access.</para> between anonymous, fully-authenticated and remember-me authenticated users. Many
<para>When we've used the attribute <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal> to grant sites allow certain limited access under remember-me authentication, but require
anonymous access, this attribute was being processed by the a user to confirm their identity by logging in for full access.</para>
<classname>AuthenticatedVoter</classname>. See the Javadoc for this class for more <para>When we've used the attribute <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>
information. </para> to grant anonymous access, this attribute was being processed by the
</section> <classname>AuthenticatedVoter</classname>. See the Javadoc for this class for
<section> more information. </para>
<title>Custom Voters</title> </section>
<para>It is also possible to implement a custom <section>
<interfacename>AccessDecisionVoter</interfacename>. Several examples are provided in <title>Custom Voters</title>
Spring Security unit tests, including <literal>ContactSecurityVoter</literal> and <para>It is also possible to implement a custom
<literal>DenyVoter</literal>. The <literal>ContactSecurityVoter</literal> abstains from <interfacename>AccessDecisionVoter</interfacename>. Several examples are
voting decisions where a <literal>CONTACT_OWNED_BY_CURRENT_USER</literal> provided in Spring Security unit tests, including
<literal>ConfigAttribute</literal> is not found. If voting, it queries the <literal>ContactSecurityVoter</literal> and <literal>DenyVoter</literal>. The
<classname>MethodInvocation</classname> to extract the owner of the <literal>ContactSecurityVoter</literal> abstains from voting decisions where a
<literal>Contact</literal> object that is subject of the method call. It votes to grant <literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
access if the <literal>Contact</literal> owner matches the principal presented in the <literal>ConfigAttribute</literal> is not found. If voting, it queries the
<interfacename>Authentication</interfacename> object. It could have just as easily <classname>MethodInvocation</classname> to extract the owner of the
compared the <literal>Contact</literal> owner with some <literal>Contact</literal> object that is subject of the method call. It votes
<interfacename>GrantedAuthority</interfacename> the to grant access if the <literal>Contact</literal> owner matches the principal
<interfacename>Authentication</interfacename> object presented. All of this is achieved presented in the <interfacename>Authentication</interfacename> object. It could
with relatively few lines of code and demonstrates the flexibility of the authorization have just as easily compared the <literal>Contact</literal> owner with some
model.</para> <interfacename>GrantedAuthority</interfacename> the
</section> <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> <section xml:id="authz-after-invocation-handling">
<section xml:id="authz-after-invocation-handling"> <info>
<info> <title>After Invocation Handling</title>
<title>After Invocation Handling</title> </info>
</info> <para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
<para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the <classname>AbstractSecurityInterceptor</classname> before proceeding with the secure
<classname>AbstractSecurityInterceptor</classname> before proceeding with the secure object object invocation, some applications need a way of modifying the object actually
invocation, some applications need a way of modifying the object actually returned by the returned by the secure object invocation. Whilst you could easily implement your own AOP
secure object invocation. Whilst you could easily implement your own AOP concern to achieve concern to achieve this, Spring Security provides a convenient hook that has several
this, Spring Security provides a convenient hook that has several concrete implementations concrete implementations that integrate with its ACL capabilities.</para>
that integrate with its ACL capabilities.</para> <para><xref linkend="authz-after-invocation"/> illustrates Spring Security's
<para><xref linkend="authz-after-invocation"/> illustrates Spring Security's <literal>AfterInvocationManager</literal> and its concrete implementations. <figure
<literal>AfterInvocationManager</literal> and its concrete implementations. <figure xml:id="authz-after-invocation">
xml:id="authz-after-invocation"> <title>After Invocation Implementation</title>
<title>After Invocation Implementation</title> <mediaobject>
<mediaobject> <imageobject>
<imageobject> <imagedata align="center" fileref="images/after-invocation.png" format="PNG"
<imagedata align="center" fileref="images/after-invocation.png" format="PNG" scale="75"/> scale="75"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</figure></para> </figure></para>
<para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal> has a <para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal>
single concrete implementation, <literal>AfterInvocationProviderManager</literal>, which polls has a single concrete implementation, <literal>AfterInvocationProviderManager</literal>,
a list of <literal>AfterInvocationProvider</literal>s. Each which polls a list of <literal>AfterInvocationProvider</literal>s. Each
<literal>AfterInvocationProvider</literal> is allowed to modify the return object or throw <literal>AfterInvocationProvider</literal> is allowed to modify the return object or
an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify the object, throw an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify
as the result of the previous provider is passed to the next in the list.</para> the object, as the result of the previous provider is passed to the next in the
<para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you will list.</para>
still need configuration attributes that allow the <para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you
<classname>MethodSecurityInterceptor</classname>'s will still need configuration attributes that allow the
<interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're using <classname>MethodSecurityInterceptor</classname>'s
the typical Spring Security included <interfacename>AccessDecisionManager</interfacename> <interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're
implementations, having no configuration attributes defined for a particular secure method using the typical Spring Security included
invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to abstain from <interfacename>AccessDecisionManager</interfacename> implementations, having no
voting. In turn, if the <interfacename>AccessDecisionManager</interfacename> property configuration attributes defined for a particular secure method invocation will cause
"<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an each <interfacename>AccessDecisionVoter</interfacename> to abstain from voting. In turn,
<literal>AccessDeniedException</literal> will be thrown. You may avoid this potential issue if the <interfacename>AccessDecisionManager</interfacename> property
by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to "<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
<literal>true</literal> (although this is generally not recommended) or (ii) simply ensure <literal>AccessDeniedException</literal> will be thrown. You may avoid this potential
that there is at least one configuration attribute that an issue by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
<interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This <literal>true</literal> (although this is generally not recommended) or (ii) simply
latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal> or ensure that there is at least one configuration attribute that an
<literal>ROLE_AUTHENTICATED</literal> configuration attribute.</para> <interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
<!-- TODO: Move to ACL section and add reference here --> 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"> <section xml:id="after-invocation-acl-aware">
<info> <info>
<title>ACL-Aware AfterInvocationProviders</title> <title>ACL-Aware AfterInvocationProviders</title>
@ -285,8 +299,8 @@ boolean supports(Class clazz);
<para>The Contacts sample application demonstrates these two <para>The Contacts sample application demonstrates these two
<literal>AfterInvocationProvider</literal>s.</para> <literal>AfterInvocationProvider</literal>s.</para>
</section> --> </section> -->
</section> </section>
<!-- TODO: Move taglibs to a separate chapter which describes them all <!-- TODO: Move taglibs to a separate chapter which describes them all
<section xml:id="authorization-taglibs"> <section xml:id="authorization-taglibs">
<info> <info>
<title>Authorization Tag Libraries</title> <title>Authorization Tag Libraries</title>

View File

@ -18,7 +18,7 @@
authenticating calls made by Spring remoting protocols (such as Hessian and Burlap), as 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 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 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 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 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> encoding of the username:password, specified in an HTTP header).</para>
@ -27,11 +27,10 @@
<title>Configuration</title> <title>Configuration</title>
</info> </info>
<para>To implement HTTP Basic Authentication, you need to add a <para>To implement HTTP Basic Authentication, you need to add a
<literal>BasicAuthenticationFilter</literal> to your filter chain. The <literal>BasicAuthenticationFilter</literal> to your filter chain. The application
application context should contain <literal>BasicAuthenticationFilter</literal> and context should contain <literal>BasicAuthenticationFilter</literal> and its required
its required collaborator:</para> collaborator:</para>
<para> <para> <programlisting language="xml"><![CDATA[
<programlisting language="xml"><![CDATA[
<bean id="basicAuthenticationFilter" <bean id="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"> class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationManager" ref="authenticationManager"/>
@ -42,21 +41,20 @@
class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint"> class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="Name Of Your Realm"/> <property name="realmName" value="Name Of Your Realm"/>
</bean>]]> </bean>]]>
</programlisting> </programlisting> </para>
</para>
<para>The configured <interfacename>AuthenticationManager</interfacename> processes each <para>The configured <interfacename>AuthenticationManager</interfacename> processes each
authentication request. If authentication fails, the configured authentication request. If authentication fails, the configured
<interfacename>AuthenticationEntryPoint</interfacename> will be used to retry <interfacename>AuthenticationEntryPoint</interfacename> will be used to retry the
the authentication process. Usually you will use the filter in combination with a authentication process. Usually you will use the filter in combination with a
<literal>BasicAuthenticationEntryPoint</literal>, which returns a 401 response <literal>BasicAuthenticationEntryPoint</literal>, which returns a 401 response with
with a suitable header to retry HTTP Basic authentication. If authentication is a suitable header to retry HTTP Basic authentication. If authentication is
successful, the resulting <interfacename>Authentication</interfacename> object will successful, the resulting <interfacename>Authentication</interfacename> object will
be placed into the <classname>SecurityContextHolder</classname> as usual.</para> be placed into the <classname>SecurityContextHolder</classname> as usual.</para>
<para>If the authentication event was successful, or authentication was not attempted <para>If the authentication event was successful, or authentication was not attempted
because the HTTP header did not contain a supported authentication request, the 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 filter chain will continue as normal. The only time the filter chain will be
interrupted is if authentication fails and the interrupted is if authentication fails and the
<interfacename>AuthenticationEntryPoint</interfacename> is called.</para> <interfacename>AuthenticationEntryPoint</interfacename> is called.</para>
</section> </section>
</section> </section>
<section xml:id="digest-processing-filter"> <section xml:id="digest-processing-filter">
@ -70,7 +68,7 @@
the Digest Authentication standard prescribed by RFC 2069. Most user agents implement the Digest Authentication standard prescribed by RFC 2069. Most user agents implement
RFC 2617. Spring Security's <classname>DigestAuthenticationFilter</classname> is RFC 2617. Spring Security's <classname>DigestAuthenticationFilter</classname> is
compatible with the "<literal>auth</literal>" quality of protection 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 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 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 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 expirationTime: The date and time when the nonce expires, expressed in milliseconds
key: A private key to prevent modification of the nonce token key: A private key to prevent modification of the nonce token
</programlisting> </programlisting> </para>
</para>
<para>The <classname>DigestAuthenticatonEntryPoint</classname> has a property specifying the <para>The <classname>DigestAuthenticatonEntryPoint</classname> has a property specifying the
<literal>key</literal> used for generating the nonce tokens, along with a <literal>key</literal> used for generating the nonce tokens, along with a
<literal>nonceValiditySeconds</literal> property for determining the expiration time <literal>nonceValiditySeconds</literal> property for determining the expiration time
(default 300, which equals five minutes). Whist ever the nonce is valid, the digest is (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 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 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 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), if the server-generated nonce has merely expired (but the digest was otherwise valid),
the <classname>DigestAuthenticationEntryPoint</classname> will send a the <classname>DigestAuthenticationEntryPoint</classname> will send a
<literal>"stale=true"</literal> header. This tells the user agent there is no need <literal>"stale=true"</literal> header. This tells the user agent there is no need to
to disturb the user (as the password and username etc is correct), but simply to try disturb the user (as the password and username etc is correct), but simply to try again
again using a new nonce.</para> using a new nonce.</para>
<para>An appropriate value for <classname>DigestAuthenticationEntryPoint</classname>'s <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 Extremely secure applications should note that an intercepted authentication header can
be used to impersonate the principal until the <literal>expirationTime</literal> 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 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> running over TLS/HTTPS in the first instance.</para>
<para>Because of the more complex implementation of Digest Authentication, there are often <para>Because of the more complex implementation of Digest Authentication, there are often
user agent issues. For example, Internet Explorer fails to present an 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 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 implementation works reliably with FireFox and Internet Explorer, correctly handling
nonce timeouts etc.</para> nonce timeouts etc.</para>
<section xml:id="digest-config"> <section xml:id="digest-config">
<title>Configuration</title> <title>Configuration</title>
<para>Now that we've reviewed the theory, let's see how to use it. To implement HTTP <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 Digest Authentication, it is necessary to define
<literal>DigestAuthenticationFilter</literal> in the filter chain. The <literal>DigestAuthenticationFilter</literal> in the filter chain. The application
application context will need to define the context will need to define the <literal>DigestAuthenticationFilter</literal> and
<literal>DigestAuthenticationFilter</literal> and its required its required collaborators:</para>
collaborators:</para> <para> <programlisting><![CDATA[
<para>
<programlisting><![CDATA[
<bean id="digestFilter" class= <bean id="digestFilter" class=
"org.springframework.security.web.authentication.www.DigestAuthenticationFilter"> "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<property name="userDetailsService" ref="jdbcDaoImpl"/> <property name="userDetailsService" ref="jdbcDaoImpl"/>
@ -139,18 +134,17 @@
<property name="key" value="acegi"/> <property name="key" value="acegi"/>
<property name="nonceValiditySeconds" value="10"/> <property name="nonceValiditySeconds" value="10"/>
</bean>]]> </bean>]]>
</programlisting> </programlisting> </para>
</para>
<para>The configured <interfacename>UserDetailsService</interfacename> is needed because <para>The configured <interfacename>UserDetailsService</interfacename> is needed because
<literal>DigestAuthenticationFilter</literal> must have direct access to the <literal>DigestAuthenticationFilter</literal> must have direct access to the clear
clear text password of a user. Digest Authentication will NOT work if you are using 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 encoded passwords in your DAO. The DAO collaborator, along with the
<literal>UserCache</literal>, are typically shared directly with a <literal>UserCache</literal>, are typically shared directly with a
<classname>DaoAuthenticationProvider</classname>. The <classname>DaoAuthenticationProvider</classname>. The
<literal>authenticationEntryPoint</literal> property must be <literal>authenticationEntryPoint</literal> property must be
<classname>DigestAuthenticationEntryPoint</classname>, so that <classname>DigestAuthenticationEntryPoint</classname>, so that
<classname>DigestAuthenticationFilter</classname> can obtain the correct <classname>DigestAuthenticationFilter</classname> can obtain the correct
<literal>realmName</literal> and <literal>key</literal> for digest <literal>realmName</literal> and <literal>key</literal> for digest
calculations.</para> calculations.</para>
<para>Like <literal>BasicAuthenticationFilter</literal>, if authentication is successful <para>Like <literal>BasicAuthenticationFilter</literal>, if authentication is successful
an <interfacename>Authentication</interfacename> request token will be placed into 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" <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CAS Authentication</title> <title>CAS Authentication</title>
<section xml:id="cas-overview"> <section xml:id="cas-overview">
<title>Overview</title> <title>Overview</title>
<para>JA-SIG produces an enterprise-wide single sign on system known as CAS. Unlike other <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 initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple
understand, platform independent, and supports proxy capabilities. Spring Security fully to understand, platform independent, and supports proxy capabilities. Spring Security
supports CAS, and provides an easy migration path from single-application deployments of fully supports CAS, and provides an easy migration path from single-application
Spring Security through to multiple-application deployments secured by an enterprise-wide CAS deployments of Spring Security through to multiple-application deployments secured by an
server.</para> enterprise-wide CAS server.</para>
<para>You can learn more about CAS at <literal>http://www.ja-sig.org/cas</literal>. You will <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> also need to visit this site to download the CAS Server files.</para>
</section> </section>
<section xml:id="cas-how-it-works"> <section xml:id="cas-how-it-works">
<info> <info>
<title>How CAS Works</title> <title>How CAS Works</title>
</info> </info>
<para>Whilst the CAS web site contains documents that detail the architecture of CAS, we present <para>Whilst the CAS web site contains documents that detail the architecture of CAS, we
the general overview again here within the context of Spring Security. Spring Security 3.0 present the general overview again here within the context of Spring Security. Spring
supports CAS 3. At the time of writing, the CAS server was at version 3.3.</para> Security 3.0 supports CAS 3. At the time of writing, the CAS server was at version
<para>Somewhere in your enterprise you will need to setup a CAS server. The CAS server is simply 3.3.</para>
a standard WAR file, so there isn't anything difficult about setting up your server. Inside <para>Somewhere in your enterprise you will need to setup a CAS server. The CAS server is
the WAR file you will customise the login and other single sign on pages displayed to simply a standard WAR file, so there isn't anything difficult about setting up your
users.</para> server. Inside the WAR file you will customise the login and other single sign on pages
<para>When deploying a CAS 3.3 server, you will also need to specify an displayed to users.</para>
<literal>AuthenticationHandler</literal> in the <para>When deploying a CAS 3.3 server, you will also need to specify an
<filename>deployerConfigContext.xml</filename> included with CAS. The <literal>AuthenticationHandler</literal> in the
<literal>AuthenticationHandler</literal> has a simple method that returns a boolean as to <filename>deployerConfigContext.xml</filename> included with CAS. The
whether a given set of Credentials is valid. Your <literal>AuthenticationHandler</literal> <literal>AuthenticationHandler</literal> has a simple method that returns a boolean as
implementation will need to link into some type of backend authentication repository, such as to whether a given set of Credentials is valid. Your
an LDAP server or database. CAS itself includes numerous <literal>AuthenticationHandler</literal> implementation will need to link into some type
<literal>AuthenticationHandler</literal>s out of the box to assist with this. When you of backend authentication repository, such as an LDAP server or database. CAS itself
download and deploy the server war file, it is set up to successfully authenticate users who includes numerous <literal>AuthenticationHandler</literal>s out of the box to assist
enter a password matching their username, which is useful for testing.</para> with this. When you download and deploy the server war file, it is set up to
<para>Apart from the CAS server itself, the other key players are of course the secure web successfully authenticate users who enter a password matching their username, which is
applications deployed throughout your enterprise. These web applications are known as useful for testing.</para>
"services". There are two types of services: standard services and proxy services. A proxy <para>Apart from the CAS server itself, the other key players are of course the secure web
service is able to request resources from other services on behalf of the user. This will be applications deployed throughout your enterprise. These web applications are known as
explained more fully later.</para> "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"> <section xml:id="cas-sequence">
<title>Spring Security and CAS Interaction Sequence</title> <title>Spring Security and CAS Interaction Sequence</title>
@ -243,36 +245,34 @@
Let's now look at how this is configured</para> Let's now look at how this is configured</para>
</section> </section>
--> -->
</section> </section>
<section xml:id="cas-client"> <section xml:id="cas-client">
<info> <info>
<title>Configuration of CAS Client</title> <title>Configuration of CAS Client</title>
</info> </info>
<para>The web application side of CAS is made easy due to Spring Security. It is assumed you <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 already know the basics of using Spring Security, so these are not covered again below.
assume a namespace based configuration is being used and add in the CAS beans as required. </para> We'll assume a namespace based configuration is being used and add in the CAS beans as
<para>You will need to add a <classname>ServiceProperties</classname> bean to your application required. </para>
context. This represents your CAS service:</para> <para>You will need to add a <classname>ServiceProperties</classname> bean to your
<para> application context. This represents your CAS service:</para>
<programlisting><![CDATA[ <para> <programlisting><![CDATA[
<bean id="serviceProperties" <bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties"> class="org.springframework.security.cas.ServiceProperties">
<property name="service" <property name="service"
value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/> value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/> <property name="sendRenew" value="false"/>
</bean>]]> </bean>]]>
</programlisting> </programlisting> </para>
</para> <para>The <literal>service</literal> must equal a URL that will be monitored by the
<para>The <literal>service</literal> must equal a URL that will be monitored by the <literal>CasAuthenticationFilter</literal>. The <literal>sendRenew</literal> defaults to
<literal>CasAuthenticationFilter</literal>. The <literal>sendRenew</literal> defaults to false, but should be set to true if your application is particularly sensitive. What
false, but should be set to true if your application is particularly sensitive. What this this parameter does is tell the CAS login service that a single sign on login is
parameter does is tell the CAS login service that a single sign on login is unacceptable. unacceptable. Instead, the user will need to re-enter their username and password in
Instead, the user will need to re-enter their username and password in order to gain access to order to gain access to the service.</para>
the service.</para> <para>The following beans should be configured to commence the CAS authentication process
<para>The following beans should be configured to commence the CAS authentication process (assuming you're using a namespace configuration):</para>
(assuming you're using a namespace configuration):</para> <para> <programlisting><![CDATA[
<para>
<programlisting><![CDATA[
<security:http entry-point-ref="casEntryPoint"> <security:http entry-point-ref="casEntryPoint">
... ...
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" /> <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
@ -289,21 +289,22 @@
<property name="serviceProperties" ref="serviceProperties"/> <property name="serviceProperties" ref="serviceProperties"/>
</bean> </bean>
]]> ]]>
</programlisting> </programlisting> </para>
</para> <para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
<para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive authentication using <link xlink:href="ns-entry-point-ref"
authentication using <link xlink:href="ns-entry-point-ref" ><literal>entry-point-ref</literal></link>. </para>
><literal>entry-point-ref</literal></link>. </para> <para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the
<para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the <classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based logins). logins). </para>
</para> <para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have
<para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have its its <literal>authenticationEntryPoint</literal> property set to the
<literal>authenticationEntryPoint</literal> property set to the <classname>CasAuthenticationEntryPoint</classname> bean.</para>
<classname>CasAuthenticationEntryPoint</classname> bean.</para> <para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the
<para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the <classname>ServiceProperties</classname> bean (discussed above), which provides the URL
<classname>ServiceProperties</classname> bean (discussed above), which provides the URL to the to the enterprise's CAS login server. This is where the user's browser will be
enterprise's CAS login server. This is where the user's browser will be redirected.</para> redirected.</para>
<para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its collaborators: <programlisting><![CDATA[ <para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its
collaborators: <programlisting><![CDATA[
<security:authentication-manager alias="authenticationManager"> <security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" /> <security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager> </security:authentication-manager>
@ -325,13 +326,14 @@
... ...
</security:user-service>]]> </security:user-service>]]>
</programlisting> The </programlisting> The
<classname>CasAuthenticationProvider</classname> uses a <classname>CasAuthenticationProvider</classname> uses a
<interfacename>UserDetailsService</interfacename> instance to load the authorities for 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> user, once they have been authentiated by CAS. We've shown a simple in-memory setup
<para>The beans are all reasonable self-explanatory if you refer back to the "How CAS Works" here. </para>
section.</para> <para>The beans are all reasonable self-explanatory if you refer back to the "How CAS Works"
</section> section.</para>
<!-- </section>
<!--
<para>Note the <literal>CasProxyTicketValidator</literal> has a <para>Note the <literal>CasProxyTicketValidator</literal> has a
remarked out <literal>trustStore</literal> property. This property remarked out <literal>trustStore</literal> property. This property
might be helpful if you experience HTTPS certificate issues. Also note might be helpful if you experience HTTPS certificate issues. Also note

View File

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

View File

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

View File

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

View File

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

View File

@ -7,10 +7,10 @@
<title>Overview</title> <title>Overview</title>
</info> </info>
<para>Spring Security includes a production-quality <para>Spring Security includes a production-quality
<classname>AuthenticationProvider</classname> implementation called <classname>AuthenticationProvider</classname> implementation called
<literal>DaoAuthenticationProvider</literal>. This authentication provider is <literal>DaoAuthenticationProvider</literal>. This authentication provider is compatible
compatible with all of the authentication mechanisms that generate a with all of the authentication mechanisms that generate a
<literal>UsernamePasswordAuthenticationToken</literal>, and is probably the most <literal>UsernamePasswordAuthenticationToken</literal>, and is probably the most
commonly used provider in the framework. Like most of the other authentication commonly used provider in the framework. Like most of the other authentication
providers, the DaoAuthenticationProvider leverages a UserDetailsService in order to providers, the DaoAuthenticationProvider leverages a UserDetailsService in order to
lookup the username, password and GrantedAuthority[]s. Unlike most of the other 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 at the start of this part of the reference guide), and ensuring a suitable
authentication mechanism is configured to present a UsernamePasswordAuthenticationToken, authentication mechanism is configured to present a UsernamePasswordAuthenticationToken,
the configuration of the provider itself is rather simple:</para> the configuration of the provider itself is rather simple:</para>
<para> <para> <programlisting>
<programlisting>
<![CDATA[ <![CDATA[
<bean id="daoAuthenticationProvider" <bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
@ -36,15 +35,14 @@
<property name="saltSource" ref bean="saltSource"/> <property name="saltSource" ref bean="saltSource"/>
<property name="passwordEncoder" ref="passwordEncoder"/> <property name="passwordEncoder" ref="passwordEncoder"/>
</bean> ]]> </bean> ]]>
</programlisting> </programlisting> </para>
</para>
<para>The <literal>PasswordEncoder</literal> and <literal>SaltSource</literal> are optional. <para>The <literal>PasswordEncoder</literal> and <literal>SaltSource</literal> are optional.
A <literal>PasswordEncoder</literal> provides encoding and decoding of passwords A <literal>PasswordEncoder</literal> provides encoding and decoding of passwords
presented in the <interfacename>UserDetails</interfacename> object that is returned from presented in the <interfacename>UserDetails</interfacename> object that is returned from
the configured <interfacename>UserDetailsService</interfacename>. A the configured <interfacename>UserDetailsService</interfacename>. A
<literal>SaltSource</literal> enables the passwords to be populated with a "salt", <literal>SaltSource</literal> enables the passwords to be populated with a "salt", which
which enhances the security of the passwords in the authentication repository. enhances the security of the passwords in the authentication repository.
<literal>PasswordEncoder</literal> implementations are provided with Spring Security <literal>PasswordEncoder</literal> implementations are provided with Spring Security
covering MD5, SHA and cleartext encodings. Two <literal>SaltSource</literal> covering MD5, SHA and cleartext encodings. Two <literal>SaltSource</literal>
implementations are also provided: <literal>SystemWideSaltSource</literal> which encodes implementations are also provided: <literal>SystemWideSaltSource</literal> which encodes
all passwords with the same salt, and <literal>ReflectionSaltSource</literal>, which all passwords with the same salt, and <literal>ReflectionSaltSource</literal>, which
@ -53,16 +51,14 @@
optional features.</para> optional features.</para>
<para>In addition to the properties above, the <literal>DaoAuthenticationProvider</literal> <para>In addition to the properties above, the <literal>DaoAuthenticationProvider</literal>
supports optional caching of <interfacename>UserDetails</interfacename> objects. The supports optional caching of <interfacename>UserDetails</interfacename> objects. The
<literal>UserCache</literal> interface enables the <literal>UserCache</literal> interface enables the
<literal>DaoAuthenticationProvider</literal> to place a <literal>DaoAuthenticationProvider</literal> to place a
<interfacename>UserDetails</interfacename> object into the cache, and retrieve it <interfacename>UserDetails</interfacename> object into the cache, and retrieve it from
from the cache upon subsequent authentication attempts for the same username. By default the cache upon subsequent authentication attempts for the same username. By default the
the <literal>DaoAuthenticationProvider</literal> uses the <literal>DaoAuthenticationProvider</literal> uses the <literal>NullUserCache</literal>,
<literal>NullUserCache</literal>, which performs no caching. A usable caching which performs no caching. A usable caching implementation is also provided,
implementation is also provided, <literal>EhCacheBasedUserCache</literal>, which is <literal>EhCacheBasedUserCache</literal>, which is configured as follows:</para>
configured as follows:</para> <para> <programlisting><![CDATA[
<para>
<programlisting><![CDATA[
<bean id="daoAuthenticationProvider" <bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/> <property name="userDetailsService" ref="userDetailsService"/>
@ -82,15 +78,14 @@
class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache"> class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
<property name="cache" ref="userCacheBackend"/> <property name="cache" ref="userCacheBackend"/>
</bean>]]> </bean>]]>
</programlisting> </programlisting> </para>
</para>
<para>All Spring Security EH-CACHE implementations (including <para>All Spring Security EH-CACHE implementations (including
<literal>EhCacheBasedUserCache</literal>) require an EH-CACHE <literal>EhCacheBasedUserCache</literal>) require an EH-CACHE <literal>Cache</literal>
<literal>Cache</literal> object. The <literal>Cache</literal> object can be obtained object. The <literal>Cache</literal> object can be obtained from wherever you like,
from wherever you like, although we recommend you use Spring's factory classes as shown although we recommend you use Spring's factory classes as shown in the above
in the above configuration. If using Spring's factory classes, please refer to the configuration. If using Spring's factory classes, please refer to the Spring
Spring documentation for further details on how to optimise the cache storage location, documentation for further details on how to optimise the cache storage location, memory
memory usage, eviction policies, timeouts etc.</para> usage, eviction policies, timeouts etc.</para>
<note> <note>
<para>In the majority of cases, where your application is a stateful web application, <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 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 <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 at a web request or method invocation level. Instead, security decisions need to
comprise both who (<interfacename>Authentication</interfacename>), where comprise both who (<interfacename>Authentication</interfacename>), where
(<classname>MethodInvocation</classname>) and what (<literal>SomeDomainObject</literal>). In (<classname>MethodInvocation</classname>) and what
other words, authorization decisions also need to consider the actual domain object (<literal>SomeDomainObject</literal>). In other words, authorization decisions also need
instance subject of a method invocation.</para> 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 <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 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 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 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 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 Security as the foundation, you have several approaches that can be used:<orderedlist
inheritnum="ignore" continuation="restarts"> inheritnum="ignore" continuation="restarts">
<listitem> <listitem>
<para>Write your business methods to enforce the security. You could consult a <para>Write your business methods to enforce the security. You could consult a
collection within the <literal>Customer</literal> domain object instance to collection within the <literal>Customer</literal> domain object instance to
determine which users have access. By using the determine which users have access. By using the
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>, <literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
you'll be able to access the <interfacename>Authentication</interfacename> you'll be able to access the <interfacename>Authentication</interfacename>
object.</para> object.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the security <para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the
from the <literal>GrantedAuthority[]</literal>s stored in the security from the <literal>GrantedAuthority[]</literal>s stored in the
<interfacename>Authentication</interfacename> object. This would mean your <interfacename>Authentication</interfacename> object. This would mean your
<interfacename>AuthenticationManager</interfacename> would need to populate the <interfacename>AuthenticationManager</interfacename> would need to populate the
<interfacename>Authentication</interfacename> with custom <interfacename>Authentication</interfacename> with custom
<interfacename>GrantedAuthority</interfacename>[]s representing each of the <interfacename>GrantedAuthority</interfacename>[]s representing each of the
<literal>Customer</literal> domain object instances the principal has <literal>Customer</literal> domain object instances the principal has access
access to.</para> to.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the security <para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the
and open the target <literal>Customer</literal> domain object directly. This security and open the target <literal>Customer</literal> domain object directly.
would mean your voter needs access to a DAO that allows it to retrieve the 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. It would then access the
<literal>Customer</literal> object's collection of approved users and <literal>Customer</literal> object's collection of approved users and make the
make the appropriate decision.</para> appropriate decision.</para>
</listitem> </listitem>
</orderedlist></para> </orderedlist></para>
<para>Each one of these approaches is perfectly legitimate. However, the first couples your <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 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 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>Customer</literal> authorization logic elsewhere. Obtaining the
<literal>GrantedAuthority[]</literal>s from the <interfacename>Authentication</interfacename> <literal>GrantedAuthority[]</literal>s from the
object is also fine, but will not scale to large numbers of <interfacename>Authentication</interfacename> object is also fine, but will not scale to
<literal>Customer</literal>s. If a user might be able to access 5,000 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 <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 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, the <interfacename>Authentication</interfacename> object would be undesirable. The final
opening the <literal>Customer</literal> directly from external code, is probably the method, opening the <literal>Customer</literal> directly from external code, is probably
best of the three. It achieves separation of concerns, and doesn't misuse memory or CPU the best of the three. It achieves separation of concerns, and doesn't misuse memory or
cycles, but it is still inefficient in that both the CPU cycles, but it is still inefficient in that both the
<interfacename>AccessDecisionVoter</interfacename> and the eventual business method itself will <interfacename>AccessDecisionVoter</interfacename> and the eventual business method
perform a call to the DAO responsible for retrieving the <literal>Customer</literal> itself will perform a call to the DAO responsible for retrieving the
object. Two accesses per method invocation is clearly undesirable. In addition, with <literal>Customer</literal> object. Two accesses per method invocation is clearly
every approach listed you'll need to write your own access control list (ACL) undesirable. In addition, with every approach listed you'll need to write your own
persistence and business logic from scratch.</para> access control list (ACL) persistence and business logic from scratch.</para>
<para>Fortunately, there is another alternative, which we'll talk about below.</para> <para>Fortunately, there is another alternative, which we'll talk about below.</para>
</section> </section>
<section xml:id="domain-acls-key-concepts"> <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 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 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> this in mind, Spring Security delivers three main ACL-related capabilities to your application:<itemizedlist>
<listitem> <listitem>
<para>A way of efficiently retrieving ACL entries for all of your domain objects <para>A way of efficiently retrieving ACL entries for all of your domain objects
(and modifying those ACLs)</para> (and modifying those ACLs)</para>
</listitem> </listitem>
<listitem> <listitem>
<para>A way of ensuring a given principal is permitted to work with your <para>A way of ensuring a given principal is permitted to work with your objects,
objects, before methods are called</para> before methods are called</para>
</listitem> </listitem>
<listitem> <listitem>
<para>A way of ensuring a given principal is permitted to work with your objects <para>A way of ensuring a given principal is permitted to work with your objects (or
(or something they return), after methods are called</para> something they return), after methods are called</para>
</listitem> </listitem>
</itemizedlist></para> </itemizedlist></para>
<para>As indicated by the first bullet point, one of the main capabilities of the Spring <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 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 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 order of size in a typical Spring Security ACL deployment, with the table with the most
rows listed last:</para> rows listed last:</para>
<para> <para> <itemizedlist>
<itemizedlist> <listitem>
<listitem> <para>ACL_SID allows us to uniquely identify any principal or authority in the
<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
system ("SID" stands for "security identity"). The only columns are the ID, textual representation of the SID, and a flag to indicate whether the textual
a textual representation of the SID, and a flag to indicate whether the representation refers to a principal name or a
textual representation refers to a principal name or a <interfacename>GrantedAuthority</interfacename>. Thus, there is a single row for
<interfacename>GrantedAuthority</interfacename>. Thus, there is a single row for each unique principal or <interfacename>GrantedAuthority</interfacename>. When
each unique principal or <interfacename>GrantedAuthority</interfacename>. When used in used in the context of receiving a permission, a SID is generally called a
the context of receiving a permission, a SID is generally called a "recipient".</para>
"recipient".</para> </listitem>
</listitem> <listitem>
<listitem> <para>ACL_CLASS allows us to uniquely identify any domain object class in the
<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
system. The only columns are the ID and the Java class name. Thus, there is single row for each unique Class we wish to store ACL permissions for.</para>
a single row for each unique Class we wish to store ACL permissions </listitem>
for.</para> <listitem>
</listitem> <para>ACL_OBJECT_IDENTITY stores information for each unique domain object instance
<listitem> in the system. Columns include the ID, a foreign key to the ACL_CLASS table, a
<para>ACL_OBJECT_IDENTITY stores information for each unique domain object unique identifier so we know which ACL_CLASS instance we're providing
instance in the system. Columns include the ID, a foreign key to the information for, the parent, a foreign key to the ACL_SID table to represent the
ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance owner of the domain object instance, and whether we allow ACL entries to inherit
we're providing information for, the parent, a foreign key to the ACL_SID from any parent ACL. We have a single row for every domain object instance we're
table to represent the owner of the domain object instance, and whether we storing ACL permissions for.</para>
allow ACL entries to inherit from any parent ACL. We have a single row for </listitem>
every domain object instance we're storing ACL permissions for.</para> <listitem>
</listitem> <para>Finally, ACL_ENTRY stores the individual permissions assigned to each
<listitem> recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the
<para>Finally, ACL_ENTRY stores the individual permissions assigned to each recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not, and
recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the the integer bit mask that represents the actual permission being granted or
recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not, denied. We have a single row for every recipient that receives a permission to
and the integer bit mask that represents the actual permission being granted work with a domain object.</para>
or denied. We have a single row for every recipient that receives a </listitem>
permission to work with a domain object.</para> </itemizedlist> </para>
</listitem>
</itemizedlist>
</para>
<para>As mentioned in the last paragraph, the ACL system uses integer bit masking. Don't <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, 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 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), 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 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> 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 <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 absolutely no bearing on the fact we've chosen to use integer bit masking. Whilst you
@ -162,16 +159,16 @@
<listitem> <listitem>
<para><literal>Acl</literal>: Every domain object has one and only one <para><literal>Acl</literal>: Every domain object has one and only one
<literal>Acl</literal> object, which internally holds the <literal>Acl</literal> object, which internally holds the
<literal>AccessControlEntry</literal>s as well as knows the owner of 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, <literal>Acl</literal>. An Acl does not refer directly to the domain object, but
but instead to an <literal>ObjectIdentity</literal>. The <literal>Acl</literal> instead to an <literal>ObjectIdentity</literal>. The <literal>Acl</literal> is
is stored in the ACL_OBJECT_IDENTITY table.</para> stored in the ACL_OBJECT_IDENTITY table.</para>
</listitem> </listitem>
<listitem> <listitem>
<para><literal>AccessControlEntry</literal>: An <literal>Acl</literal> holds <para><literal>AccessControlEntry</literal>: An <literal>Acl</literal> holds
multiple <literal>AccessControlEntry</literal>s, which are often abbreviated as multiple <literal>AccessControlEntry</literal>s, which are often abbreviated as
ACEs in the framework. Each ACE refers to a specific tuple of 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 <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> audit settings. The ACE is stored in the ACL_ENTRY table.</para>
</listitem> </listitem>
@ -183,11 +180,11 @@
</listitem> </listitem>
<listitem> <listitem>
<para><literal>Sid</literal>: The ACL module needs to refer to principals and <para><literal>Sid</literal>: The ACL module needs to refer to principals and
<literal>GrantedAuthority[]</literal>s. A level of indirection is provided <literal>GrantedAuthority[]</literal>s. A level of indirection is provided by
by the <literal>Sid</literal> interface, which is an abbreviation of "security the <literal>Sid</literal> interface, which is an abbreviation of "security
identity". Common classes include <literal>PrincipalSid</literal> (to represent identity". Common classes include <literal>PrincipalSid</literal> (to represent
the principal inside an <interfacename>Authentication</interfacename> object) and the principal inside an <interfacename>Authentication</interfacename> object)
<literal>GrantedAuthoritySid</literal>. The security identity information is and <literal>GrantedAuthoritySid</literal>. The security identity information is
stored in the ACL_SID table.</para> stored in the ACL_SID table.</para>
</listitem> </listitem>
<listitem> <listitem>
@ -198,8 +195,8 @@
<listitem> <listitem>
<para><literal>AclService</literal>: Retrieves the <literal>Acl</literal> applicable <para><literal>AclService</literal>: Retrieves the <literal>Acl</literal> applicable
for a given <literal>ObjectIdentity</literal>. In the included implementation for a given <literal>ObjectIdentity</literal>. In the included implementation
(<literal>JdbcAclService</literal>), retrieval operations are delegated to a (<literal>JdbcAclService</literal>), retrieval operations are delegated to a
<literal>LookupStrategy</literal>. The <literal>LookupStrategy</literal> <literal>LookupStrategy</literal>. The <literal>LookupStrategy</literal>
provides a highly optimized strategy for retrieving ACL information, using provides a highly optimized strategy for retrieving ACL information, using
batched retrievals <literal>(BasicLookupStrategy</literal>) and supporting batched retrievals <literal>(BasicLookupStrategy</literal>) and supporting
custom implementations that leverage materialized views, hierarchical queries custom implementations that leverage materialized views, hierarchical queries
@ -227,16 +224,15 @@
ACL information somewhere. This necessitates the instantiation of a ACL information somewhere. This necessitates the instantiation of a
<literal>DataSource</literal> using Spring. The <literal>DataSource</literal> is then <literal>DataSource</literal> using Spring. The <literal>DataSource</literal> is then
injected into a <literal>JdbcMutableAclService</literal> and injected into a <literal>JdbcMutableAclService</literal> and
<literal>BasicLookupStrategy</literal> instance. The latter provides <literal>BasicLookupStrategy</literal> instance. The latter provides high-performance
high-performance ACL retrieval capabilities, and the former provides mutator ACL retrieval capabilities, and the former provides mutator capabilities. Refer to one
capabilities. Refer to one of the samples that ship with Spring Security for an example of the samples that ship with Spring Security for an example configuration. You'll also
configuration. You'll also need to populate the database with the four ACL-specific need to populate the database with the four ACL-specific tables listed in the last
tables listed in the last section (refer to the ACL samples for the appropriate SQL section (refer to the ACL samples for the appropriate SQL statements).</para>
statements).</para>
<para>Once you've created the required schema and instantiated <para>Once you've created the required schema and instantiated
<literal>JdbcMutableAclService</literal>, you'll next need to ensure your domain <literal>JdbcMutableAclService</literal>, you'll next need to ensure your domain model
model supports interoperability with the Spring Security ACL package. Hopefully supports interoperability with the Spring Security ACL package. Hopefully
<literal>ObjectIdentityImpl</literal> will prove sufficient, as it provides a large <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 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 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 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 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 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 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, <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 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 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, <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 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 logic. You have a number of choices here. You could write your own
<interfacename>AccessDecisionVoter</interfacename> or <literal>AfterInvocationProvider</literal> <interfacename>AccessDecisionVoter</interfacename> or
that respectively fires before or after a method invocation. Such classes would use <literal>AfterInvocationProvider</literal> that respectively fires before or after a
<literal>AclService</literal> to retrieve the relevant ACL and then call method invocation. Such classes would use <literal>AclService</literal> to retrieve the
<literal>Acl.isGranted(Permission[] permission, Sid[] sids, boolean relevant ACL and then call <literal>Acl.isGranted(Permission[] permission, Sid[] sids,
administrativeMode)</literal> to decide whether permission is granted or denied. boolean administrativeMode)</literal> to decide whether permission is granted or denied.
Alternately, you could use our <literal>AclEntryVoter</literal>, Alternately, you could use our <literal>AclEntryVoter</literal>,
<literal>AclEntryAfterInvocationProvider</literal> or <literal>AclEntryAfterInvocationProvider</literal> or
<literal>AclEntryAfterInvocationCollectionFilteringProvider</literal> classes. All <literal>AclEntryAfterInvocationCollectionFilteringProvider</literal> classes. All of
of these classes provide a declarative-based approach to evaluating ACL information at 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 runtime, freeing you from needing to write any code. Please refer to the sample
applications to learn how to use these classes.</para> applications to learn how to use these classes.</para>
</section> </section>

View File

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

View File

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

View File

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

View File

@ -1,36 +1,38 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="jaas"> <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"> <section xml:id="jaas-overview">
<info><title>Overview</title></info> <info>
<para>Spring Security provides a package able to delegate <title>Overview</title>
authentication requests to the Java Authentication and Authorization </info>
Service (JAAS). This package is discussed in detail below.</para> <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 <para>Central to JAAS operation are login configuration files. To learn more about JAAS
learn more about JAAS login configuration files, consult the JAAS login configuration files, consult the JAAS reference documentation available from Sun
reference documentation available from Sun Microsystems. We expect you Microsystems. We expect you to have a basic understanding of JAAS and its login
to have a basic understanding of JAAS and its login configuration file configuration file syntax in order to understand this section.</para>
syntax in order to understand this section.</para>
</section> </section>
<section xml:id="jaas-config"> <section xml:id="jaas-config">
<info><title>Configuration</title></info> <info>
<para>The <literal>JaasAuthenticationProvider</literal> attempts to <title>Configuration</title>
authenticate a users principal and credentials through JAAS.</para> </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, <para>Lets assume we have a JAAS login configuration file,
<literal>/WEB-INF/login.conf</literal>, with the following <literal>/WEB-INF/login.conf</literal>, with the following contents:
contents: <programlisting>
<programlisting>
JAASTest { JAASTest {
sample.SampleLoginModule required; sample.SampleLoginModule required;
};</programlisting></para> };</programlisting></para>
<para>Like all Spring Security beans, the <para>Like all Spring Security beans, the <classname>JaasAuthenticationProvider</classname>
<classname>JaasAuthenticationProvider</classname> is configured via the is configured via the application context. The following definitions would correspond to
application context. The following definitions would correspond to the the above JAAS login configuration file: <programlisting><![CDATA[
above JAAS login configuration file:
<programlisting><![CDATA[
<bean id="jaasAuthenticationProvider" <bean id="jaasAuthenticationProvider"
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider"> class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="/WEB-INF/login.conf"/> <property name="loginConfig" value="/WEB-INF/login.conf"/>
@ -55,82 +57,76 @@ JAASTest {
<interfacename>AuthorityGranter</interfacename>s are discussed below.</para> <interfacename>AuthorityGranter</interfacename>s are discussed below.</para>
<section xml:id="jaas-callbackhandler"> <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 <para>Most JAAS <literal>LoginModule</literal>s require a callback of some sort. These
of some sort. These callbacks are usually used to obtain the callbacks are usually used to obtain the username and password from the user.</para>
username and password from the user.</para>
<para>In a Spring Security deployment, Spring Security is <para>In a Spring Security deployment, Spring Security is responsible for this user
responsible for this user interaction (via the authentication interaction (via the authentication mechanism). Thus, by the time the authentication
mechanism). Thus, by the time the authentication request is request is delegated through to JAAS, Spring Security's authentication mechanism
delegated through to JAAS, Spring Security's authentication will already have fully-populated an <interfacename>Authentication</interfacename>
mechanism will already have fully-populated an object containing all the information required by the JAAS
<interfacename>Authentication</interfacename> object containing all the
information required by the JAAS
<literal>LoginModule</literal>.</para> <literal>LoginModule</literal>.</para>
<para>Therefore, the JAAS package for Spring Security provides two <para>Therefore, the JAAS package for Spring Security provides two default callback
default callback handlers, handlers, <literal>JaasNameCallbackHandler</literal> and
<literal>JaasNameCallbackHandler</literal> and <literal>JaasPasswordCallbackHandler</literal>. Each of these callback handlers
<literal>JaasPasswordCallbackHandler</literal>. Each of these implement <literal>JaasAuthenticationCallbackHandler</literal>. In most cases these
callback handlers implement callback handlers can simply be used without understanding the internal
<literal>JaasAuthenticationCallbackHandler</literal>. In most cases mechanics.</para>
these callback handlers can simply be used without understanding the
internal mechanics.</para>
<para>For those needing full control over the callback behavior, <para>For those needing full control over the callback behavior, internally
internally <literal>JaasAuthenticationProvider</literal> wraps these <literal>JaasAuthenticationProvider</literal> wraps these
<literal>JaasAuthenticationCallbackHandler</literal>s with an <literal>JaasAuthenticationCallbackHandler</literal>s with an
<literal>InternalCallbackHandler</literal>. The <literal>InternalCallbackHandler</literal>. The
<literal>InternalCallbackHandler</literal> is the class that <literal>InternalCallbackHandler</literal> is the class that actually implements
actually implements JAAS normal <literal>CallbackHandler</literal> JAAS normal <literal>CallbackHandler</literal> interface. Any time that the JAAS
interface. Any time that the JAAS <literal>LoginModule</literal> is <literal>LoginModule</literal> is used, it is passed a list of application context
used, it is passed a list of application context configured configured <literal>InternalCallbackHandler</literal>s. If the
<literal>InternalCallbackHandler</literal>s. If the
<literal>LoginModule</literal> requests a callback against the <literal>LoginModule</literal> requests a callback against the
<literal>InternalCallbackHandler</literal>s, the callback is in-turn <literal>InternalCallbackHandler</literal>s, the callback is in-turn passed to the
passed to the <literal>JaasAuthenticationCallbackHandler</literal>s <literal>JaasAuthenticationCallbackHandler</literal>s being wrapped.</para>
being wrapped.</para>
</section> </section>
<section xml:id="jaas-authoritygranter"> <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 <para>JAAS works with principals. Even "roles" are represented as principals in JAAS.
principals in JAAS. Spring Security, on the other hand, works with Spring Security, on the other hand, works with
<interfacename>Authentication</interfacename> objects. Each <interfacename>Authentication</interfacename> objects. Each
<interfacename>Authentication</interfacename> object contains a single <interfacename>Authentication</interfacename> object contains a single principal,
principal, and multiple <interfacename>GrantedAuthority</interfacename>[]s. To and multiple <interfacename>GrantedAuthority</interfacename>[]s. To facilitate
facilitate mapping between these different concepts, Spring mapping between these different concepts, Spring Security's JAAS package includes an
Security's JAAS package includes an
<literal>AuthorityGranter</literal> interface.</para> <literal>AuthorityGranter</literal> interface.</para>
<para>An <literal>AuthorityGranter</literal> is responsible for <para>An <literal>AuthorityGranter</literal> is responsible for inspecting a JAAS
inspecting a JAAS principal and returning a set of principal and returning a set of <literal>String</literal>s, representing the
<literal>String</literal>s, representing the authorities assigned to the principal. authorities assigned to the principal. For each returned authority string, the
For each returned authority string, the
<classname>JaasAuthenticationProvider</classname> creates a <classname>JaasAuthenticationProvider</classname> creates a
<classname>JaasGrantedAuthority</classname> (which implements Spring <classname>JaasGrantedAuthority</classname> (which implements Spring Securitys
Securitys <interfacename>GrantedAuthority</interfacename> interface) containing <interfacename>GrantedAuthority</interfacename> interface) containing the authority
the authority string and the JAAS principal that the string and the JAAS principal that the
<interfacename>AuthorityGranter</interfacename> was passed. The <interfacename>AuthorityGranter</interfacename> was passed. The
<classname>JaasAuthenticationProvider</classname> obtains the JAAS <classname>JaasAuthenticationProvider</classname> obtains the JAAS principals by
principals by firstly successfully authenticating the users firstly successfully authenticating the users credentials using the JAAS
credentials using the JAAS <literal>LoginModule</literal>, and then <literal>LoginModule</literal>, and then accessing the
accessing the <literal>LoginContext</literal> it returns. A call to <literal>LoginContext</literal> it returns. A call to
<literal>LoginContext.getSubject().getPrincipals()</literal> is <literal>LoginContext.getSubject().getPrincipals()</literal> is made, with each
made, with each resulting principal passed to each resulting principal passed to each <interfacename>AuthorityGranter</interfacename>
<interfacename>AuthorityGranter</interfacename> defined against the defined against the
<literal>JaasAuthenticationProvider.setAuthorityGranters(List)</literal> <literal>JaasAuthenticationProvider.setAuthorityGranters(List)</literal>
property.</para> property.</para>
<para>Spring Security does not include any production <para>Spring Security does not include any production
<interfacename>AuthorityGranter</interfacename>s given that every JAAS principal <interfacename>AuthorityGranter</interfacename>s given that every JAAS principal has
has an implementation-specific meaning. However, there is a an implementation-specific meaning. However, there is a
<literal>TestAuthorityGranter</literal> in the unit tests that <literal>TestAuthorityGranter</literal> in the unit tests that demonstrates a simple
demonstrates a simple <literal>AuthorityGranter</literal> <literal>AuthorityGranter</literal> implementation.</para>
implementation.</para>
</section> </section>
</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 <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 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 setting up a directory using the free LDAP server OpenLDAP: <uri
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="http://www.zytrax.com/books/ldap/" xlink:href="http://www.zytrax.com/books/ldap/">http://www.zytrax.com/books/ldap/</uri>.
>http://www.zytrax.com/books/ldap/</uri>. Some familiarity with the JNDI APIs used Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. We
to access LDAP from Java may also be useful. We don't use any third-party LDAP libraries don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but
(Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so extensive use is made of Spring LDAP, so some familiarity with that project may be
some familiarity with that project may be useful if you plan on adding your own useful if you plan on adding your own customizations.</para>
customizations.</para>
</section> </section>
<section> <section>
<info> <info>
@ -30,19 +29,19 @@
</info> </info>
<para> LDAP authentication in Spring Security can be roughly divided into the following <para> LDAP authentication in Spring Security can be roughly divided into the following
stages. <orderedlist inheritnum="ignore" continuation="restarts"> stages. <orderedlist inheritnum="ignore" continuation="restarts">
<listitem> <listitem>
<para>Obtaining the unique LDAP <quote>Distinguished Name</quote>, or DN, from <para>Obtaining the unique LDAP <quote>Distinguished Name</quote>, or DN, from the
the login name. This will often mean performing a search in the directory, login name. This will often mean performing a search in the directory, unless
unless the exact mapping of usernames to DNs is known in advance.</para> the exact mapping of usernames to DNs is known in advance.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Authenticating the user, either by binding as that user or by performing a <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 remote <quote>compare</quote> operation of the user's password against the
password attribute in the directory entry for the DN.</para> password attribute in the directory entry for the DN.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Loading the list of authorities for the user.</para> <para>Loading the list of authorities for the user.</para>
</listitem> </listitem>
</orderedlist> The exception is when the LDAP directory is just being used to retrieve </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 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 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"/> <ldap-server root="dc=springframework,dc=org"/>
]]> ]]>
</programlisting> Here we've specified that the root DIT of the directory should be </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, <quote>dc=springframework,dc=org</quote>, which is the default. Used this way, the
the namespace parser will create an embedded Apache Directory server and scan 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 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 customize this behaviour using the <literal>ldif</literal> attribute, which defines
an LDIF resource to be loaded: <programlisting><![CDATA[ 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> 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. 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 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> from the root. </para>
</section> </section>
<section> <section>
@ -111,41 +110,37 @@
</info> </info>
<para> How authorities are loaded from groups in the LDAP directory is controlled by the <para> How authorities are loaded from groups in the LDAP directory is controlled by the
following attributes. <itemizedlist> following attributes. <itemizedlist>
<listitem> <listitem>
<para> <para> <literal>group-search-base</literal>. Defines the part of the directory
<literal>group-search-base</literal>. Defines the part of the directory tree under which group searches should be performed.</para>
tree under which group searches should be performed.</para> </listitem>
</listitem> <listitem>
<listitem> <para> <literal>group-role-attribute</literal>. The attribute which contains the
<para> name of the authority defined by the group entry. Defaults to
<literal>group-role-attribute</literal>. The attribute which contains <literal>cn</literal> </para>
the name of the authority defined by the group entry. Defaults to </listitem>
<literal>cn</literal> <listitem>
</para> <para> <literal>group-search-filter</literal>. The filter which is used to
</listitem> search for group membership. The default is
<listitem> <literal>uniqueMember={0}</literal>, corresponding to the
<para> <literal>groupOfUniqueMembers</literal> LDAP class. In this case, the
<literal>group-search-filter</literal>. The filter which is used to substituted parameter is the full distinguished name of the user. The
search for group membership. The default is parameter <literal>{1}</literal> can be used if you want to filter on the
<literal>uniqueMember={0}</literal>, corresponding to the login name.</para>
<literal>groupOfUniqueMembers</literal> LDAP class. In this case, </listitem>
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[ </itemizedlist> So if we used the following configuration <programlisting><![CDATA[
<ldap-authentication-provider user-dn-pattern="uid={0},ou=people" <ldap-authentication-provider user-dn-pattern="uid={0},ou=people"
group-search-base="ou=groups" /> group-search-base="ou=groups" />
]]></programlisting> and authenticated successfully as user <quote>ben</quote>, the subsequent ]]></programlisting> and authenticated successfully as user <quote>ben</quote>, the subsequent
loading of authorities would perform a search under the directory entry loading of authorities would perform a search under the directory entry
<literal>ou=groups,dc=springframework,dc=org</literal>, looking for entries <literal>ou=groups,dc=springframework,dc=org</literal>, looking for entries which
which contain the attribute <literal>uniqueMember</literal> with value contain the attribute <literal>uniqueMember</literal> with value
<literal>uid=ben,ou=people,dc=springframework,dc=org</literal>. By default the <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 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 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 any prefix, use <literal>role-prefix="none"</literal>. For more information on
loading authorities, see the Javadoc for the loading authorities, see the Javadoc for the
<classname>DefaultLdapAuthoritiesPopulator</classname> class. </para> <classname>DefaultLdapAuthoritiesPopulator</classname> class. </para>
</section> </section>
</section> </section>
<section> <section>
@ -159,10 +154,10 @@
using namespace configuration then you can skip this section and the next one. </para> using namespace configuration then you can skip this section and the next one. </para>
<para> The main LDAP provider class, <classname>LdapAuthenticationProvider</classname>, <para> The main LDAP provider class, <classname>LdapAuthenticationProvider</classname>,
doesn't actually do much itself but delegates the work to two other beans, an doesn't actually do much itself but delegates the work to two other beans, an
<interfacename>LdapAuthenticator</interfacename> and an <interfacename>LdapAuthenticator</interfacename> and an
<interfacename>LdapAuthoritiesPopulator</interfacename> which are responsible for <interfacename>LdapAuthoritiesPopulator</interfacename> which are responsible for
authenticating the user and retrieving the user's set of 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"> <section xml:id="ldap-ldap-authenticators">
<info> <info>
<title>LdapAuthenticator Implementations</title> <title>LdapAuthenticator Implementations</title>
@ -172,18 +167,16 @@
authentication being used. For example, if binding as the user, it may be necessary authentication being used. For example, if binding as the user, it may be necessary
to read them with the user's own permissions.</para> to read them with the user's own permissions.</para>
<para>There are currently two authentication strategies supplied with Spring Security: <itemizedlist> <para>There are currently two authentication strategies supplied with Spring Security: <itemizedlist>
<listitem> <listitem>
<para>Authentication directly to the LDAP server ("bind" <para>Authentication directly to the LDAP server ("bind" authentication).</para>
authentication).</para> </listitem>
</listitem> <listitem>
<listitem> <para>Password comparison, where the password supplied by the user is compared
<para>Password comparison, where the password supplied by the user is with the one stored in the repository. This can either be done by retrieving
compared with the one stored in the repository. This can either be done the value of the password attribute and checking it locally or by performing
by retrieving the value of the password attribute and checking it an LDAP "compare" operation, where the supplied password is passed to the
locally or by performing an LDAP "compare" operation, where the supplied server for comparison and the real password value is never retrieved.</para>
password is passed to the server for comparison and the real password </listitem>
value is never retrieved.</para>
</listitem>
</itemizedlist></para> </itemizedlist></para>
<section xml:id="ldap-ldap-authenticators-common"> <section xml:id="ldap-ldap-authenticators-common">
<info> <info>
@ -192,33 +185,32 @@
<para>Before it is possible to authenticate a user (by either strategy), the <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 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 application. This can be done either by simple pattern-matching (by setting the
<property>setUserDnPatterns</property> array property) or by setting the <property>setUserDnPatterns</property> array property) or by setting the
<property>userSearch</property> property. For the DN pattern-matching <property>userSearch</property> property. For the DN pattern-matching approach,
approach, a standard Java pattern format is used, and the login name will be a standard Java pattern format is used, and the login name will be substituted
substituted for the parameter <parameter>{0}</parameter>. The pattern should be for the parameter <parameter>{0}</parameter>. The pattern should be relative to
relative to the DN that the configured the DN that the configured
<interfacename>SpringSecurityContextSource</interfacename> will bind to (see <interfacename>SpringSecurityContextSource</interfacename> will bind to (see the
the section on <link linkend="ldap-context-source">connecting to the LDAP section on <link linkend="ldap-context-source">connecting to the LDAP
server</link> for more information on this). For example, if you are using server</link> for more information on this). For example, if you are using an
an LDAP server with the URL LDAP server with the URL
<literal>ldap://monkeymachine.co.uk/dc=springframework,dc=org</literal>, and <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 have a pattern <literal>uid={0},ou=greatapes</literal>, then a login name of
"gorilla" will map to a DN "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 configured DN pattern will be tried in turn until a match is found. For
information on using a search, see the section on <link information on using a search, see the section on <link
linkend="ldap-searchobjects">search objects</link> below. A combination of linkend="ldap-searchobjects">search objects</link> below. A combination of the
the two approaches can also be used - the patterns will be checked first and if two approaches can also be used - the patterns will be checked first and if no
no matching DN is found, the search will be used.</para> matching DN is found, the search will be used.</para>
</section> </section>
<section xml:id="ldap-ldap-authenticators-bind"> <section xml:id="ldap-ldap-authenticators-bind">
<info> <info>
<title>BindAuthenticator</title> <title>BindAuthenticator</title>
</info> </info>
<para>The class <classname>BindAuthenticator</classname> in the package <para>The class <classname>BindAuthenticator</classname> in the package
<filename>org.springframework.security.ldap.authentication</filename> <filename>org.springframework.security.ldap.authentication</filename> implements
implements the bind authentication strategy. It simply attempts to bind as the the bind authentication strategy. It simply attempts to bind as the user.</para>
user.</para>
</section> </section>
<section xml:id="ldap-ldap-authenticators-password"> <section xml:id="ldap-ldap-authenticators-password">
<info> <info>
@ -243,7 +235,7 @@
to be supplied with a <interfacename>SpringSecurityContextSource</interfacename> to be supplied with a <interfacename>SpringSecurityContextSource</interfacename>
which is an extension of Spring LDAP's <interfacename>ContextSource</interfacename>. which is an extension of Spring LDAP's <interfacename>ContextSource</interfacename>.
Unless you have special requirements, you will usually configure a 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 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 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 server (instead of binding anonymously). For more information read the Javadoc for
@ -254,38 +246,37 @@
<info> <info>
<title>LDAP Search Objects</title> <title>LDAP Search Objects</title>
</info> </info>
<para>Often a more complicated strategy than simple DN-matching is required to <para>Often a more complicated strategy than simple DN-matching is required to locate a
locate a user entry in the directory. This can be encapsulated in an user entry in the directory. This can be encapsulated in an
<interfacename>LdapUserSearch</interfacename> instance which can be supplied to <interfacename>LdapUserSearch</interfacename> instance which can be supplied to the
the authenticator implementations, for example, to allow them to locate a user. The authenticator implementations, for example, to allow them to locate a user. The
supplied implementation is <classname>FilterBasedLdapUserSearch</classname>.</para> supplied implementation is <classname>FilterBasedLdapUserSearch</classname>.</para>
<section xml:id="ldap-searchobjects-filter"> <section xml:id="ldap-searchobjects-filter">
<info> <info>
<title xml:id="ldap-searchobjects-filter-based"> <title xml:id="ldap-searchobjects-filter-based">
<classname>FilterBasedLdapUserSearch</classname> <classname>FilterBasedLdapUserSearch</classname> </title>
</title>
</info> </info>
<para>This bean uses an LDAP filter to match the user object in the directory. The <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 process is explained in the Javadoc for the corresponding search method on the
<link xmlns:xlink="http://www.w3.org/1999/xlink" <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)" 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 >JDK DirContext class</link>. As explained there, the search filter can be
supplied with parameters. For this class, the only valid parameter is 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> name.</para>
</section> </section>
</section> </section>
<section xml:id="ldap-authorities"> <section xml:id="ldap-authorities">
<title>LdapAuthoritiesPopulator</title> <title>LdapAuthoritiesPopulator</title>
<para> After authenticating the user successfully, the <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 authorities for the user by calling the configured
<interfacename>LdapAuthoritiesPopulator</interfacename> bean. The <interfacename>LdapAuthoritiesPopulator</interfacename> bean. The
<classname>DefaultLdapAuthoritiesPopulator</classname> is an implementation <classname>DefaultLdapAuthoritiesPopulator</classname> is an implementation which
which will load the authorities by searching the directory for groups of which the will load the authorities by searching the directory for groups of which the user is
user is a member (typically these will be <literal>groupOfNames</literal> or a member (typically these will be <literal>groupOfNames</literal> or
<literal>groupOfUniqueNames</literal> entries in the directory). Consult the <literal>groupOfUniqueNames</literal> entries in the directory). Consult the Javadoc
Javadoc for this class for more details on how it works. </para> 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 <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 difference source (such as a database) then you can provide your own implementation
of this interface and inject that instead.</para> of this interface and inject that instead.</para>
@ -325,14 +316,14 @@
</programlisting> This would set up the provider to access an LDAP server </programlisting> This would set up the provider to access an LDAP server
with URL <literal>ldap://monkeymachine:389/dc=springframework,dc=org</literal>. with URL <literal>ldap://monkeymachine:389/dc=springframework,dc=org</literal>.
Authentication will be performed by attempting to bind with the DN 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 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 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 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> from the <quote>ou</quote> attribute of each match.</para>
<para>To configure a user search object, which uses the filter <para>To configure a user search object, which uses the filter
<literal>(uid=&lt;user-login-name&gt;)</literal> for use instead of the <literal>(uid=&lt;user-login-name&gt;)</literal> for use instead of the DN-pattern
DN-pattern (or in addition to it), you would configure the following bean <programlisting><![CDATA[ (or in addition to it), you would configure the following bean <programlisting><![CDATA[
<bean id="userSearch" <bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value=""/> <constructor-arg index="0" value=""/>
@ -340,40 +331,40 @@
<constructor-arg index="2" ref="contextSource" /> <constructor-arg index="2" ref="contextSource" />
</bean> ]]> </bean> ]]>
</programlisting> and use it by setting the </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 property. The authenticator would then call the search object to obtain the correct
user's DN before attempting to bind as this user.</para> user's DN before attempting to bind as this user.</para>
</section> </section>
<section xml:id="ldap-custom-user-details"> <section xml:id="ldap-custom-user-details">
<title>LDAP Attributes and Customized UserDetails</title> <title>LDAP Attributes and Customized UserDetails</title>
<para> The net result of an authentication using <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 Security authentication using the standard
<interfacename>UserDetailsService</interfacename> interface. A <interfacename>UserDetailsService</interfacename> interface. A
<interfacename>UserDetails</interfacename> object is created and stored in the <interfacename>UserDetails</interfacename> object is created and stored in the
returned <interfacename>Authentication</interfacename> object. As with using a 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, 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 these will normally be attributes from the user entry. The creation of the
<interfacename>UserDetails</interfacename> object is controlled by the <interfacename>UserDetails</interfacename> object is controlled by the provider's
provider's <interfacename>UserDetailsContextMapper</interfacename> strategy, which <interfacename>UserDetailsContextMapper</interfacename> strategy, which is
is responsible for mapping user objects to and from LDAP context data: <programlisting><![CDATA[ responsible for mapping user objects to and from LDAP context data: <programlisting><![CDATA[
public interface UserDetailsContextMapper { public interface UserDetailsContextMapper {
UserDetails mapUserFromContext(DirContextOperations ctx, String username, UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<GrantedAuthority> authorities); Collection<GrantedAuthority> authorities);
void mapUserToContext(UserDetails user, DirContextAdapter ctx); void mapUserToContext(UserDetails user, DirContextAdapter ctx);
}]]> }]]>
</programlisting> Only the first method is relevant for </programlisting> Only the first method is relevant for authentication. If you
authentication. If you provide an implementation of this interface, you can control provide an implementation of this interface, you can control exactly how the
exactly how the UserDetails object is created. The first parameter is an instance of UserDetails object is created. The first parameter is an instance of Spring LDAP's
Spring LDAP's <interfacename>DirContextOperations</interfacename> which gives you <interfacename>DirContextOperations</interfacename> which gives you access to the
access to the LDAP attributes which were loaded. The <literal>username</literal> LDAP attributes which were loaded. The <literal>username</literal> parameter is the
parameter is the name used to authenticate and the final parameter is the collection name used to authenticate and the final parameter is the collection of authorities
of authorities loaded for the user. </para> loaded for the user. </para>
<para> The way the context data is loaded varies slightly depending on the type of <para> The way the context data is loaded varies slightly depending on the type of
authentication you are using. With the <classname>BindAuthenticator</classname>, authentication you are using. With the <classname>BindAuthenticator</classname>, the
the context returned from the bind operation will be used to read the attributes, 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 otherwise the data will be read using the standard context obtained from the
configured <interfacename>ContextSource</interfacename> (when a search is configured configured <interfacename>ContextSource</interfacename> (when a search is configured
to locate the user, this will be the data returned by the search object). </para> 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"?> <?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="preauth" <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="preauth"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<info> <info>
<title>Pre-Authentication Scenarios</title> <title>Pre-Authentication Scenarios</title>
</info> </info>
<para> There are situations where you want to use Spring Security for authorization, but the user <para> There are situations where you want to use Spring Security for authorization, but the
has already been reliably authenticated by some external system prior to accessing 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. 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 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 application is running. When using pre-authentication, Spring Security has to <orderedlist>
<orderedlist><listitem><para>Identify the user making the request. <listitem>
</para></listitem><listitem><para>Obtain the authorities for the <para>Identify the user making the request. </para>
user.</para></listitem></orderedlist>The details will depend on the external authentication </listitem>
mechanism. A user might be identified by their certificate information in the case of X.509, or <listitem>
by an HTTP request header in the case of Siteminder. If relying on container authentication, the <para>Obtain the authorities for the user.</para>
user will be identified by calling the <methodname>getUserPrincipal()</methodname> method on the </listitem>
incoming HTTP request. In some cases, the external mechanism may supply role/authority </orderedlist>The details will depend on the external authentication mechanism. A user might
information for the user but in others the authorities must be obtained from a separate source, be identified by their certificate information in the case of X.509, or by an HTTP request
such as a <interfacename>UserDetailsService</interfacename>. </para> header in the case of Siteminder. If relying on container authentication, the user will be
<section> identified by calling the <methodname>getUserPrincipal()</methodname> method on the incoming
<title>Pre-Authentication Framework Classes</title> HTTP request. In some cases, the external mechanism may supply role/authority information
<para> Because most pre-authentication mechanisms follow the same pattern, Spring Security has a for the user but in others the authorities must be obtained from a separate source, such as
set of classes which provide an internal framework for implementing pre-authenticated a <interfacename>UserDetailsService</interfacename>. </para>
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> <section>
<title>AbstractPreAuthenticatedProcessingFilter</title> <title>Pre-Authentication Framework Classes</title>
<para> This class will check the current contents of the security context and, if empty, it <para> Because most pre-authentication mechanisms follow the same pattern, Spring Security
will attempt to extract user information from the HTTP request and submit it to the has a set of classes which provide an internal framework for implementing
<interfacename>AuthenticationManager</interfacename>. Subclasses override the following pre-authenticated authentication providers. This removes duplication and allows new
methods to obtain this information: implementations to be added in a structured fashion, without having to write everything
<programlisting language="java"> 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 getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request); protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
</programlisting> </programlisting>
After calling these, the filter will create a After calling these, the filter will create a
<classname>PreAuthenticatedAuthenticationToken</classname> containing the returned data <classname>PreAuthenticatedAuthenticationToken</classname> containing the returned
and submit it for authentication. By <quote>authentication</quote> here, we really just mean data and submit it for authentication. By <quote>authentication</quote> here, we
further processing to perhaps load the user's authorities, but the standard Spring Security really just mean further processing to perhaps load the user's authorities, but the
authentication architecture is followed. </para> standard Spring Security authentication architecture is followed. </para>
</section> </section>
<section> <section>
<title>AbstractPreAuthenticatedAuthenticationDetailsSource</title> <title>AbstractPreAuthenticatedAuthenticationDetailsSource</title>
<para> Like other Spring Security authentication filters, the pre-authentication filter has an <para> Like other Spring Security authentication filters, the pre-authentication filter
<literal>authenticationDetailsSource</literal> property which by default will create a has an <literal>authenticationDetailsSource</literal> property which by default will
<classname>WebAuthenticationDetails</classname> object to store additional information create a <classname>WebAuthenticationDetails</classname> object to store additional
such as the session-identifier and originating IP address in the <literal>details</literal> information such as the session-identifier and originating IP address in the
property of the <interfacename>Authentication</interfacename> object. In cases where user <literal>details</literal> property of the
role information can be obtained from the pre-authentication mechanism, the data is also <interfacename>Authentication</interfacename> object. In cases where user role
stored in this property. Subclasses of information can be obtained from the pre-authentication mechanism, the data is also
<classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an extended stored in this property. Subclasses of
details object which implements the <classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an
<interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling the extended details object which implements the
authentication provider to read the authorities which were externally allocated to the user. <interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling
We'll look at a concrete example next. </para> the authentication provider to read the authorities which were externally allocated
<section xml:id="j2ee-preauth-details"> to the user. We'll look at a concrete example next. </para>
<title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title> <section xml:id="j2ee-preauth-details">
<para> If the filter is configured with an <literal>authenticationDetailsSource</literal> <title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title>
which is an instance of this class, the authority information is obtained by calling the <para> If the filter is configured with an
<methodname>isUserInRole(String role)</methodname> method for each of a pre-determined <literal>authenticationDetailsSource</literal> which is an instance of this
set of <quote>mappable roles</quote>. The class gets these from a configured class, the authority information is obtained by calling the
<interfacename>MappableAttributesRetriever</interfacename>. Possible implementations <methodname>isUserInRole(String role)</methodname> method for each of a
include hard-coding a list in the application context and reading the role information pre-determined set of <quote>mappable roles</quote>. The class gets these from a
from the <literal>&lt;security-role&gt;</literal> information in a configured <interfacename>MappableAttributesRetriever</interfacename>. Possible
<filename>web.xml</filename> file. The pre-authentication sample application uses the implementations include hard-coding a list in the application context and
latter approach. </para> reading the role information from the <literal>&lt;security-role&gt;</literal>
<para>There is an additional stage where the roles (or attributes) are mapped to Spring information in a <filename>web.xml</filename> file. The pre-authentication
Security <interfacename>GrantedAuthority</interfacename> objects using a configured sample application uses the latter approach. </para>
<interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>. The default will <para>There is an additional stage where the roles (or attributes) are mapped to
just add the usual <literal>ROLE_</literal> prefix to the names, but it gives you full Spring Security <interfacename>GrantedAuthority</interfacename> objects using a
control over the behaviour. </para> configured <interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>.
</section> The default will just add the usual <literal>ROLE_</literal> prefix to the
</section> names, but it gives you full control over the behaviour. </para>
<section> </section>
<title>PreAuthenticatedAuthenticationProvider</title> </section>
<para> The pre-authenticated provider has little more to do than load the <section>
<interfacename>UserDetails</interfacename> object for the user. It does this by delegating <title>PreAuthenticatedAuthenticationProvider</title>
to a <interfacename>AuthenticationUserDetailsService</interfacename>. The latter is similar <para> The pre-authenticated provider has little more to do than load the
to the standard <interfacename>UserDetailsService</interfacename> but takes an <interfacename>UserDetails</interfacename> object for the user. It does this by
<interfacename>Authentication</interfacename> object rather than just user name: delegating to a <interfacename>AuthenticationUserDetailsService</interfacename>. The
<programlisting language="java"> 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 { public interface AuthenticationUserDetailsService {
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException; UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
} }
</programlisting> </programlisting>
This interface may have also other uses but with pre-authentication it allows access to the This interface may have also other uses but with pre-authentication it allows access
authorities which were packaged in the <interfacename>Authentication</interfacename> object, to the authorities which were packaged in the
as we saw in the previous section. The <interfacename>Authentication</interfacename> object, as we saw in the previous
<classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class does section. The
this. Alternatively, it may delegate to a standard <classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class
<interfacename>UserDetailsService</interfacename> via the does this. Alternatively, it may delegate to a standard
<classname>UserDetailsByNameServiceWrapper</classname> implementation. </para> <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>
<section> <section>
<title>Http403ForbiddenEntryPoint</title> <title>Concrete Implementations</title>
<para> The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the <link <para> X.509 authentication is covered in its <link xlink:href="#x509">own chapter</link>.
xlink:href="#tech-intro-auth-entry-point">technical overview</link> chapter. Normally it Here we'll look at some classes which provide support for other pre-authenticated
is responsible for kick-starting the authentication process for an unauthenticated user scenarios. </para>
(when they try to access a protected resource), but in the pre-authenticated case this <section>
doesn't apply. You would only configure the <title>Request-Header Authentication (Siteminder)</title>
<classname>ExceptionTranslationFilter</classname> with an instance of this class if you <para> An external authentication system may supply information to the application by
aren't using pre-authentication in combination with other authentication mechanisms. It will setting specific headers on the HTTP request. A well known example of this is
be called if the user is rejected by the Siteminder, which passes the username in a header called <literal>SM_USER</literal>.
<classname>AbstractPreAuthenticatedProcessingFilter</classname> resulting in a null This mechanism is supported by the class
authentication. It always returns a <literal>403</literal>-forbidden response code if <classname>RequestHeaderAuthenticationFilter</classname> which simply extracts the
called. </para> username from the header. It defaults to using the name <literal>SM_USER</literal>
</section> as the header name. See the Javadoc for more details. </para>
</section> <tip>
<section> <para>Note that when using a system like this, the framework performs no
<title>Concrete Implementations</title> authentication checks at all and it is <emphasis>extremely</emphasis> important
<para> X.509 authentication is covered in its <link xlink:href="#x509">own chapter</link>. Here that the external system is configured properly and protects all access to the
we'll look at some classes which provide support for other pre-authenticated scenarios. </para> application. If an attacker is able to forge the headers in their original
<section> request without this being detected then they could potentially choose any
<title>Request-Header Authentication (Siteminder)</title> username they wished. </para>
<para> An external authentication system may supply information to the application by setting </tip>
specific headers on the HTTP request. A well known example of this is Siteminder, which <section>
passes the username in a header called <literal>SM_USER</literal>. This mechanism is <title>Siteminder Example Configuration</title>
supported by the class <classname>RequestHeaderAuthenticationFilter</classname> which simply <para> A typical configuration using this filter would look like this: <programlisting><![CDATA[
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> <security:http>
<!-- Additional http configuration omitted --> <!-- Additional http configuration omitted -->
<security:custom-filter ref="siteminderFilter" /> <security:custom-filter ref="siteminderFilter" />
@ -162,27 +174,28 @@ class="org.springframework.security.web.authentication.preauth.PreAuthenticatedA
<security:authentication-provider ref="preauthAuthProvider" /> <security:authentication-provider ref="preauthAuthProvider" />
</security-authentication-manager> </security-authentication-manager>
]]> ]]>
</programlisting> We've assumed here that the security namespace is being used for </programlisting> We've assumed here that the security namespace is being used for configuration
configuration (hence the user of the <literal>custom-filter</literal>, (hence the user of the <literal>custom-filter</literal>,
<literal>authentication-manager</literal> and <literal>authentication-manager</literal> and
<literal>custom-authentication-provider</literal> elements (you can read more about them <literal>custom-authentication-provider</literal> elements (you can read more
in the <link xlink:href="ns-config">namespace chapter</link>). You would leave these out about them in the <link xlink:href="ns-config">namespace chapter</link>). You
of a traditional bean configuration. It's also assumed that you have added a would leave these out of a traditional bean configuration. It's also assumed
<interfacename>UserDetailsService</interfacename> (called that you have added a <interfacename>UserDetailsService</interfacename> (called
<quote>userDetailsService</quote>) to your configuration to load the user's roles. <quote>userDetailsService</quote>) to your configuration to load the user's
</para> roles. </para>
</section> </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>
<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> </chapter>

View File

@ -15,11 +15,10 @@
One uses hashing to preserve the security of cookie-based tokens and the other uses a 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> database or other persistent storage mechanism to store the generated tokens. </para>
<para> Note that both implemementations require a <para> Note that both implemementations require a
<interfacename>UserDetailsService</interfacename>. If you are using an <interfacename>UserDetailsService</interfacename>. If you are using an authentication
authentication provider which doesn't use a provider which doesn't use a <interfacename>UserDetailsService</interfacename> (for
<interfacename>UserDetailsService</interfacename> (for example, the LDAP provider) example, the LDAP provider) then it won't work unless you also have a
then it won't work unless you also have a <interfacename>UserDetailsService</interfacename> bean in your application context.
<interfacename>UserDetailsService</interfacename> bean in your application context.
</para> </para>
</section> </section>
<section xml:id="remember-me-hash-token"> <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 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> 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 <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[ authentication just by adding the <literal>&lt;remember-me&gt;</literal> element: <programlisting><![CDATA[
<http> <http>
... ...
@ -56,26 +55,27 @@
</programlisting> The <interfacename>UserDetailsService</interfacename> will </programlisting> The <interfacename>UserDetailsService</interfacename> will
normally be selected automatically. If you have more than one in your application 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 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 <literal>user-service-ref</literal> attribute, where the value is the name of your
<interfacename>UserDetailsService</interfacename> bean. </para> <interfacename>UserDetailsService</interfacename> bean. </para>
</section> </section>
<section xml:id="remember-me-persistent-token"> <section xml:id="remember-me-persistent-token">
<title>Persistent Token Approach</title> <title>Persistent Token Approach</title>
<para>This approach is based on the article <link <para>This approach is based on the article <link
xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice" xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice"
>http://jaspan.com/improved_persistent_login_cookie_best_practice</link> with some >http://jaspan.com/improved_persistent_login_cookie_best_practice</link> with some minor
minor modifications <footnote><para>Essentially, the username is not included in the modifications <footnote>
cookie, to prevent exposing a valid login name unecessarily. There is a <para>Essentially, the username is not included in the cookie, to prevent exposing a
discussion on this in the comments section of this article.</para></footnote>. valid login name unecessarily. There is a discussion on this in the comments section
To use the this approach with namespace configuration, you would supply a datasource of this article.</para>
reference: <programlisting><![CDATA[ </footnote>. To use the this approach with namespace configuration, you would supply a
datasource reference: <programlisting><![CDATA[
<http> <http>
... ...
<remember-me data-source-ref="someDataSource"/> <remember-me data-source-ref="someDataSource"/>
</http> </http>
]]> ]]>
</programlisting> The database should contain a </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): equivalent):
<programlisting> <programlisting>
create table persistent_logins (username varchar(64) not null, create table persistent_logins (username varchar(64) not null,
@ -91,10 +91,10 @@
</info> </info>
<para>Remember-me authentication is not used with basic authentication, given it is often <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 not used with <literal>HttpSession</literal>s. Remember-me is used with
<literal>UsernamePasswordAuthenticationFilter</literal>, and is implemented via <literal>UsernamePasswordAuthenticationFilter</literal>, and is implemented via hooks in
hooks in the <literal>AbstractAuthenticationProcessingFilter</literal> superclass. The the <literal>AbstractAuthenticationProcessingFilter</literal> superclass. The hooks will
hooks will invoke a concrete <interfacename>RememberMeServices</interfacename> at the invoke a concrete <interfacename>RememberMeServices</interfacename> at the appropriate
appropriate times. The interface looks like this: times. The interface looks like this:
<programlisting language="java"> <programlisting language="java">
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response); Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response); void loginFail(HttpServletRequest request, HttpServletResponse response);
@ -105,9 +105,9 @@
note at this stage that <literal>AbstractAuthenticationProcessingFilter</literal> only note at this stage that <literal>AbstractAuthenticationProcessingFilter</literal> only
calls the <literal>loginFail()</literal> and <literal>loginSuccess()</literal> methods. calls the <literal>loginFail()</literal> and <literal>loginSuccess()</literal> methods.
The <literal>autoLogin()</literal> method is called by The <literal>autoLogin()</literal> method is called by
<classname>RememberMeAuthenticationFilter</classname> whenever the <classname>RememberMeAuthenticationFilter</classname> whenever the
<classname>SecurityContextHolder</classname> does not contain an <classname>SecurityContextHolder</classname> does not contain an
<interfacename>Authentication</interfacename>. This interface therefore provides the <interfacename>Authentication</interfacename>. This interface therefore provides the
underlying remember-me implementation with sufficient notification of underlying remember-me implementation with sufficient notification of
authentication-related events, and delegates to the implementation whenever a candidate 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 web request might contain a cookie and wish to be remembered. This design allows any
@ -116,18 +116,18 @@
<section> <section>
<title>TokenBasedRememberMeServices</title> <title>TokenBasedRememberMeServices</title>
<para> This implementation supports the simpler approach described in <xref <para> This implementation supports the simpler approach described in <xref
linkend="remember-me-hash-token"/>. linkend="remember-me-hash-token"/>.
<classname>TokenBasedRememberMeServices</classname> generates a <classname>TokenBasedRememberMeServices</classname> generates a
<literal>RememberMeAuthenticationToken</literal>, which is processed by <literal>RememberMeAuthenticationToken</literal>, which is processed by
<literal>RememberMeAuthenticationProvider</literal>. A <literal>key</literal> is <literal>RememberMeAuthenticationProvider</literal>. A <literal>key</literal> is
shared between this authentication provider and the shared between this authentication provider and the
<literal>TokenBasedRememberMeServices</literal>. In addition, <literal>TokenBasedRememberMeServices</literal>. In addition,
<literal>TokenBasedRememberMeServices</literal> requires A UserDetailsService <literal>TokenBasedRememberMeServices</literal> requires A UserDetailsService from
from which it can retrieve the username and password for signature comparison which it can retrieve the username and password for signature comparison purposes,
purposes, and generate the <literal>RememberMeAuthenticationToken</literal> to and generate the <literal>RememberMeAuthenticationToken</literal> to contain the
contain the correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of logout
logout command should be provided by the application that invalidates the cookie if command should be provided by the application that invalidates the cookie if the
the user requests this. <classname>TokenBasedRememberMeServices</classname> also user requests this. <classname>TokenBasedRememberMeServices</classname> also
implements Spring Security's <interfacename>LogoutHandler</interfacename> interface implements Spring Security's <interfacename>LogoutHandler</interfacename> interface
so can be used with <classname>LogoutFilter</classname> to have the cookie cleared so can be used with <classname>LogoutFilter</classname> to have the cookie cleared
automatically. </para> automatically. </para>
@ -151,26 +151,30 @@
</bean> </bean>
]]> ]]>
</programlisting>Don't forget to add your </programlisting>Don't forget to add your
<interfacename>RememberMeServices</interfacename> implementation to your <interfacename>RememberMeServices</interfacename> implementation to your
<literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal> <literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal>
property, include the <literal>RememberMeAuthenticationProvider</literal> in your property, include the <literal>RememberMeAuthenticationProvider</literal> in your
<literal>AuthenticationManager.setProviders()</literal> list, and add <literal>AuthenticationManager.setProviders()</literal> list, and add
<classname>RememberMeAuthenticationFilter</classname> into your <classname>RememberMeAuthenticationFilter</classname> into your
<classname>FilterChainProxy</classname> (typically immediately after your <classname>FilterChainProxy</classname> (typically immediately after your
<literal>UsernamePasswordAuthenticationFilter</literal>).</para> <literal>UsernamePasswordAuthenticationFilter</literal>).</para>
</section> </section>
<section> <section>
<title>PersistentTokenBasedRememberMeServices</title> <title>PersistentTokenBasedRememberMeServices</title>
<para> This class can be used in the same way as <para> This class can be used in the same way as
<classname>TokenBasedRememberMeServices</classname>, but it additionally needs <classname>TokenBasedRememberMeServices</classname>, but it additionally needs to be
to be configured with a <interfacename>PersistentTokenRepository</interfacename> to configured with a <interfacename>PersistentTokenRepository</interfacename> to store
store the tokens. There are two standard implementations. the tokens. There are two standard implementations. <itemizedlist>
<itemizedlist><listitem><para><classname>InMemoryTokenRepositoryImpl</classname> <listitem>
which is intended for testing <para><classname>InMemoryTokenRepositoryImpl</classname> which is intended for
only.</para></listitem><listitem><para><classname>JdbcTokenRepositoryImpl</classname> testing only.</para>
which stores the tokens in a database. </para></listitem></itemizedlist> </listitem>
The database schema is described above in <xref <listitem>
linkend="remember-me-persistent-token"/>. </para> <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>
</section> </section>
</chapter> </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"> <section xml:id="runas-overview">
<info><title>Overview</title></info> <info>
<title>Overview</title>
</info>
<para>The <classname>AbstractSecurityInterceptor</classname> is able to <para>The <classname>AbstractSecurityInterceptor</classname> is able to temporarily replace
temporarily replace the <interfacename>Authentication</interfacename> object in the <interfacename>Authentication</interfacename> object in the
the <interfacename>SecurityContext</interfacename> and <interfacename>SecurityContext</interfacename> and
<classname>SecurityContextHolder</classname> during the secure object <classname>SecurityContextHolder</classname> during the secure object callback phase.
callback phase. This only occurs if the original This only occurs if the original <interfacename>Authentication</interfacename> object
<interfacename>Authentication</interfacename> object was successfully processed by was successfully processed by the <interfacename>AuthenticationManager</interfacename>
the <interfacename>AuthenticationManager</interfacename> and and <interfacename>AccessDecisionManager</interfacename>. The
<interfacename>AccessDecisionManager</interfacename>. The
<literal>RunAsManager</literal> will indicate the replacement <literal>RunAsManager</literal> will indicate the replacement
<interfacename>Authentication</interfacename> object, if any, that should be used <interfacename>Authentication</interfacename> object, if any, that should be used during
during the <literal>SecurityInterceptorCallback</literal>.</para> the <literal>SecurityInterceptorCallback</literal>.</para>
<para>By temporarily replacing the <interfacename>Authentication</interfacename> <para>By temporarily replacing the <interfacename>Authentication</interfacename> object
object during the secure object callback phase, the secured invocation during the secure object callback phase, the secured invocation will be able to call
will be able to call other objects which require different other objects which require different authentication and authorization credentials. It
authentication and authorization credentials. It will also be able to will also be able to perform any internal security checks for specific
perform any internal security checks for specific
<interfacename>GrantedAuthority</interfacename> objects. Because Spring Security <interfacename>GrantedAuthority</interfacename> objects. Because Spring Security
provides a number of helper classes that automatically configure provides a number of helper classes that automatically configure remoting protocols
remoting protocols based on the contents of the based on the contents of the <classname>SecurityContextHolder</classname>, these run-as
<classname>SecurityContextHolder</classname>, these run-as replacements replacements are particularly useful when calling remote web services</para>
are particularly useful when calling remote web services</para>
</section> </section>
<section xml:id="runas-config"> <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: <para>A <literal>RunAsManager</literal> interface is provided by Spring Security:
<programlisting> <programlisting>
Authentication buildRunAs(Authentication authentication, Object object, Authentication buildRunAs(Authentication authentication, Object object,
List&lt;ConfigAttribute&gt; config); List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute); boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz); boolean supports(Class clazz);
</programlisting> </programlisting> </para>
</para>
<para>The first method returns the <interfacename>Authentication</interfacename> <para>The first method returns the <interfacename>Authentication</interfacename> object that
object that should replace the existing should replace the existing <interfacename>Authentication</interfacename> object for the
<interfacename>Authentication</interfacename> object for the duration of the duration of the method invocation. If the method returns <literal>null</literal>, it
method invocation. If the method returns <literal>null</literal>, it indicates no replacement should be made. The second method is used by the
indicates no replacement should be made. The second method is used by <classname>AbstractSecurityInterceptor</classname> as part of its startup validation of
the <classname>AbstractSecurityInterceptor</classname> as part of its configuration attributes. The <literal>supports(Class)</literal> method is called by a
startup validation of configuration attributes. The security interceptor implementation to ensure the configured
<literal>supports(Class)</literal> method is called by a security <literal>RunAsManager</literal> supports the type of secure object that the security
interceptor implementation to ensure the configured interceptor will present.</para>
<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> <para>One concrete implementation of a <literal>RunAsManager</literal> is provided with
is provided with Spring Security. The Spring Security. The <literal>RunAsManagerImpl</literal> class returns a replacement
<literal>RunAsManagerImpl</literal> class returns a replacement <literal>RunAsUserToken</literal> if any <literal>ConfigAttribute</literal> starts with
<literal>RunAsUserToken</literal> if any <literal>RUN_AS_</literal>. If any such <literal>ConfigAttribute</literal> is found, the
<literal>ConfigAttribute</literal> starts with replacement <literal>RunAsUserToken</literal> will contain the same principal,
<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 credentials and granted authorities as the original
<interfacename>Authentication</interfacename> object, along with a new <interfacename>Authentication</interfacename> object, along with a new
<literal>GrantedAuthorityImpl</literal> for each <literal>GrantedAuthorityImpl</literal> for each <literal>RUN_AS_</literal>
<literal>RUN_AS_</literal> <literal>ConfigAttribute</literal>. Each <literal>ConfigAttribute</literal>. Each new <literal>GrantedAuthorityImpl</literal>
new <literal>GrantedAuthorityImpl</literal> will be prefixed with will be prefixed with <literal>ROLE_</literal>, followed by the
<literal>ROLE_</literal>, followed by the <literal>RUN_AS</literal> <literal>RUN_AS</literal> <literal>ConfigAttribute</literal>. For example, a
<literal>ConfigAttribute</literal>. For example, a
<literal>RUN_AS_SERVER</literal> will result in the replacement <literal>RUN_AS_SERVER</literal> will result in the replacement
<literal>RunAsUserToken</literal> containing a <literal>RunAsUserToken</literal> containing a <literal>ROLE_RUN_AS_SERVER</literal>
<literal>ROLE_RUN_AS_SERVER</literal> granted authority.</para> granted authority.</para>
<para>The replacement <literal>RunAsUserToken</literal> is just like <para>The replacement <literal>RunAsUserToken</literal> is just like any other
any other <interfacename>Authentication</interfacename> object. It needs to be <interfacename>Authentication</interfacename> object. It needs to be authenticated by
authenticated by the <interfacename>AuthenticationManager</interfacename>, the <interfacename>AuthenticationManager</interfacename>, probably via delegation to a
probably via delegation to a suitable suitable <classname>AuthenticationProvider</classname>. The
<classname>AuthenticationProvider</classname>. The <literal>RunAsImplAuthenticationProvider</literal> performs such authentication. It
<literal>RunAsImplAuthenticationProvider</literal> performs such simply accepts as valid any <literal>RunAsUserToken</literal> presented.</para>
authentication. It simply accepts as valid any
<literal>RunAsUserToken</literal> presented.</para>
<para>To ensure malicious code does not create a <para>To ensure malicious code does not create a <literal>RunAsUserToken</literal> and
<literal>RunAsUserToken</literal> and present it for guaranteed present it for guaranteed acceptance by the
acceptance by the <literal>RunAsImplAuthenticationProvider</literal>, <literal>RunAsImplAuthenticationProvider</literal>, the hash of a key is stored in all
the hash of a key is stored in all generated tokens. The generated tokens. The <literal>RunAsManagerImpl</literal> and
<literal>RunAsManagerImpl</literal> and <literal>RunAsImplAuthenticationProvider</literal> is created in the bean context with
<literal>RunAsImplAuthenticationProvider</literal> is created in the the same key: <programlisting>
bean context with the same key:
<programlisting>
<![CDATA[ <![CDATA[
<bean id="runAsManager" <bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl"> class="org.springframework.security.access.intercept.RunAsManagerImpl">
@ -97,10 +89,9 @@
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider"> class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
<property name="key" value="my_run_as_password"/> <property name="key" value="my_run_as_password"/>
</bean>]]></programlisting></para> </bean>]]></programlisting></para>
<para>By using the same key, each <literal>RunAsUserToken</literal> <para>By using the same key, each <literal>RunAsUserToken</literal> can be validated it was
can be validated it was created by an approved created by an approved <literal>RunAsManagerImpl</literal>. The
<literal>RunAsManagerImpl</literal>. The <literal>RunAsUserToken</literal> is immutable after creation for security
<literal>RunAsUserToken</literal> is immutable after creation for reasons</para>
security reasons</para>
</section> </section>
</chapter> </chapter>

View File

@ -9,23 +9,23 @@
files individually from the central Maven repository. We'd recommend the former. You can get 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 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 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/"> <link xlink:href="http://www.springsource.org/security/">
http://www.springsource.org/security/ </link> if you need it. All paths referred to in http://www.springsource.org/security/ </link> if you need it. All paths referred to in this
this chapter are relative to the project source directory. </para> chapter are relative to the project source directory. </para>
<section xml:id="tutorial-sample"> <section xml:id="tutorial-sample">
<title>Tutorial Sample</title> <title>Tutorial Sample</title>
<para> The tutorial sample is a nice basic example to get you started. It uses simple <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 namespace configuration throughout. The compiled application is included in the
distribution zip file, ready to be deployed into your web container distribution zip file, ready to be deployed into your web container
(<filename>spring-security-samples-tutorial-3.0.x.war</filename>). The <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 xlink:href="#ns-form-and-basic">form-based</link> authentication mechanism is used in
in combination with the commonly-used <link xlink:href="#remember-me">remember-me</link> combination with the commonly-used <link xlink:href="#remember-me">remember-me</link>
authentication provider to automatically remember the login using cookies.</para> 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 <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 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 <literal>web.xml</literal> entries) to your existing application. Only when this basic
basic integration is achieved do we suggest you attempt adding in method authorization integration is achieved do we suggest you attempt adding in method authorization or
or domain object security.</para> domain object security.</para>
</section> </section>
<section xml:id="contacts-sample"> <section xml:id="contacts-sample">
<title>Contacts</title> <title>Contacts</title>
@ -35,11 +35,11 @@
administer a simple database of contacts (the domain objects).</para> administer a simple database of contacts (the domain objects).</para>
<para>To deploy, simply copy the WAR file from Spring Security distribution into your <para>To deploy, simply copy the WAR file from Spring Security distribution into your
containers <literal>webapps</literal> directory. The war should be called containers <literal>webapps</literal> directory. The war should be called
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended <filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended version
version number will vary depending on what release you are using). </para> number will vary depending on what release you are using). </para>
<para>After starting your container, check the application can load. Visit <para>After starting your container, check the application can load. Visit
<literal>http://localhost:8080/contacts</literal> (or whichever URL is appropriate <literal>http://localhost:8080/contacts</literal> (or whichever URL is appropriate for
for your web container and the WAR you deployed). </para> your web container and the WAR you deployed). </para>
<para>Next, click "Debug". You will be prompted to authenticate, and a series of usernames <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 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: 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 <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 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 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. <literal>ROLE_SUPERVISOR</literal> are granted access to delete their contacts. Behind
Behind the scenes, the <classname>MethodSecurityInterceptor</classname> is securing the the scenes, the <classname>MethodSecurityInterceptor</classname> is securing the
business objects. </para> business objects. </para>
<para>The application allows you to modify the access control lists associated with <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 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> <title>CAS Sample</title>
<para> The CAS sample requires that you run both a CAS server and CAS client. It isn't <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 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 <link xlink:href="get-source">the introduction</link>. You'll find the relevant files
files under the <filename>sample/cas</filename> directory. There's also a 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 <filename>Readme.txt</filename> file in there which explains how to run both the server
server and the client directly from the source tree, complete with SSL support. You have and the client directly from the source tree, complete with SSL support. You have to
to download the CAS Server web application (a war file) from the CAS site and drop it download the CAS Server web application (a war file) from the CAS site and drop it into
into the <filename>samples/cas/server</filename> directory. </para> the <filename>samples/cas/server</filename> directory. </para>
</section> </section>
<section xml:id="preauth-sample"> <section xml:id="preauth-sample">
<title>Pre-Authentication Sample</title> <title>Pre-Authentication Sample</title>
<para> This sample application demonstrates how to wire up beans from the <link <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 information from a J2EE container. The user name and roles are those setup by the
container. </para> container. </para>
<para> The code is in <filename>samples/preauth</filename>. </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" <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Secure Object Implementations</title>
</info>
<section xml:id="aop-alliance">
<info> <info>
<title>AOP Alliance (MethodInvocation) Security Interceptor</title> <title>Secure Object Implementations</title>
</info> </info>
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed <section xml:id="aop-alliance">
quite a lot of boiler plate configuration. Now the recommended approach for method security is <info>
to use <link xlink:href="#ns-method-security">namespace configuration</link>. This way the <title>AOP Alliance (MethodInvocation) Security Interceptor</title>
method security infrastructure beans are configured automatically for you so you don't really </info>
need to know about the implementation classes. We'll just provide a quick overview of the <para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s
classes that are involved here. </para> needed quite a lot of boiler plate configuration. Now the recommended approach for
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>, method security is to use <link xlink:href="#ns-method-security">namespace
which secures <classname>MethodInvocation</classname>s. Depending on the configuration configuration</link>. This way the method security infrastructure beans are configured
approach, an interceptor may be specific to a single bean or shared between multiple beans. automatically for you so you don't really need to know about the implementation classes.
The interceptor uses a <interfacename>MethodSecurityMetadataSource</interfacename> instance to We'll just provide a quick overview of the classes that are involved here. </para>
obtain the configuration attributes that apply to a particular method invocation. <para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
<classname>MapBasedMethodSecurityMetadataSource</classname> is used to store configuration which secures <classname>MethodInvocation</classname>s. Depending on the configuration
attributes keyed by method names (which can be wildcarded) and will be used internally when approach, an interceptor may be specific to a single bean or shared between multiple
the attributes are defined in the application context using the beans. The interceptor uses a
<literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal> <interfacename>MethodSecurityMetadataSource</interfacename> instance to obtain the
elements. Other implementations will be used to handle annotation-based configuration. </para> configuration attributes that apply to a particular method invocation.
<section> <classname>MapBasedMethodSecurityMetadataSource</classname> is used to store
<title>Explicit MethodSecurityInterceptor Configuration</title> configuration attributes keyed by method names (which can be wildcarded) and will be
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname> directly used internally when the attributes are defined in the application context using the
in your application context for use with one of Spring AOP's proxying mechanisms: <programlisting><![CDATA[ <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= <bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor"> "org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationManager" ref="authenticationManager"/>
@ -40,26 +42,27 @@
</property> </property>
</bean> ]]> </bean> ]]>
</programlisting></para> </programlisting></para>
</section>
</section> </section>
</section> <section xml:id="aspectj">
<section xml:id="aspectj"> <info>
<info> <title>AspectJ (JoinPoint) Security Interceptor</title>
<title>AspectJ (JoinPoint) Security Interceptor</title> </info>
</info> <para>The AspectJ security interceptor is very similar to the AOP Alliance security
<para>The AspectJ security interceptor is very similar to the AOP Alliance security interceptor interceptor discussed in the previous section. Indeed we will only discuss the
discussed in the previous section. Indeed we will only discuss the differences in this differences in this section.</para>
section.</para> <para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike the the AOP Alliance security interceptor, which relies on the Spring application context to
AOP Alliance security interceptor, which relies on the Spring application context to weave in weave in the security interceptor via proxying, the
the security interceptor via proxying, the <literal>AspectJSecurityInterceptor</literal> is <literal>AspectJSecurityInterceptor</literal> is weaved in via the AspectJ compiler. It
weaved in via the AspectJ compiler. It would not be uncommon to use both types of security would not be uncommon to use both types of security interceptors in the same
interceptors in the same application, with <literal>AspectJSecurityInterceptor</literal> being application, with <literal>AspectJSecurityInterceptor</literal> being used for domain
used for domain object instance security and the AOP Alliance object instance security and the AOP Alliance
<classname>MethodSecurityInterceptor</classname> being used for services layer <classname>MethodSecurityInterceptor</classname> being used for services layer
security.</para> security.</para>
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is configured <para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is
in the Spring application context:</para> configured in the Spring application context:</para>
<programlisting><![CDATA[ <programlisting><![CDATA[
<bean id="bankManagerSecurity" class= <bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor"> "org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationManager" ref="authenticationManager"/>
@ -72,18 +75,18 @@
</value> </value>
</property> </property>
</bean>]]> </programlisting> </bean>]]> </programlisting>
<para>As you can see, aside from the class name, the <para>As you can see, aside from the class name, the
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance <literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
security interceptor. Indeed the two interceptors can share the same security interceptor. Indeed the two interceptors can share the same
<literal>securityMetadataSource</literal>, as the <literal>securityMetadataSource</literal>, as the
<interfacename>SecurityMetadataSource</interfacename> works with <interfacename>SecurityMetadataSource</interfacename> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class. Of <literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class.
course, your access decisions have access to the relevant AOP library-specific invocation (ie Of course, your access decisions have access to the relevant AOP library-specific
<classname>MethodInvocation</classname> or <literal>JoinPoint</literal>) and as such can invocation (ie <classname>MethodInvocation</classname> or <literal>JoinPoint</literal>)
consider a range of addition criteria when making access decisions (such as method and as such can consider a range of addition criteria when making access decisions (such
arguments).</para> as method arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para> <para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
<programlisting language="java"> <programlisting language="java">
package org.springframework.security.samples.aspectj; package org.springframework.security.samples.aspectj;
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor; import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
@ -126,25 +129,26 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
} }
} }
</programlisting> </programlisting>
<para>In the above example, the security interceptor will be applied to every instance of <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 <literal>PersistableEntity</literal>, which is an abstract class not shown (you can use
other class or <literal>pointcut</literal> expression you like). For those curious, any other class or <literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal> <literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
statement has special meaning only within an <literal>around()</literal> body. The statement has special meaning only within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous <literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target object to continue.</para> <literal>AspectJCallback</literal> class when it wants the target object to
<para>You will need to configure Spring to load the aspect and wire it with the continue.</para>
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is <para>You will need to configure Spring to load the aspect and wire it with the
shown below:</para> <literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
<programlisting><![CDATA[ shown below:</para>
<programlisting><![CDATA[
<bean id="domainObjectInstanceSecurityAspect" <bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect" class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf"> factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/> <property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>]]> </bean>]]>
</programlisting> </programlisting>
<para>That's it! Now you can create your beans from anywhere within your application, using <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 whatever means you think fit (eg <literal>new Person();</literal>) and they will have
security interceptor applied.</para> the security interceptor applied.</para>
</section> </section>
</chapter> </chapter>

View File

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

View File

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

View File

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

View File

@ -14,15 +14,15 @@
<title>The <literal>authorize</literal> Tag</title> <title>The <literal>authorize</literal> Tag</title>
<para> This tag is used to determine whether its contents should be evaluated or not. In <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> 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 <para>The legacy options from Spring Security 2.0 are also supported, but
discouraged.</para> discouraged.</para>
</footnote>. The first approach uses a <link xlink:href="el-access-we">web-security </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. expression</link>, specified in the <literal>access</literal> attribute of the tag. The
The expression evaluation will be delegated to the expression evaluation will be delegated to the
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the <interfacename>WebSecurityExpressionHandler</interfacename> defined in the application
application context (you should have web expressions enabled in your context (you should have web expressions enabled in your <literal>&lt;http></literal>
<literal>&lt;http></literal> namespace configuration to make sure this service is namespace configuration to make sure this service is available). So, for example, you
available). So, for example, you might might
have<programlisting>&lt;sec:authorize access="hasRole('supervisor')"> have<programlisting>&lt;sec:authorize access="hasRole('supervisor')">
This content will only be visible to users who have 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 &lt;/sec:authorize></programlisting>To
use this tag there must also be an instance of 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 context. If you are using the namespace, one will automatically be registered. This is
an instance of <classname>DefaultWebInvocationPrivilegeEvaluator</classname>, which an instance of <classname>DefaultWebInvocationPrivilegeEvaluator</classname>, which
creates a dummy web request for the supplied URL and invokes the security interceptor to 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> <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 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 the JSP. So, for example, if the <literal>principal</literal> property of the
<interfacename>Authentication</interfacename> is an instance of Spring Security's <interfacename>Authentication</interfacename> is an instance of Spring Security's
<interfacename>UserDetails</interfacename> object, then using <interfacename>UserDetails</interfacename> object, then using
<literal>&lt;sec:authentication property="principal.username" /></literal> will <literal>&lt;sec:authentication property="principal.username" /></literal> will render
render the name of the current user.</para> 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 <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 prefer to keep as little logic as possible in the view. You can access the
<interfacename>Authentication</interfacename> object in your MVC controller (by <interfacename>Authentication</interfacename> object in your MVC controller (by calling
calling <code>SecurityContextHolder.getContext().getAuthentication()</code>) and add the <code>SecurityContextHolder.getContext().getAuthentication()</code>) and add the data
data directly to your model for rendering by the view.</para> directly to your model for rendering by the view.</para>
</section> </section>
<section> <section>
<title>The <literal>accesscontrollist</literal> Tag</title> <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> &lt;/sec:accesscontrollist></programlisting></para>
<para>The permissions are passed to the <interfacename>PermissionFactory</interfacename> <para>The permissions are passed to the <interfacename>PermissionFactory</interfacename>
defined in the application context, converting them to ACL defined in the application context, converting them to ACL
<interfacename>Permission</interfacename> instances, so they may be any format which <interfacename>Permission</interfacename> instances, so they may be any format which is
is supported by the factory - they don't have to be integers, they could be strings like 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 <literal>READ</literal> or <literal>WRITE</literal>. If no
<interfacename>PermissionFactory</interfacename> is found, an instance of <interfacename>PermissionFactory</interfacename> is found, an instance of
<classname>DefaultPermissionFactory</classname> will be used. The <classname>DefaultPermissionFactory</classname> will be used. The
<interfacename>AclService</interfacename>from the application context will be used <interfacename>AclService</interfacename>from the application context will be used to
to load the <interfacename>Acl</interfacename> instance for the supplied object. The load the <interfacename>Acl</interfacename> instance for the supplied object. The
<interfacename>Acl</interfacename> will be invoked with the required permissions to <interfacename>Acl</interfacename> will be invoked with the required permissions to
check if any of them are granted.</para> check if any of them are granted.</para>
</section> </section>
</chapter> </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" <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<info> <info>
<title>Web Application Infrastructure</title> <title>Web Application Infrastructure</title>
</info> </info>
<section xml:id="filters"> <section xml:id="filters">
<title>The Security Filter Chain</title> <title>The Security Filter Chain</title>
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It <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 doesn't use servlets or any other servlet-based frameworks (such as Spring MVC)
it has no strong links to any particular web technology. It deals in internally, so it has no strong links to any particular web technology. It deals in
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s <classname>HttpServletRequest</classname>s and
and doesn't care whether the requests come from a browser, a web service client, an <classname>HttpServletResponse</classname>s and doesn't care whether the requests come
<classname>HttpInvoker</classname> or an AJAX application. </para> from a browser, a web service client, an <classname>HttpInvoker</classname> or an AJAX
<para> Spring Security maintains a filter chain internally where each of the filters has a application. </para>
particular responsibility and filters are added or removed from the configuration depending on <para> Spring Security maintains a filter chain internally where each of the filters has a
which services are required. The ordering of the filters is important as there are particular responsibility and filters are added or removed from the configuration
dependencies between them. If you have been using <link xlink:href="#ns-config">namespace depending on which services are required. The ordering of the filters is important as
configuration</link>, then the filters are automatically configured for you and you don't there are dependencies between them. If you have been using <link
have to define any Spring beans explicitly but here may be times when you want full control xlink:href="#ns-config">namespace configuration</link>, then the filters are
over the security filter chain, either because you are using features which aren't supported automatically configured for you and you don't have to define any Spring beans
in the namespace, or you are using your own customized versions of classes.</para> explicitly but here may be times when you want full control over the security filter
<section xml:id="delegating-filter-proxy"> chain, either because you are using features which aren't supported in the namespace, or
<title><classname>DelegatingFilterProxy</classname></title> you are using your own customized versions of classes.</para>
<para> When using servlet filters, you obviously need to declare them in your <section xml:id="delegating-filter-proxy">
<filename>web.xml</filename>, or they will be ignored by the servlet container. In Spring <title><classname>DelegatingFilterProxy</classname></title>
Security, the filter classes are also Spring beans defined in the application context and <para> When using servlet filters, you obviously need to declare them in your
thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle <filename>web.xml</filename>, or they will be ignored by the servlet container. In
interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides the link between Spring Security, the filter classes are also Spring beans defined in the application
<filename>web.xml</filename> and the application context. </para> context and thus able to take advantage of Spring's rich dependency-injection
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like facilities and lifecycle interfaces. Spring's
this in the <filename>web.xml</filename> file: <programlisting><![CDATA[ <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>
<filter-name>myFilter</filter-name> <filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
@ -40,29 +43,31 @@
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping>]]> </filter-mapping>]]>
</programlisting> Notice that the filter is actually a </programlisting> Notice that the filter is actually a
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement <literal>DelegatingFilterProxy</literal>, and not the class that will actually
the logic of the filter. What <classname>DelegatingFilterProxy</classname> does is delegate implement the logic of the filter. What <classname>DelegatingFilterProxy</classname>
the <interfacename>Filter</interfacename>'s methods through to a bean which is obtained from does is delegate the <interfacename>Filter</interfacename>'s methods through to a
the Spring application context. This enables the bean to benefit from the Spring web bean which is obtained from the Spring application context. This enables the bean to
application context lifecycle support and configuration flexibility. The bean must implement benefit from the Spring web application context lifecycle support and configuration
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that flexibility. The bean must implement
in the <literal>filter-name</literal> element. Read the Javadoc for <interfacename>javax.servlet.Filter</interfacename> and it must have the same name
<classname>DelegatingFilterProxy</classname> for more information</para> as that in the <literal>filter-name</literal> element. Read the Javadoc for
</section> <classname>DelegatingFilterProxy</classname> for more information</para>
<section xml:id="filter-chain-proxy"> </section>
<title><classname>FilterChainProxy</classname></title> <section xml:id="filter-chain-proxy">
<para> It should now be clear that you can declare each Spring Security filter bean that you <title><classname>FilterChainProxy</classname></title>
require in your application context file and add a corresponding <para> It should now be clear that you can declare each Spring Security filter bean that
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for you require in your application context file and add a corresponding
each filter, making sure that they are ordered correctly. This is a cumbersome approach and <classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename>
clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We for each filter, making sure that they are ordered correctly. This is a cumbersome
would prefer to just add a single entry to <filename>web.xml</filename> and deal entirely approach and clutters up the <filename>web.xml</filename> file quickly if we have a
with the application context file for managing our web security beans. This is where Spring lot of filters. We would prefer to just add a single entry to
Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a <filename>web.xml</filename> and deal entirely with the application context file for
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with the managing our web security beans. This is where Spring Secuiryt's
<literal>filter-name</literal> set to the bean name <quote>filterChainProxy</quote>. The <classname>FilterChainProxy</classname> comes in. It is wired using a
filter chain is then declared in the application context with the same bean name. Here's an <literal>DelegatingFilterProxy</literal>, just like in the example above, but with
example: <programlisting language="xml"><![CDATA[ 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"> <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant"> <sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters=" <sec:filter-chain pattern="/webServices/**" filters="
@ -78,127 +83,134 @@
</sec:filter-chain-map> </sec:filter-chain-map>
</bean> </bean>
]]> ]]>
</programlisting> The namespace element <literal>filter-chain-map</literal> is </programlisting> The namespace element <literal>filter-chain-map</literal> is used to set
used to set up the security filter chain(s) which are required within the application<footnote> 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 <para>Note that you'll need to include the security namespace in your application
XML file in order to use this syntax.</para> 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 </footnote>. It maps a particular URL pattern to a chain of filters built up from
names specified in the <literal>filters</literal> element. Both regular expressions and Ant the bean names specified in the <literal>filters</literal> element. Both regular
Paths are supported, and the most specific URIs appear first. At runtime the expressions and Ant Paths are supported, and the most specific URIs appear first. At
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches the runtime the <classname>FilterChainProxy</classname> will locate the first URI
current web request and the list of filter beans specified by the <literal>filters</literal> pattern that matches the current web request and the list of filter beans specified
attribute will be applied to that request. The filters will be invoked in the order they are by the <literal>filters</literal> attribute will be applied to that request. The
defined, so you have complete control over the filter chain which is applied to a particular filters will be invoked in the order they are defined, so you have complete control
URL.</para> over the filter chain which is applied to a particular URL.</para>
<para>You may have noticed we have declared two <para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain <classname>SecurityContextPersistenceFilter</classname>s in the filter chain
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property (<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a
of <classname>SecurityContextPersistenceFilter</classname>). As web services will never property of <classname>SecurityContextPersistenceFilter</classname>). As web
present a <literal>jsessionid</literal> on future requests, creating services will never present a <literal>jsessionid</literal> on future requests,
<literal>HttpSession</literal>s for such user agents would be wasteful. If you had a creating <literal>HttpSession</literal>s for such user agents would be wasteful. If
high-volume application which required maximum scalability, we recommend you use the you had a high-volume application which required maximum scalability, we recommend
approach shown above. For smaller applications, using a single you use the approach shown above. For smaller applications, using a single
<classname>SecurityContextPersistenceFilter</classname> (with its default <classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be <literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para> sufficient.</para>
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will always <para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will
delegate <methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname> always delegate <methodname>init(FilterConfig)</methodname> and
methods through to the underlaying <interfacename>Filter</interfacename>s if such methods <methodname>destroy()</methodname> methods through to the underlaying
are called against <classname>FilterChainProxy</classname> itself. In this case, <interfacename>Filter</interfacename>s if such methods are called against
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy each <classname>FilterChainProxy</classname> itself. In this case,
<literal>Filter</literal> bean once, no matter how many times it is declared in the filter <classname>FilterChainProxy</classname> guarantees to only initialize and destroy
chain(s). You control the overall choice as to whether these methods are called or not via each <literal>Filter</literal> bean once, no matter how many times it is declared in
the <literal>targetFilterLifecycle</literal> initialization parameter of the filter chain(s). You control the overall choice as to whether these methods are
<literal>DelegatingFilterProxy</literal>. By default this property is called or not via the <literal>targetFilterLifecycle</literal> initialization
<literal>false</literal> and servlet container lifecycle invocations are not delegated parameter of <literal>DelegatingFilterProxy</literal>. By default this property is
through <literal>DelegatingFilterProxy</literal>.</para> <literal>false</literal> and servlet container lifecycle invocations are not
<para> When we looked at how to set up web security using <link delegated through <literal>DelegatingFilterProxy</literal>.</para>
xlink:href="#namespace-auto-config">namespace configuration</link>, we used a <para> When we looked at how to set up web security using <link
<literal>DelegatingFilterProxy</literal> with the name xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
<quote>springSecurityFilterChain</quote>. You should now be able to see that this is the <literal>DelegatingFilterProxy</literal> with the name
name of the <classname>FilterChainProxy</classname> which is created by the namespace. </para> <quote>springSecurityFilterChain</quote>. You should now be able to see that this is
<section> the name of the <classname>FilterChainProxy</classname> which is created by the
<title>Bypassing the Filter Chain</title> namespace. </para>
<para> As with the namespace, you can use the attribute <literal>filters = "none"</literal> <section>
as an alternative to supplying a filter bean list. This will omit the request pattern from <title>Bypassing the Filter Chain</title>
the security filter chain entirely. Note that anything matching this path will then have <para> As with the namespace, you can use the attribute <literal>filters =
no authentication or authorization services applied and will be freely accessible. If you "none"</literal> as an alternative to supplying a filter bean list. This will
want to make use of the contents of the <classname>SecurityContext</classname> contents omit the request pattern from the security filter chain entirely. Note that
during a request, then it must have passed through the security filter chain. Otherwise anything matching this path will then have no authentication or authorization
the <classname>SecurityContextHolder</classname> will not have been populated and the services applied and will be freely accessible. If you want to make use of the
contents will be null.</para> contents of the <classname>SecurityContext</classname> contents during a
</section> 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>
<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"> <section xml:id="taglib">
<info> <info>
<title>Tag Libraries</title> <title>Tag Libraries</title>

View File

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