Manual formatting.
This commit is contained in:
parent
ae8027fa47
commit
90caf1bb37
|
@ -8,30 +8,30 @@
|
|||
<title>Overview</title>
|
||||
</info>
|
||||
<para>It's generally considered good security practice to adopt a
|
||||
<quote>deny-by-default</quote> where you explicitly specify what is allowed and
|
||||
disallow everything else. Defining what is accessible to unauthenticated users is a
|
||||
similar situation, particularly for web applications. Many sites require that users must
|
||||
be authenticated for anything other than a few URLs (for example the home and login
|
||||
pages). In this case it is easiest to define access configuration attributes for these
|
||||
specific URLs rather than have for every secured resource. Put differently, sometimes it
|
||||
is nice to say <literal>ROLE_SOMETHING</literal> is required by default and only allow
|
||||
certain exceptions to this rule, such as for login, logout and home pages of an
|
||||
application. You could also omit these pages from the filter chain entirely, thus
|
||||
bypassing the access control checks, but this may be undesirable for other reasons,
|
||||
particularly if the pages behave differently for authenticated users.</para>
|
||||
<quote>deny-by-default</quote> where you explicitly specify what is allowed and disallow
|
||||
everything else. Defining what is accessible to unauthenticated users is a similar
|
||||
situation, particularly for web applications. Many sites require that users must be
|
||||
authenticated for anything other than a few URLs (for example the home and login pages).
|
||||
In this case it is easiest to define access configuration attributes for these specific
|
||||
URLs rather than have for every secured resource. Put differently, sometimes it is nice
|
||||
to say <literal>ROLE_SOMETHING</literal> is required by default and only allow certain
|
||||
exceptions to this rule, such as for login, logout and home pages of an application. You
|
||||
could also omit these pages from the filter chain entirely, thus bypassing the access
|
||||
control checks, but this may be undesirable for other reasons, particularly if the pages
|
||||
behave differently for authenticated users.</para>
|
||||
<para>This is what we mean by anonymous authentication. Note that there is no real
|
||||
conceptual difference between a user who is <quote>anonymously authenticated</quote> and
|
||||
an unauthenticated user. Spring Security's anonymous authentication just gives you a
|
||||
more convenient way to configure your access-control attributes. Calls to servlet API
|
||||
calls such as <methodname>getCallerPrincipal</methodname>, for example, will still
|
||||
return null even though there is actually an anonymous authentication object in the
|
||||
<classname>SecurityContextHolder</classname>.</para>
|
||||
<classname>SecurityContextHolder</classname>.</para>
|
||||
<para>There are other situations where anonymous authentication is useful, such as when an
|
||||
auditing interceptor queries the <classname>SecurityContextHolder</classname> to
|
||||
identify which principal was responsible for a given operation. Classes can be authored
|
||||
more robustly if they know the <classname>SecurityContextHolder</classname> always
|
||||
contains an <interfacename>Authentication</interfacename> object, and never
|
||||
<literal>null</literal>.</para>
|
||||
<literal>null</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="anonymous-config">
|
||||
<info>
|
||||
|
@ -39,23 +39,22 @@
|
|||
</info>
|
||||
<para>Anonymous authentication support is provided automatically when using the HTTP
|
||||
configuration Spring Security 3.0 and can be customized (or disabled) using the
|
||||
<literal><anonymous></literal> element. You don't need to configure the beans
|
||||
<literal><anonymous></literal> element. You don't need to configure the beans
|
||||
described here unless you are using traditional bean configuration.</para>
|
||||
<para>Three classes that together provide the anonymous authentication feature.
|
||||
<literal>AnonymousAuthenticationToken</literal> is an implementation of
|
||||
<interfacename>Authentication</interfacename>, and stores the
|
||||
<interfacename>GrantedAuthority</interfacename>s which apply to the anonymous
|
||||
principal. There is a corresponding <literal>AnonymousAuthenticationProvider</literal>,
|
||||
which is chained into the <literal>ProviderManager</literal> so that
|
||||
<literal>AnonymousAuthenticationToken</literal>s are accepted. Finally, there is an
|
||||
<classname>AnonymousAuthenticationFilter</classname>, which is chained after the
|
||||
normal authentication mechanisms and automatically adds an
|
||||
<literal>AnonymousAuthenticationToken</literal> to the
|
||||
<classname>SecurityContextHolder</classname> if there is no existing
|
||||
<interfacename>Authentication</interfacename> held there. The definition of the
|
||||
filter and authentication provider appears as follows:</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
<literal>AnonymousAuthenticationToken</literal> is an implementation of
|
||||
<interfacename>Authentication</interfacename>, and stores the
|
||||
<interfacename>GrantedAuthority</interfacename>s which apply to the anonymous principal.
|
||||
There is a corresponding <literal>AnonymousAuthenticationProvider</literal>, which is
|
||||
chained into the <literal>ProviderManager</literal> so that
|
||||
<literal>AnonymousAuthenticationToken</literal>s are accepted. Finally, there is an
|
||||
<classname>AnonymousAuthenticationFilter</classname>, which is chained after the normal
|
||||
authentication mechanisms and automatically adds an
|
||||
<literal>AnonymousAuthenticationToken</literal> to the
|
||||
<classname>SecurityContextHolder</classname> if there is no existing
|
||||
<interfacename>Authentication</interfacename> held there. The definition of the filter
|
||||
and authentication provider appears as follows:</para>
|
||||
<para> <programlisting>
|
||||
<![CDATA[
|
||||
<bean id="anonymousAuthFilter"
|
||||
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
|
||||
|
@ -67,32 +66,30 @@
|
|||
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
|
||||
<property name="key" value="foobar"/>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>The <literal>key</literal> is shared between the filter and authentication provider,
|
||||
so that tokens created by the former are accepted by the latter<footnote><para>The use
|
||||
of the <literal>key</literal> property should not be regarded as providing any
|
||||
real security here. It is merely a book-keeping exercise. If you are sharing a
|
||||
<classname>ProviderManager</classname> which contains an
|
||||
<classname>AnonymousAuthenticationProvider</classname> in a scenario where
|
||||
it is possible for an authenticating client to construct the
|
||||
<interfacename>Authentication</interfacename> object (such as with RMI
|
||||
invocations), then a malicious client could submit an
|
||||
<classname>AnonymousAuthenticationToken</classname> which it had created
|
||||
itself (with chosen username and authority list). If the <literal>key</literal>
|
||||
is guessable or can be found out, then the token would be accepted by the
|
||||
anonymous provider. This isn't a problem with normal usage but if you are using
|
||||
RMI you would be best to use a customized <classname>ProviderManager</classname>
|
||||
which omits the anonymous provider rather than sharing the one you use for your
|
||||
HTTP authentication mechanisms.</para></footnote>. The
|
||||
<literal>userAttribute</literal> is expressed in the form of
|
||||
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
|
||||
so that tokens created by the former are accepted by the latter<footnote>
|
||||
<para>The use of the <literal>key</literal> property should not be regarded as providing
|
||||
any real security here. It is merely a book-keeping exercise. If you are sharing a
|
||||
<classname>ProviderManager</classname> which contains an
|
||||
<classname>AnonymousAuthenticationProvider</classname> in a scenario where it is
|
||||
possible for an authenticating client to construct the
|
||||
<interfacename>Authentication</interfacename> object (such as with RMI invocations),
|
||||
then a malicious client could submit an
|
||||
<classname>AnonymousAuthenticationToken</classname> which it had created itself
|
||||
(with chosen username and authority list). If the <literal>key</literal> is
|
||||
guessable or can be found out, then the token would be accepted by the anonymous
|
||||
provider. This isn't a problem with normal usage but if you are using RMI you would
|
||||
be best to use a customized <classname>ProviderManager</classname> which omits the
|
||||
anonymous provider rather than sharing the one you use for your HTTP authentication
|
||||
mechanisms.</para>
|
||||
</footnote>. The <literal>userAttribute</literal> is expressed in the form of
|
||||
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
|
||||
This is the same syntax as used after the equals sign for
|
||||
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal> property.</para>
|
||||
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal> property.</para>
|
||||
<para>As explained earlier, the benefit of anonymous authentication is that all URI patterns
|
||||
can have security applied to them. For example:</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
<para> <programlisting>
|
||||
<![CDATA[
|
||||
<bean id="filterSecurityInterceptor"
|
||||
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
|
||||
|
@ -108,19 +105,18 @@
|
|||
</security:filter-security-metadata-source>" +
|
||||
</property>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
</section>
|
||||
<section xml:id="anonymous-auth-trust-resolver">
|
||||
<title><interfacename>AuthenticationTrustResolver</interfacename></title>
|
||||
<para> Rounding out the anonymous authentication discussion is the
|
||||
<interfacename>AuthenticationTrustResolver</interfacename> interface, with its
|
||||
<interfacename>AuthenticationTrustResolver</interfacename> interface, with its
|
||||
corresponding <literal>AuthenticationTrustResolverImpl</literal> implementation. This
|
||||
interface provides an <literal>isAnonymous(Authentication)</literal> method, which
|
||||
allows interested classes to take into account this special type of authentication
|
||||
status. The <classname>ExceptionTranslationFilter</classname> uses this interface in
|
||||
processing <literal>AccessDeniedException</literal>s. If an
|
||||
<literal>AccessDeniedException</literal> is thrown, and the authentication is of an
|
||||
<literal>AccessDeniedException</literal> is thrown, and the authentication is of an
|
||||
anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead
|
||||
commence the <interfacename>AuthenticationEntryPoint</interfacename> so the principal
|
||||
can authenticate properly. This is a necessary distinction, otherwise principals would
|
||||
|
@ -130,13 +126,13 @@
|
|||
interceptor configuration replaced with <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>,
|
||||
which is effectively the same thing when defining access controls. This is an example of
|
||||
the use of the <classname>AuthenticatedVoter</classname> which we will see in the <link
|
||||
xlink:href="#authz-authenticated-voter">authorization chapter</link>. It uses an
|
||||
<interfacename>AuthenticationTrustResolver</interfacename> to process this
|
||||
particular configuration attribute and grant access to anonymous users. The
|
||||
<classname>AuthenticatedVoter</classname> approach is more powerful, since it allows
|
||||
you to differentiate between anonymous, remember-me and fully-authenticated users. If
|
||||
you don't need this functionality though, then you can stick with
|
||||
<literal>ROLE_ANONYMOUS</literal>, which will be processed by Spring Security's
|
||||
standard <classname>RoleVoter</classname>. </para>
|
||||
xlink:href="#authz-authenticated-voter">authorization chapter</link>. It uses an
|
||||
<interfacename>AuthenticationTrustResolver</interfacename> to process this particular
|
||||
configuration attribute and grant access to anonymous users. The
|
||||
<classname>AuthenticatedVoter</classname> approach is more powerful, since it allows you
|
||||
to differentiate between anonymous, remember-me and fully-authenticated users. If you
|
||||
don't need this functionality though, then you can stick with
|
||||
<literal>ROLE_ANONYMOUS</literal>, which will be processed by Spring Security's standard
|
||||
<classname>RoleVoter</classname>. </para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix version="5.0" xml:id="appendix-schema" xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<info>
|
||||
<title>Security Database Schema</title>
|
||||
</info>
|
||||
<para> There are various database schema used by the framework and this appendix provides a single
|
||||
reference point to them all. You only need to provide the tables for the areas of functonality
|
||||
you require. </para>
|
||||
<para> DDL statements are given for the HSQLDB database. You can use these as a guideline for
|
||||
defining the schema for the database you are using. </para>
|
||||
<section>
|
||||
<title>User Schema</title>
|
||||
<para> The standard JDBC implementation of the <interfacename>UserDetailsService</interfacename>
|
||||
(<classname>JdbcDaoImpl</classname>) requires tables to load the password, account status
|
||||
(enabled or disabled) and a list of authorities (roles) for the user.
|
||||
<programlisting xml:id="db_schema_users_authorities">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<info>
|
||||
<title>Security Database Schema</title>
|
||||
</info>
|
||||
<para> There are various database schema used by the framework and this appendix provides a
|
||||
single reference point to them all. You only need to provide the tables for the areas of
|
||||
functonality you require. </para>
|
||||
<para> DDL statements are given for the HSQLDB database. You can use these as a guideline for
|
||||
defining the schema for the database you are using. </para>
|
||||
<section>
|
||||
<title>User Schema</title>
|
||||
<para> The standard JDBC implementation of the
|
||||
<interfacename>UserDetailsService</interfacename> (<classname>JdbcDaoImpl</classname>)
|
||||
requires tables to load the password, account status (enabled or disabled) and a list of
|
||||
authorities (roles) for the user.
|
||||
<programlisting xml:id="db_schema_users_authorities">
|
||||
create table users(
|
||||
username varchar_ignorecase(50) not null primary key,
|
||||
password varchar_ignorecase(50) not null,
|
||||
|
@ -26,11 +27,11 @@
|
|||
constraint fk_authorities_users foreign key(username) references users(username));
|
||||
create unique index ix_auth_username on authorities (username,authority);
|
||||
</programlisting></para>
|
||||
<section>
|
||||
<title>Group Authorities</title>
|
||||
<para> Spring Security 2.0 introduced support for group authorities in
|
||||
<classname>JdbcDaoImpl</classname>. The table structure if groups are enabled is as
|
||||
follows:<programlisting xml:id="db-schema-groups">
|
||||
<section>
|
||||
<title>Group Authorities</title>
|
||||
<para> Spring Security 2.0 introduced support for group authorities in
|
||||
<classname>JdbcDaoImpl</classname>. The table structure if groups are enabled is as
|
||||
follows:<programlisting xml:id="db-schema-groups">
|
||||
create table groups (
|
||||
id bigint generated by default as identity(start with 0) primary key,
|
||||
group_name varchar_ignorecase(50) not null);
|
||||
|
@ -46,55 +47,57 @@ create table group_members (
|
|||
group_id bigint not null,
|
||||
constraint fk_group_members_group foreign key(group_id) references groups(id));
|
||||
</programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Persistent Login (Remember-Me) Schema</title>
|
||||
<para> This table is used to store data used by the more secure <link
|
||||
xlink:href="#remember-me-persistent-token">persistent token</link> remember-me
|
||||
implementation. If you are using <classname>JdbcTokenRepositoryImpl</classname> either
|
||||
directly or through the namespace, then you will need this table.
|
||||
<programlisting xml:id="db-schema-remeber-me">
|
||||
<section>
|
||||
<title>Persistent Login (Remember-Me) Schema</title>
|
||||
<para> This table is used to store data used by the more secure <link
|
||||
xlink:href="#remember-me-persistent-token">persistent token</link> remember-me
|
||||
implementation. If you are using <classname>JdbcTokenRepositoryImpl</classname> either
|
||||
directly or through the namespace, then you will need this table.
|
||||
<programlisting xml:id="db-schema-remeber-me">
|
||||
create table persistent_logins (
|
||||
username varchar(64) not null,
|
||||
series varchar(64) primary key,
|
||||
token varchar(64) not null,
|
||||
last_used timestamp not null);
|
||||
</programlisting></para>
|
||||
</section>
|
||||
<section xml:id="dbschema-acl">
|
||||
<title>ACL Schema</title>
|
||||
<para>There are four tables used by the Spring Security <link xlink:href="#domain-acls"
|
||||
>ACL</link> implementation. <orderedlist>
|
||||
<listitem>
|
||||
<para><literal>acl_sid</literal> stores the security identities recognised by the ACL
|
||||
system. These can be unique principals or authorities which may apply to multiple
|
||||
principals.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>acl_class</literal> defines the domain object types to which ACLs apply.
|
||||
The <literal>class</literal> column stores the Java class name of the object. </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>acl_object_identity</literal> stores the object identity definitions of
|
||||
specific domai objects.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>acl_entry</literal> stores the ACL permissions which apply to a specific
|
||||
object identity and security identity.</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
<para>It is assumed that the database will auto-generate the primary keys for each of the
|
||||
identities. The <literal>JdbcMutableAclService</literal> has to be able to retrieve these when
|
||||
it has created a new row in the <literal>acl_sid</literal> or <literal>acl_class</literal>
|
||||
tables. It has two properties which define the SQL needed to retrieve these values
|
||||
<literal>classIdentityQuery</literal> and <literal>sidIdentityQuery</literal>. Both of these
|
||||
default to <literal>call identity()</literal></para>
|
||||
<section>
|
||||
<title>Hypersonic SQL</title>
|
||||
<para>The default schema works with the embedded HSQLDB database that is used in unit tests
|
||||
within the
|
||||
framework.<programlisting xml:id="dbschema-acl-hsql">
|
||||
</section>
|
||||
<section xml:id="dbschema-acl">
|
||||
<title>ACL Schema</title>
|
||||
<para>There are four tables used by the Spring Security <link xlink:href="#domain-acls"
|
||||
>ACL</link> implementation. <orderedlist>
|
||||
<listitem>
|
||||
<para><literal>acl_sid</literal> stores the security identities recognised by the
|
||||
ACL system. These can be unique principals or authorities which may apply to
|
||||
multiple principals.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>acl_class</literal> defines the domain object types to which ACLs
|
||||
apply. The <literal>class</literal> column stores the Java class name of the
|
||||
object. </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>acl_object_identity</literal> stores the object identity definitions
|
||||
of specific domai objects.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>acl_entry</literal> stores the ACL permissions which apply to a
|
||||
specific object identity and security identity.</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
<para>It is assumed that the database will auto-generate the primary keys for each of the
|
||||
identities. The <literal>JdbcMutableAclService</literal> has to be able to retrieve
|
||||
these when it has created a new row in the <literal>acl_sid</literal> or
|
||||
<literal>acl_class</literal> tables. It has two properties which define the SQL needed
|
||||
to retrieve these values <literal>classIdentityQuery</literal> and
|
||||
<literal>sidIdentityQuery</literal>. Both of these default to <literal>call
|
||||
identity()</literal></para>
|
||||
<section>
|
||||
<title>Hypersonic SQL</title>
|
||||
<para>The default schema works with the embedded HSQLDB database that is used in unit
|
||||
tests within the
|
||||
framework.<programlisting xml:id="dbschema-acl-hsql">
|
||||
create table acl_sid (
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
principal boolean not null,
|
||||
|
@ -129,10 +132,10 @@ create table acl_entry (
|
|||
constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );
|
||||
|
||||
</programlisting></para>
|
||||
<section>
|
||||
<title>PostgreSQL</title>
|
||||
<para>
|
||||
<programlisting>create table acl_sid(
|
||||
<section>
|
||||
<title>PostgreSQL</title>
|
||||
<para>
|
||||
<programlisting>create table acl_sid(
|
||||
id bigserial not null primary key,
|
||||
principal boolean not null,
|
||||
sid varchar(100) not null,
|
||||
|
@ -168,21 +171,21 @@ create table acl_entry(
|
|||
constraint foreign_fk_4 foreign key(acl_object_identity)
|
||||
references acl_object_identity(id),
|
||||
constraint foreign_fk_5 foreign key(sid) references acl_sid(id));
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>You will have to set the <literal>classIdentityQuery</literal> and
|
||||
<literal>sidIdentityQuery</literal> properties of
|
||||
<classname>JdbcMutableAclService</classname> to the following values, respectively: <itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>select currval(pg_get_serial_sequence('acl_class',
|
||||
'id'))</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>select currval(pg_get_serial_sequence('acl_sid',
|
||||
'id'))</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</section>
|
||||
</programlisting> </para>
|
||||
<para>You will have to set the <literal>classIdentityQuery</literal> and
|
||||
<literal>sidIdentityQuery</literal> properties of
|
||||
<classname>JdbcMutableAclService</classname> to the following values,
|
||||
respectively: <itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>select currval(pg_get_serial_sequence('acl_class',
|
||||
'id'))</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>select currval(pg_get_serial_sequence('acl_sid',
|
||||
'id'))</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,232 +1,246 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authz-arch"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Authorization Architecture</title>
|
||||
</info>
|
||||
<section xml:id="authz-authorities">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Authorities</title>
|
||||
<title>Authorization Architecture</title>
|
||||
</info>
|
||||
<para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>, all
|
||||
<interfacename>Authentication</interfacename> implementations store a list of
|
||||
<interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
|
||||
that have been granted to the principal. The <interfacename>GrantedAuthority</interfacename>
|
||||
objects are inserted into the <interfacename>Authentication</interfacename> object by the
|
||||
<interfacename>AuthenticationManager</interfacename> and are later read by
|
||||
<interfacename>AccessDecisionManager</interfacename>s when making authorization
|
||||
decisions.</para>
|
||||
<para><interfacename>GrantedAuthority</interfacename> is an interface with only one method:
|
||||
<programlisting>
|
||||
<section xml:id="authz-authorities">
|
||||
<info>
|
||||
<title>Authorities</title>
|
||||
</info>
|
||||
<para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>,
|
||||
all <interfacename>Authentication</interfacename> implementations store a list of
|
||||
<interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
|
||||
that have been granted to the principal. The
|
||||
<interfacename>GrantedAuthority</interfacename> objects are inserted into the
|
||||
<interfacename>Authentication</interfacename> object by the
|
||||
<interfacename>AuthenticationManager</interfacename> and are later read by
|
||||
<interfacename>AccessDecisionManager</interfacename>s when making authorization
|
||||
decisions.</para>
|
||||
<para><interfacename>GrantedAuthority</interfacename> is an interface with only one method:
|
||||
<programlisting>
|
||||
String getAuthority();
|
||||
</programlisting> This method allows
|
||||
<interfacename>AccessDecisionManager</interfacename>s to obtain a precise
|
||||
<literal>String</literal> representation of the
|
||||
<interfacename>GrantedAuthority</interfacename>. By returning a representation as a
|
||||
<literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be easily
|
||||
<quote>read</quote> by most <interfacename>AccessDecisionManager</interfacename>s. If a
|
||||
<interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
|
||||
<literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is considered
|
||||
<quote>complex</quote> and <literal>getAuthority()</literal> must return
|
||||
<literal>null</literal>.</para>
|
||||
<para>An example of a <quote>complex</quote>
|
||||
<interfacename>GrantedAuthority</interfacename> would be an implementation that stores a list
|
||||
of operations and authority thresholds that apply to different customer account numbers.
|
||||
Representing this complex <interfacename>GrantedAuthority</interfacename> as a
|
||||
<literal>String</literal> would be quite difficult, and as a result the
|
||||
<literal>getAuthority()</literal> method should return <literal>null</literal>. This will
|
||||
indicate to any <interfacename>AccessDecisionManager</interfacename> that it will need to
|
||||
specifically support the <interfacename>GrantedAuthority</interfacename> implementation in
|
||||
order to understand its contents.</para>
|
||||
<para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
|
||||
implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified
|
||||
<literal>String</literal> to be converted into a
|
||||
<interfacename>GrantedAuthority</interfacename>. All
|
||||
<classname>AuthenticationProvider</classname>s included with the security architecture use
|
||||
<literal>GrantedAuthorityImpl</literal> to populate the
|
||||
<interfacename>Authentication</interfacename> object.</para>
|
||||
</section>
|
||||
<section xml:id="authz-pre-invocation">
|
||||
<info>
|
||||
<title>Pre-Invocation Handling</title>
|
||||
</info>
|
||||
<para> As we've also seen in the <link xlink:href="#secure-objects">Technical Overview</link>
|
||||
chapter, Spring Security provides interceptors which control access to secure objects such as
|
||||
method invocations or web requests. A pre-invocation decision on whether the invocation is
|
||||
allowed to proceed is made by the <interfacename>AccessDecisionManager</interfacename>. </para>
|
||||
<section xml:id="authz-access-decision-manager">
|
||||
<title>The AccessDecisionManager</title>
|
||||
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the
|
||||
<classname>AbstractSecurityInterceptor</classname> and is responsible for making final
|
||||
access control decisions. The <interfacename>AccessDecisionManager</interfacename> interface
|
||||
contains three methods:
|
||||
<programlisting>
|
||||
<interfacename>AccessDecisionManager</interfacename>s to obtain a precise
|
||||
<literal>String</literal> representation of the
|
||||
<interfacename>GrantedAuthority</interfacename>. By returning a representation as a
|
||||
<literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be
|
||||
easily <quote>read</quote> by most
|
||||
<interfacename>AccessDecisionManager</interfacename>s. If a
|
||||
<interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
|
||||
<literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is
|
||||
considered <quote>complex</quote> and <literal>getAuthority()</literal> must return
|
||||
<literal>null</literal>.</para>
|
||||
<para>An example of a <quote>complex</quote> <interfacename>GrantedAuthority</interfacename>
|
||||
would be an implementation that stores a list of operations and authority thresholds
|
||||
that apply to different customer account numbers. Representing this complex
|
||||
<interfacename>GrantedAuthority</interfacename> as a <literal>String</literal> would be
|
||||
quite difficult, and as a result the <literal>getAuthority()</literal> method should
|
||||
return <literal>null</literal>. This will indicate to any
|
||||
<interfacename>AccessDecisionManager</interfacename> that it will need to specifically
|
||||
support the <interfacename>GrantedAuthority</interfacename> implementation in order to
|
||||
understand its contents.</para>
|
||||
<para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
|
||||
implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified
|
||||
<literal>String</literal> to be converted into a
|
||||
<interfacename>GrantedAuthority</interfacename>. All
|
||||
<classname>AuthenticationProvider</classname>s included with the security architecture
|
||||
use <literal>GrantedAuthorityImpl</literal> to populate the
|
||||
<interfacename>Authentication</interfacename> object.</para>
|
||||
</section>
|
||||
<section xml:id="authz-pre-invocation">
|
||||
<info>
|
||||
<title>Pre-Invocation Handling</title>
|
||||
</info>
|
||||
<para> As we've also seen in the <link xlink:href="#secure-objects">Technical
|
||||
Overview</link> chapter, Spring Security provides interceptors which control access to
|
||||
secure objects such as method invocations or web requests. A pre-invocation decision on
|
||||
whether the invocation is allowed to proceed is made by the
|
||||
<interfacename>AccessDecisionManager</interfacename>. </para>
|
||||
<section xml:id="authz-access-decision-manager">
|
||||
<title>The AccessDecisionManager</title>
|
||||
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the
|
||||
<classname>AbstractSecurityInterceptor</classname> and is responsible for making
|
||||
final access control decisions. The
|
||||
<interfacename>AccessDecisionManager</interfacename> interface contains three
|
||||
methods:
|
||||
<programlisting>
|
||||
void decide(Authentication authentication, Object secureObject,
|
||||
List<ConfigAttribute> config) throws AccessDeniedException;
|
||||
boolean supports(ConfigAttribute attribute);
|
||||
boolean supports(Class clazz);
|
||||
</programlisting>
|
||||
The <interfacename>AccessDecisionManager</interfacename>'s <methodname>decide</methodname>
|
||||
method is passed all the relevant information it needs in order to make an authorization
|
||||
decision. In particular, passing the secure <literal>Object</literal> enables those
|
||||
arguments contained in the actual secure object invocation to be inspected. For example,
|
||||
let's assume the secure object was a <classname>MethodInvocation</classname>. It would be
|
||||
easy to query the <classname>MethodInvocation</classname> for any
|
||||
<literal>Customer</literal> argument, and then implement some sort of security logic in
|
||||
the <interfacename>AccessDecisionManager</interfacename> to ensure the principal is
|
||||
permitted to operate on that customer. Implementations are expected to throw an
|
||||
<literal>AccessDeniedException</literal> if access is denied.</para>
|
||||
<para>The <literal>supports(ConfigAttribute)</literal> method is called by the
|
||||
<classname>AbstractSecurityInterceptor</classname> at startup time to determine if the
|
||||
<interfacename>AccessDecisionManager</interfacename> can process the passed
|
||||
<literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
|
||||
called by a security interceptor implementation to ensure the configured
|
||||
<interfacename>AccessDecisionManager</interfacename> supports the type of secure object
|
||||
that the security interceptor will present.</para>
|
||||
</section>
|
||||
<section xml:id="authz-voting-based">
|
||||
<title>Voting-Based AccessDecisionManager Implementations</title>
|
||||
<para>Whilst users can implement their own
|
||||
<interfacename>AccessDecisionManager</interfacename> to control all aspects of
|
||||
authorization, Spring Security includes several
|
||||
<interfacename>AccessDecisionManager</interfacename> implementations that are based on
|
||||
voting. <xref linkend="authz-access-voting"/> illustrates the relevant classes.</para>
|
||||
<figure xml:id="authz-access-voting">
|
||||
<title>Voting Decision Manager</title>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center" fileref="images/access-decision-voting.png"
|
||||
format="PNG" scale="75"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure>
|
||||
<para>Using this approach, a series of <interfacename>AccessDecisionVoter</interfacename>
|
||||
implementations are polled on an authorization decision. The
|
||||
<interfacename>AccessDecisionManager</interfacename> then decides whether or not to throw
|
||||
an <literal>AccessDeniedException</literal> based on its assessment of the votes.</para>
|
||||
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three methods:
|
||||
<programlisting>
|
||||
The <interfacename>AccessDecisionManager</interfacename>'s
|
||||
<methodname>decide</methodname> method is passed all the relevant information it
|
||||
needs in order to make an authorization decision. In particular, passing the secure
|
||||
<literal>Object</literal> enables those arguments contained in the actual secure
|
||||
object invocation to be inspected. For example, let's assume the secure object was a
|
||||
<classname>MethodInvocation</classname>. It would be easy to query the
|
||||
<classname>MethodInvocation</classname> for any <literal>Customer</literal>
|
||||
argument, and then implement some sort of security logic in the
|
||||
<interfacename>AccessDecisionManager</interfacename> to ensure the principal is
|
||||
permitted to operate on that customer. Implementations are expected to throw an
|
||||
<literal>AccessDeniedException</literal> if access is denied.</para>
|
||||
<para>The <literal>supports(ConfigAttribute)</literal> method is called by the
|
||||
<classname>AbstractSecurityInterceptor</classname> at startup time to determine if
|
||||
the <interfacename>AccessDecisionManager</interfacename> can process the passed
|
||||
<literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
|
||||
called by a security interceptor implementation to ensure the configured
|
||||
<interfacename>AccessDecisionManager</interfacename> supports the type of secure
|
||||
object that the security interceptor will present.</para>
|
||||
</section>
|
||||
<section xml:id="authz-voting-based">
|
||||
<title>Voting-Based AccessDecisionManager Implementations</title>
|
||||
<para>Whilst users can implement their own
|
||||
<interfacename>AccessDecisionManager</interfacename> to control all aspects of
|
||||
authorization, Spring Security includes several
|
||||
<interfacename>AccessDecisionManager</interfacename> implementations that are based
|
||||
on voting. <xref linkend="authz-access-voting"/> illustrates the relevant
|
||||
classes.</para>
|
||||
<figure xml:id="authz-access-voting">
|
||||
<title>Voting Decision Manager</title>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center" fileref="images/access-decision-voting.png"
|
||||
format="PNG" scale="75"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure>
|
||||
<para>Using this approach, a series of
|
||||
<interfacename>AccessDecisionVoter</interfacename> implementations are polled on an
|
||||
authorization decision. The <interfacename>AccessDecisionManager</interfacename>
|
||||
then decides whether or not to throw an <literal>AccessDeniedException</literal>
|
||||
based on its assessment of the votes.</para>
|
||||
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three
|
||||
methods:
|
||||
<programlisting>
|
||||
int vote(Authentication authentication, Object object, List<ConfigAttribute> config);
|
||||
boolean supports(ConfigAttribute attribute);
|
||||
boolean supports(Class clazz);
|
||||
</programlisting>
|
||||
Concrete implementations return an <literal>int</literal>, with possible values being
|
||||
reflected in the <interfacename>AccessDecisionVoter</interfacename> static fields
|
||||
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
|
||||
<literal>ACCESS_GRANTED</literal>. A voting implementation will return
|
||||
<literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision. If it
|
||||
does have an opinion, it must return either <literal>ACCESS_DENIED</literal> or
|
||||
<literal>ACCESS_GRANTED</literal>.</para>
|
||||
<para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s provided
|
||||
with Spring Security that tally the votes. The <literal>ConsensusBased</literal>
|
||||
implementation will grant or deny access based on the consensus of non-abstain votes.
|
||||
Properties are provided to control behavior in the event of an equality of votes or if all
|
||||
votes are abstain. The <literal>AffirmativeBased</literal> implementation will grant access
|
||||
if one or more <literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny vote will
|
||||
be ignored, provided there was at least one grant vote). Like the
|
||||
<literal>ConsensusBased</literal> implementation, there is a parameter that controls the
|
||||
behavior if all voters abstain. The <literal>UnanimousBased</literal> provider expects
|
||||
unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access, ignoring
|
||||
abstains. It will deny access if there is any <literal>ACCESS_DENIED</literal> vote. Like
|
||||
the other implementations, there is a parameter that controls the behaviour if all voters
|
||||
abstain.</para>
|
||||
<para>It is possible to implement a custom
|
||||
<interfacename>AccessDecisionManager</interfacename> that tallies votes differently. For
|
||||
example, votes from a particular <interfacename>AccessDecisionVoter</interfacename> might
|
||||
receive additional weighting, whilst a deny vote from a particular voter may have a veto
|
||||
effect.</para>
|
||||
<section xml:id="authz-role-voter">
|
||||
<title><classname>RoleVoter</classname></title>
|
||||
<para> The most commonly used <interfacename>AccessDecisionVoter</interfacename> provided
|
||||
with Spring Security is the simple <classname>RoleVoter</classname>, which treats
|
||||
configuration attributes as simple role names and votes to grant access if the user has
|
||||
been assigned that role.</para>
|
||||
<para>It will vote if any <interfacename>ConfigAttribute</interfacename> begins with the
|
||||
prefix <literal>ROLE_</literal>. It will vote to grant access if there is a
|
||||
<interfacename>GrantedAuthority</interfacename> which returns a
|
||||
<literal>String</literal> representation (via the <literal>getAuthority()</literal>
|
||||
method) exactly equal to one or more <literal>ConfigAttributes</literal> starting with the
|
||||
prefix <literal>ROLE_</literal>. If there is no exact match of any
|
||||
<literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
|
||||
<literal>RoleVoter</literal> will vote to deny access. If no
|
||||
<literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the voter will
|
||||
abstain.</para>
|
||||
</section>
|
||||
<section xml:id="authz-authenticated-voter">
|
||||
<title><classname>AuthenticatedVoter</classname></title>
|
||||
<para> Another voter which we've implicitly seen is the
|
||||
<classname>AuthenticatedVoter</classname>, which can be used to differentiate between
|
||||
anonymous, fully-authenticated and remember-me authenticated users. Many sites allow
|
||||
certain limited access under remember-me authentication, but require a user to confirm
|
||||
their identity by logging in for full access.</para>
|
||||
<para>When we've used the attribute <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal> to grant
|
||||
anonymous access, this attribute was being processed by the
|
||||
<classname>AuthenticatedVoter</classname>. See the Javadoc for this class for more
|
||||
information. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Custom Voters</title>
|
||||
<para>It is also possible to implement a custom
|
||||
<interfacename>AccessDecisionVoter</interfacename>. Several examples are provided in
|
||||
Spring Security unit tests, including <literal>ContactSecurityVoter</literal> and
|
||||
<literal>DenyVoter</literal>. The <literal>ContactSecurityVoter</literal> abstains from
|
||||
voting decisions where a <literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
|
||||
<literal>ConfigAttribute</literal> is not found. If voting, it queries the
|
||||
<classname>MethodInvocation</classname> to extract the owner of the
|
||||
<literal>Contact</literal> object that is subject of the method call. It votes to grant
|
||||
access if the <literal>Contact</literal> owner matches the principal presented in the
|
||||
<interfacename>Authentication</interfacename> object. It could have just as easily
|
||||
compared the <literal>Contact</literal> owner with some
|
||||
<interfacename>GrantedAuthority</interfacename> the
|
||||
<interfacename>Authentication</interfacename> object presented. All of this is achieved
|
||||
with relatively few lines of code and demonstrates the flexibility of the authorization
|
||||
model.</para>
|
||||
</section>
|
||||
Concrete implementations return an <literal>int</literal>, with possible values
|
||||
being reflected in the <interfacename>AccessDecisionVoter</interfacename> static
|
||||
fields <literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
|
||||
<literal>ACCESS_GRANTED</literal>. A voting implementation will return
|
||||
<literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision.
|
||||
If it does have an opinion, it must return either <literal>ACCESS_DENIED</literal>
|
||||
or <literal>ACCESS_GRANTED</literal>.</para>
|
||||
<para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s
|
||||
provided with Spring Security that tally the votes. The
|
||||
<literal>ConsensusBased</literal> implementation will grant or deny access based on
|
||||
the consensus of non-abstain votes. Properties are provided to control behavior in
|
||||
the event of an equality of votes or if all votes are abstain. The
|
||||
<literal>AffirmativeBased</literal> implementation will grant access if one or more
|
||||
<literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny vote will be
|
||||
ignored, provided there was at least one grant vote). Like the
|
||||
<literal>ConsensusBased</literal> implementation, there is a parameter that controls
|
||||
the behavior if all voters abstain. The <literal>UnanimousBased</literal> provider
|
||||
expects unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access,
|
||||
ignoring abstains. It will deny access if there is any
|
||||
<literal>ACCESS_DENIED</literal> vote. Like the other implementations, there is a
|
||||
parameter that controls the behaviour if all voters abstain.</para>
|
||||
<para>It is possible to implement a custom
|
||||
<interfacename>AccessDecisionManager</interfacename> that tallies votes differently.
|
||||
For example, votes from a particular
|
||||
<interfacename>AccessDecisionVoter</interfacename> might receive additional
|
||||
weighting, whilst a deny vote from a particular voter may have a veto effect.</para>
|
||||
<section xml:id="authz-role-voter">
|
||||
<title><classname>RoleVoter</classname></title>
|
||||
<para> The most commonly used <interfacename>AccessDecisionVoter</interfacename>
|
||||
provided with Spring Security is the simple <classname>RoleVoter</classname>,
|
||||
which treats configuration attributes as simple role names and votes to grant
|
||||
access if the user has been assigned that role.</para>
|
||||
<para>It will vote if any <interfacename>ConfigAttribute</interfacename> begins with
|
||||
the prefix <literal>ROLE_</literal>. It will vote to grant access if there is a
|
||||
<interfacename>GrantedAuthority</interfacename> which returns a
|
||||
<literal>String</literal> representation (via the
|
||||
<literal>getAuthority()</literal> method) exactly equal to one or more
|
||||
<literal>ConfigAttributes</literal> starting with the prefix
|
||||
<literal>ROLE_</literal>. If there is no exact match of any
|
||||
<literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
|
||||
<literal>RoleVoter</literal> will vote to deny access. If no
|
||||
<literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the
|
||||
voter will abstain.</para>
|
||||
</section>
|
||||
<section xml:id="authz-authenticated-voter">
|
||||
<title><classname>AuthenticatedVoter</classname></title>
|
||||
<para> Another voter which we've implicitly seen is the
|
||||
<classname>AuthenticatedVoter</classname>, which can be used to differentiate
|
||||
between anonymous, fully-authenticated and remember-me authenticated users. Many
|
||||
sites allow certain limited access under remember-me authentication, but require
|
||||
a user to confirm their identity by logging in for full access.</para>
|
||||
<para>When we've used the attribute <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal>
|
||||
to grant anonymous access, this attribute was being processed by the
|
||||
<classname>AuthenticatedVoter</classname>. See the Javadoc for this class for
|
||||
more information. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Custom Voters</title>
|
||||
<para>It is also possible to implement a custom
|
||||
<interfacename>AccessDecisionVoter</interfacename>. Several examples are
|
||||
provided in Spring Security unit tests, including
|
||||
<literal>ContactSecurityVoter</literal> and <literal>DenyVoter</literal>. The
|
||||
<literal>ContactSecurityVoter</literal> abstains from voting decisions where a
|
||||
<literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
|
||||
<literal>ConfigAttribute</literal> is not found. If voting, it queries the
|
||||
<classname>MethodInvocation</classname> to extract the owner of the
|
||||
<literal>Contact</literal> object that is subject of the method call. It votes
|
||||
to grant access if the <literal>Contact</literal> owner matches the principal
|
||||
presented in the <interfacename>Authentication</interfacename> object. It could
|
||||
have just as easily compared the <literal>Contact</literal> owner with some
|
||||
<interfacename>GrantedAuthority</interfacename> the
|
||||
<interfacename>Authentication</interfacename> object presented. All of this is
|
||||
achieved with relatively few lines of code and demonstrates the flexibility of
|
||||
the authorization model.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="authz-after-invocation-handling">
|
||||
<info>
|
||||
<title>After Invocation Handling</title>
|
||||
</info>
|
||||
<para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
|
||||
<classname>AbstractSecurityInterceptor</classname> before proceeding with the secure object
|
||||
invocation, some applications need a way of modifying the object actually returned by the
|
||||
secure object invocation. Whilst you could easily implement your own AOP concern to achieve
|
||||
this, Spring Security provides a convenient hook that has several concrete implementations
|
||||
that integrate with its ACL capabilities.</para>
|
||||
<para><xref linkend="authz-after-invocation"/> illustrates Spring Security's
|
||||
<literal>AfterInvocationManager</literal> and its concrete implementations. <figure
|
||||
xml:id="authz-after-invocation">
|
||||
<title>After Invocation Implementation</title>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center" fileref="images/after-invocation.png" format="PNG" scale="75"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure></para>
|
||||
<para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal> has a
|
||||
single concrete implementation, <literal>AfterInvocationProviderManager</literal>, which polls
|
||||
a list of <literal>AfterInvocationProvider</literal>s. Each
|
||||
<literal>AfterInvocationProvider</literal> is allowed to modify the return object or throw
|
||||
an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify the object,
|
||||
as the result of the previous provider is passed to the next in the list.</para>
|
||||
<para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you will
|
||||
still need configuration attributes that allow the
|
||||
<classname>MethodSecurityInterceptor</classname>'s
|
||||
<interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're using
|
||||
the typical Spring Security included <interfacename>AccessDecisionManager</interfacename>
|
||||
implementations, having no configuration attributes defined for a particular secure method
|
||||
invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to abstain from
|
||||
voting. In turn, if the <interfacename>AccessDecisionManager</interfacename> property
|
||||
"<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
|
||||
<literal>AccessDeniedException</literal> will be thrown. You may avoid this potential issue
|
||||
by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
|
||||
<literal>true</literal> (although this is generally not recommended) or (ii) simply ensure
|
||||
that there is at least one configuration attribute that an
|
||||
<interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
|
||||
latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal> or
|
||||
<literal>ROLE_AUTHENTICATED</literal> configuration attribute.</para>
|
||||
<!-- TODO: Move to ACL section and add reference here -->
|
||||
<!--
|
||||
<section xml:id="authz-after-invocation-handling">
|
||||
<info>
|
||||
<title>After Invocation Handling</title>
|
||||
</info>
|
||||
<para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
|
||||
<classname>AbstractSecurityInterceptor</classname> before proceeding with the secure
|
||||
object invocation, some applications need a way of modifying the object actually
|
||||
returned by the secure object invocation. Whilst you could easily implement your own AOP
|
||||
concern to achieve this, Spring Security provides a convenient hook that has several
|
||||
concrete implementations that integrate with its ACL capabilities.</para>
|
||||
<para><xref linkend="authz-after-invocation"/> illustrates Spring Security's
|
||||
<literal>AfterInvocationManager</literal> and its concrete implementations. <figure
|
||||
xml:id="authz-after-invocation">
|
||||
<title>After Invocation Implementation</title>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center" fileref="images/after-invocation.png" format="PNG"
|
||||
scale="75"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure></para>
|
||||
<para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal>
|
||||
has a single concrete implementation, <literal>AfterInvocationProviderManager</literal>,
|
||||
which polls a list of <literal>AfterInvocationProvider</literal>s. Each
|
||||
<literal>AfterInvocationProvider</literal> is allowed to modify the return object or
|
||||
throw an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify
|
||||
the object, as the result of the previous provider is passed to the next in the
|
||||
list.</para>
|
||||
<para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you
|
||||
will still need configuration attributes that allow the
|
||||
<classname>MethodSecurityInterceptor</classname>'s
|
||||
<interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're
|
||||
using the typical Spring Security included
|
||||
<interfacename>AccessDecisionManager</interfacename> implementations, having no
|
||||
configuration attributes defined for a particular secure method invocation will cause
|
||||
each <interfacename>AccessDecisionVoter</interfacename> to abstain from voting. In turn,
|
||||
if the <interfacename>AccessDecisionManager</interfacename> property
|
||||
"<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
|
||||
<literal>AccessDeniedException</literal> will be thrown. You may avoid this potential
|
||||
issue by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
|
||||
<literal>true</literal> (although this is generally not recommended) or (ii) simply
|
||||
ensure that there is at least one configuration attribute that an
|
||||
<interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
|
||||
latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal>
|
||||
or <literal>ROLE_AUTHENTICATED</literal> configuration attribute.</para>
|
||||
<!-- TODO: Move to ACL section and add reference here -->
|
||||
<!--
|
||||
<section xml:id="after-invocation-acl-aware">
|
||||
<info>
|
||||
<title>ACL-Aware AfterInvocationProviders</title>
|
||||
|
@ -285,8 +299,8 @@ boolean supports(Class clazz);
|
|||
<para>The Contacts sample application demonstrates these two
|
||||
<literal>AfterInvocationProvider</literal>s.</para>
|
||||
</section> -->
|
||||
</section>
|
||||
<!-- TODO: Move taglibs to a separate chapter which describes them all
|
||||
</section>
|
||||
<!-- TODO: Move taglibs to a separate chapter which describes them all
|
||||
<section xml:id="authorization-taglibs">
|
||||
<info>
|
||||
<title>Authorization Tag Libraries</title>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
authenticating calls made by Spring remoting protocols (such as Hessian and Burlap), as
|
||||
well as normal browser user agents (such as Firefox and Internet Explorer). The standard
|
||||
governing HTTP Basic Authentication is defined by RFC 1945, Section 11, and
|
||||
<literal>BasicAuthenticationFilter</literal> conforms with this RFC. Basic
|
||||
<literal>BasicAuthenticationFilter</literal> conforms with this RFC. Basic
|
||||
Authentication is an attractive approach to authentication, because it is very widely
|
||||
deployed in user agents and implementation is extremely simple (it's just a Base64
|
||||
encoding of the username:password, specified in an HTTP header).</para>
|
||||
|
@ -27,11 +27,10 @@
|
|||
<title>Configuration</title>
|
||||
</info>
|
||||
<para>To implement HTTP Basic Authentication, you need to add a
|
||||
<literal>BasicAuthenticationFilter</literal> to your filter chain. The
|
||||
application context should contain <literal>BasicAuthenticationFilter</literal> and
|
||||
its required collaborator:</para>
|
||||
<para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<literal>BasicAuthenticationFilter</literal> to your filter chain. The application
|
||||
context should contain <literal>BasicAuthenticationFilter</literal> and its required
|
||||
collaborator:</para>
|
||||
<para> <programlisting language="xml"><![CDATA[
|
||||
<bean id="basicAuthenticationFilter"
|
||||
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
|
@ -42,21 +41,20 @@
|
|||
class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
|
||||
<property name="realmName" value="Name Of Your Realm"/>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>The configured <interfacename>AuthenticationManager</interfacename> processes each
|
||||
authentication request. If authentication fails, the configured
|
||||
<interfacename>AuthenticationEntryPoint</interfacename> will be used to retry
|
||||
the authentication process. Usually you will use the filter in combination with a
|
||||
<literal>BasicAuthenticationEntryPoint</literal>, which returns a 401 response
|
||||
with a suitable header to retry HTTP Basic authentication. If authentication is
|
||||
<interfacename>AuthenticationEntryPoint</interfacename> will be used to retry the
|
||||
authentication process. Usually you will use the filter in combination with a
|
||||
<literal>BasicAuthenticationEntryPoint</literal>, which returns a 401 response with
|
||||
a suitable header to retry HTTP Basic authentication. If authentication is
|
||||
successful, the resulting <interfacename>Authentication</interfacename> object will
|
||||
be placed into the <classname>SecurityContextHolder</classname> as usual.</para>
|
||||
<para>If the authentication event was successful, or authentication was not attempted
|
||||
because the HTTP header did not contain a supported authentication request, the
|
||||
filter chain will continue as normal. The only time the filter chain will be
|
||||
interrupted is if authentication fails and the
|
||||
<interfacename>AuthenticationEntryPoint</interfacename> is called.</para>
|
||||
<interfacename>AuthenticationEntryPoint</interfacename> is called.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="digest-processing-filter">
|
||||
|
@ -70,7 +68,7 @@
|
|||
the Digest Authentication standard prescribed by RFC 2069. Most user agents implement
|
||||
RFC 2617. Spring Security's <classname>DigestAuthenticationFilter</classname> is
|
||||
compatible with the "<literal>auth</literal>" quality of protection
|
||||
(<literal>qop</literal>) prescribed by RFC 2617, which also provides backward
|
||||
(<literal>qop</literal>) prescribed by RFC 2617, which also provides backward
|
||||
compatibility with RFC 2069. Digest Authentication is a more attractive option if you
|
||||
need to use unencrypted HTTP (i.e. no TLS/HTTPS) and wish to maximise security of the
|
||||
authentication process. Indeed Digest Authentication is a mandatory requirement for the
|
||||
|
@ -86,11 +84,10 @@
|
|||
|
||||
expirationTime: The date and time when the nonce expires, expressed in milliseconds
|
||||
key: A private key to prevent modification of the nonce token
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>The <classname>DigestAuthenticatonEntryPoint</classname> has a property specifying the
|
||||
<literal>key</literal> used for generating the nonce tokens, along with a
|
||||
<literal>nonceValiditySeconds</literal> property for determining the expiration time
|
||||
<literal>key</literal> used for generating the nonce tokens, along with a
|
||||
<literal>nonceValiditySeconds</literal> property for determining the expiration time
|
||||
(default 300, which equals five minutes). Whist ever the nonce is valid, the digest is
|
||||
computed by concatenating various strings including the username, password, nonce, URI
|
||||
being requested, a client-generated nonce (merely a random value which the user agent
|
||||
|
@ -99,11 +96,11 @@
|
|||
if they disagree on an included value (eg password). In Spring Security implementation,
|
||||
if the server-generated nonce has merely expired (but the digest was otherwise valid),
|
||||
the <classname>DigestAuthenticationEntryPoint</classname> will send a
|
||||
<literal>"stale=true"</literal> header. This tells the user agent there is no need
|
||||
to disturb the user (as the password and username etc is correct), but simply to try
|
||||
again using a new nonce.</para>
|
||||
<literal>"stale=true"</literal> header. This tells the user agent there is no need to
|
||||
disturb the user (as the password and username etc is correct), but simply to try again
|
||||
using a new nonce.</para>
|
||||
<para>An appropriate value for <classname>DigestAuthenticationEntryPoint</classname>'s
|
||||
<literal>nonceValiditySeconds</literal> parameter will depend on your application.
|
||||
<literal>nonceValiditySeconds</literal> parameter will depend on your application.
|
||||
Extremely secure applications should note that an intercepted authentication header can
|
||||
be used to impersonate the principal until the <literal>expirationTime</literal>
|
||||
contained in the nonce is reached. This is the key principle when selecting an
|
||||
|
@ -111,21 +108,19 @@
|
|||
running over TLS/HTTPS in the first instance.</para>
|
||||
<para>Because of the more complex implementation of Digest Authentication, there are often
|
||||
user agent issues. For example, Internet Explorer fails to present an
|
||||
"<literal>opaque</literal>" token on subsequent requests in the same session. Spring
|
||||
"<literal>opaque</literal>" token on subsequent requests in the same session. Spring
|
||||
Security filters therefore encapsulate all state information into the
|
||||
"<literal>nonce</literal>" token instead. In our testing, Spring Security's
|
||||
"<literal>nonce</literal>" token instead. In our testing, Spring Security's
|
||||
implementation works reliably with FireFox and Internet Explorer, correctly handling
|
||||
nonce timeouts etc.</para>
|
||||
<section xml:id="digest-config">
|
||||
<title>Configuration</title>
|
||||
<para>Now that we've reviewed the theory, let's see how to use it. To implement HTTP
|
||||
Digest Authentication, it is necessary to define
|
||||
<literal>DigestAuthenticationFilter</literal> in the filter chain. The
|
||||
application context will need to define the
|
||||
<literal>DigestAuthenticationFilter</literal> and its required
|
||||
collaborators:</para>
|
||||
<para>
|
||||
<programlisting><![CDATA[
|
||||
<literal>DigestAuthenticationFilter</literal> in the filter chain. The application
|
||||
context will need to define the <literal>DigestAuthenticationFilter</literal> and
|
||||
its required collaborators:</para>
|
||||
<para> <programlisting><![CDATA[
|
||||
<bean id="digestFilter" class=
|
||||
"org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
|
||||
<property name="userDetailsService" ref="jdbcDaoImpl"/>
|
||||
|
@ -139,18 +134,17 @@
|
|||
<property name="key" value="acegi"/>
|
||||
<property name="nonceValiditySeconds" value="10"/>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>The configured <interfacename>UserDetailsService</interfacename> is needed because
|
||||
<literal>DigestAuthenticationFilter</literal> must have direct access to the
|
||||
clear text password of a user. Digest Authentication will NOT work if you are using
|
||||
<literal>DigestAuthenticationFilter</literal> must have direct access to the clear
|
||||
text password of a user. Digest Authentication will NOT work if you are using
|
||||
encoded passwords in your DAO. The DAO collaborator, along with the
|
||||
<literal>UserCache</literal>, are typically shared directly with a
|
||||
<classname>DaoAuthenticationProvider</classname>. The
|
||||
<literal>authenticationEntryPoint</literal> property must be
|
||||
<classname>DigestAuthenticationEntryPoint</classname>, so that
|
||||
<classname>DigestAuthenticationFilter</classname> can obtain the correct
|
||||
<literal>realmName</literal> and <literal>key</literal> for digest
|
||||
<literal>UserCache</literal>, are typically shared directly with a
|
||||
<classname>DaoAuthenticationProvider</classname>. The
|
||||
<literal>authenticationEntryPoint</literal> property must be
|
||||
<classname>DigestAuthenticationEntryPoint</classname>, so that
|
||||
<classname>DigestAuthenticationFilter</classname> can obtain the correct
|
||||
<literal>realmName</literal> and <literal>key</literal> for digest
|
||||
calculations.</para>
|
||||
<para>Like <literal>BasicAuthenticationFilter</literal>, if authentication is successful
|
||||
an <interfacename>Authentication</interfacename> request token will be placed into
|
||||
|
|
|
@ -1,44 +1,46 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>CAS Authentication</title>
|
||||
<section xml:id="cas-overview">
|
||||
<title>Overview</title>
|
||||
<para>JA-SIG produces an enterprise-wide single sign on system known as CAS. Unlike other
|
||||
initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to
|
||||
understand, platform independent, and supports proxy capabilities. Spring Security fully
|
||||
supports CAS, and provides an easy migration path from single-application deployments of
|
||||
Spring Security through to multiple-application deployments secured by an enterprise-wide CAS
|
||||
server.</para>
|
||||
<para>You can learn more about CAS at <literal>http://www.ja-sig.org/cas</literal>. You will
|
||||
also need to visit this site to download the CAS Server files.</para>
|
||||
</section>
|
||||
<section xml:id="cas-how-it-works">
|
||||
<info>
|
||||
<title>How CAS Works</title>
|
||||
</info>
|
||||
<para>Whilst the CAS web site contains documents that detail the architecture of CAS, we present
|
||||
the general overview again here within the context of Spring Security. Spring Security 3.0
|
||||
supports CAS 3. At the time of writing, the CAS server was at version 3.3.</para>
|
||||
<para>Somewhere in your enterprise you will need to setup a CAS server. The CAS server is simply
|
||||
a standard WAR file, so there isn't anything difficult about setting up your server. Inside
|
||||
the WAR file you will customise the login and other single sign on pages displayed to
|
||||
users.</para>
|
||||
<para>When deploying a CAS 3.3 server, you will also need to specify an
|
||||
<literal>AuthenticationHandler</literal> in the
|
||||
<filename>deployerConfigContext.xml</filename> included with CAS. The
|
||||
<literal>AuthenticationHandler</literal> has a simple method that returns a boolean as to
|
||||
whether a given set of Credentials is valid. Your <literal>AuthenticationHandler</literal>
|
||||
implementation will need to link into some type of backend authentication repository, such as
|
||||
an LDAP server or database. CAS itself includes numerous
|
||||
<literal>AuthenticationHandler</literal>s out of the box to assist with this. When you
|
||||
download and deploy the server war file, it is set up to successfully authenticate users who
|
||||
enter a password matching their username, which is useful for testing.</para>
|
||||
<para>Apart from the CAS server itself, the other key players are of course the secure web
|
||||
applications deployed throughout your enterprise. These web applications are known as
|
||||
"services". There are two types of services: standard services and proxy services. A proxy
|
||||
service is able to request resources from other services on behalf of the user. This will be
|
||||
explained more fully later.</para>
|
||||
<!--
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>CAS Authentication</title>
|
||||
<section xml:id="cas-overview">
|
||||
<title>Overview</title>
|
||||
<para>JA-SIG produces an enterprise-wide single sign on system known as CAS. Unlike other
|
||||
initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple
|
||||
to understand, platform independent, and supports proxy capabilities. Spring Security
|
||||
fully supports CAS, and provides an easy migration path from single-application
|
||||
deployments of Spring Security through to multiple-application deployments secured by an
|
||||
enterprise-wide CAS server.</para>
|
||||
<para>You can learn more about CAS at <literal>http://www.ja-sig.org/cas</literal>. You will
|
||||
also need to visit this site to download the CAS Server files.</para>
|
||||
</section>
|
||||
<section xml:id="cas-how-it-works">
|
||||
<info>
|
||||
<title>How CAS Works</title>
|
||||
</info>
|
||||
<para>Whilst the CAS web site contains documents that detail the architecture of CAS, we
|
||||
present the general overview again here within the context of Spring Security. Spring
|
||||
Security 3.0 supports CAS 3. At the time of writing, the CAS server was at version
|
||||
3.3.</para>
|
||||
<para>Somewhere in your enterprise you will need to setup a CAS server. The CAS server is
|
||||
simply a standard WAR file, so there isn't anything difficult about setting up your
|
||||
server. Inside the WAR file you will customise the login and other single sign on pages
|
||||
displayed to users.</para>
|
||||
<para>When deploying a CAS 3.3 server, you will also need to specify an
|
||||
<literal>AuthenticationHandler</literal> in the
|
||||
<filename>deployerConfigContext.xml</filename> included with CAS. The
|
||||
<literal>AuthenticationHandler</literal> has a simple method that returns a boolean as
|
||||
to whether a given set of Credentials is valid. Your
|
||||
<literal>AuthenticationHandler</literal> implementation will need to link into some type
|
||||
of backend authentication repository, such as an LDAP server or database. CAS itself
|
||||
includes numerous <literal>AuthenticationHandler</literal>s out of the box to assist
|
||||
with this. When you download and deploy the server war file, it is set up to
|
||||
successfully authenticate users who enter a password matching their username, which is
|
||||
useful for testing.</para>
|
||||
<para>Apart from the CAS server itself, the other key players are of course the secure web
|
||||
applications deployed throughout your enterprise. These web applications are known as
|
||||
"services". There are two types of services: standard services and proxy services. A
|
||||
proxy service is able to request resources from other services on behalf of the user.
|
||||
This will be explained more fully later.</para>
|
||||
<!--
|
||||
<section xml:id="cas-sequence">
|
||||
<title>Spring Security and CAS Interaction Sequence</title>
|
||||
|
||||
|
@ -243,36 +245,34 @@
|
|||
Let's now look at how this is configured</para>
|
||||
</section>
|
||||
-->
|
||||
</section>
|
||||
<section xml:id="cas-client">
|
||||
<info>
|
||||
<title>Configuration of CAS Client</title>
|
||||
</info>
|
||||
<para>The web application side of CAS is made easy due to Spring Security. It is assumed you
|
||||
already know the basics of using Spring Security, so these are not covered again below. We'll
|
||||
assume a namespace based configuration is being used and add in the CAS beans as required. </para>
|
||||
<para>You will need to add a <classname>ServiceProperties</classname> bean to your application
|
||||
context. This represents your CAS service:</para>
|
||||
<para>
|
||||
<programlisting><![CDATA[
|
||||
</section>
|
||||
<section xml:id="cas-client">
|
||||
<info>
|
||||
<title>Configuration of CAS Client</title>
|
||||
</info>
|
||||
<para>The web application side of CAS is made easy due to Spring Security. It is assumed you
|
||||
already know the basics of using Spring Security, so these are not covered again below.
|
||||
We'll assume a namespace based configuration is being used and add in the CAS beans as
|
||||
required. </para>
|
||||
<para>You will need to add a <classname>ServiceProperties</classname> bean to your
|
||||
application context. This represents your CAS service:</para>
|
||||
<para> <programlisting><![CDATA[
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>The <literal>service</literal> must equal a URL that will be monitored by the
|
||||
<literal>CasAuthenticationFilter</literal>. The <literal>sendRenew</literal> defaults to
|
||||
false, but should be set to true if your application is particularly sensitive. What this
|
||||
parameter does is tell the CAS login service that a single sign on login is unacceptable.
|
||||
Instead, the user will need to re-enter their username and password in order to gain access to
|
||||
the service.</para>
|
||||
<para>The following beans should be configured to commence the CAS authentication process
|
||||
(assuming you're using a namespace configuration):</para>
|
||||
<para>
|
||||
<programlisting><![CDATA[
|
||||
</programlisting> </para>
|
||||
<para>The <literal>service</literal> must equal a URL that will be monitored by the
|
||||
<literal>CasAuthenticationFilter</literal>. The <literal>sendRenew</literal> defaults to
|
||||
false, but should be set to true if your application is particularly sensitive. What
|
||||
this parameter does is tell the CAS login service that a single sign on login is
|
||||
unacceptable. Instead, the user will need to re-enter their username and password in
|
||||
order to gain access to the service.</para>
|
||||
<para>The following beans should be configured to commence the CAS authentication process
|
||||
(assuming you're using a namespace configuration):</para>
|
||||
<para> <programlisting><![CDATA[
|
||||
<security:http entry-point-ref="casEntryPoint">
|
||||
...
|
||||
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
|
||||
|
@ -289,21 +289,22 @@
|
|||
<property name="serviceProperties" ref="serviceProperties"/>
|
||||
</bean>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
|
||||
authentication using <link xlink:href="ns-entry-point-ref"
|
||||
><literal>entry-point-ref</literal></link>. </para>
|
||||
<para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based logins).
|
||||
</para>
|
||||
<para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have its
|
||||
<literal>authenticationEntryPoint</literal> property set to the
|
||||
<classname>CasAuthenticationEntryPoint</classname> bean.</para>
|
||||
<para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the
|
||||
<classname>ServiceProperties</classname> bean (discussed above), which provides the URL to the
|
||||
enterprise's CAS login server. This is where the user's browser will be redirected.</para>
|
||||
<para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its collaborators: <programlisting><![CDATA[
|
||||
</programlisting> </para>
|
||||
<para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
|
||||
authentication using <link xlink:href="ns-entry-point-ref"
|
||||
><literal>entry-point-ref</literal></link>. </para>
|
||||
<para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based
|
||||
logins). </para>
|
||||
<para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have
|
||||
its <literal>authenticationEntryPoint</literal> property set to the
|
||||
<classname>CasAuthenticationEntryPoint</classname> bean.</para>
|
||||
<para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the
|
||||
<classname>ServiceProperties</classname> bean (discussed above), which provides the URL
|
||||
to the enterprise's CAS login server. This is where the user's browser will be
|
||||
redirected.</para>
|
||||
<para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its
|
||||
collaborators: <programlisting><![CDATA[
|
||||
<security:authentication-manager alias="authenticationManager">
|
||||
<security:authentication-provider ref="casAuthenticationProvider" />
|
||||
</security:authentication-manager>
|
||||
|
@ -325,13 +326,14 @@
|
|||
...
|
||||
</security:user-service>]]>
|
||||
</programlisting> The
|
||||
<classname>CasAuthenticationProvider</classname> uses a
|
||||
<interfacename>UserDetailsService</interfacename> instance to load the authorities for a
|
||||
user, once they have been authentiated by CAS. We've shown a simple in-memory setup here. </para>
|
||||
<para>The beans are all reasonable self-explanatory if you refer back to the "How CAS Works"
|
||||
section.</para>
|
||||
</section>
|
||||
<!--
|
||||
<classname>CasAuthenticationProvider</classname> uses a
|
||||
<interfacename>UserDetailsService</interfacename> instance to load the authorities for a
|
||||
user, once they have been authentiated by CAS. We've shown a simple in-memory setup
|
||||
here. </para>
|
||||
<para>The beans are all reasonable self-explanatory if you refer back to the "How CAS Works"
|
||||
section.</para>
|
||||
</section>
|
||||
<!--
|
||||
<para>Note the <literal>CasProxyTicketValidator</literal> has a
|
||||
remarked out <literal>trustStore</literal> property. This property
|
||||
might be helpful if you experience HTTPS certificate issues. Also note
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
protocol, such as HTTPS.</para>
|
||||
<para>An important issue in considering transport security is that of session hijacking.
|
||||
Your web container manages a <literal>HttpSession</literal> by reference to a
|
||||
<literal>jsessionid</literal> that is sent to user agents either via a cookie or URL
|
||||
<literal>jsessionid</literal> that is sent to user agents either via a cookie or URL
|
||||
rewriting. If the <literal>jsessionid</literal> is ever sent over HTTP, there is a
|
||||
possibility that session identifier can be intercepted and used to impersonate the user
|
||||
after they complete the authentication process. This is because most web containers
|
||||
|
@ -23,19 +23,18 @@
|
|||
to HTTPS pages.</para>
|
||||
<para>If session hijacking is considered too significant a risk for your particular
|
||||
application, the only option is to use HTTPS for every request. This means the
|
||||
<literal>jsessionid</literal> is never sent across an insecure channel. You will
|
||||
need to ensure your <literal>web.xml</literal>-defined
|
||||
<literal><welcome-file></literal> points to an HTTPS location, and the
|
||||
application never directs the user to an HTTP location. Spring Security provides a
|
||||
solution to assist with the latter.</para>
|
||||
<literal>jsessionid</literal> is never sent across an insecure channel. You will need to
|
||||
ensure your <literal>web.xml</literal>-defined <literal><welcome-file></literal>
|
||||
points to an HTTPS location, and the application never directs the user to an HTTP
|
||||
location. Spring Security provides a solution to assist with the latter.</para>
|
||||
</section>
|
||||
<section xml:id="channel-security-config">
|
||||
<info>
|
||||
<title>Configuration</title>
|
||||
</info>
|
||||
<para>Channel security is supported by the <link xlink:href="#ns-requires-channel">security
|
||||
namespace</link> by means of the <literal>requires-channel</literal> attribute on
|
||||
the <literal><intercept-url></literal> element and this is the simplest (and
|
||||
namespace</link> by means of the <literal>requires-channel</literal> attribute on the
|
||||
<literal><intercept-url></literal> element and this is the simplest (and
|
||||
recommended approach).</para>
|
||||
<para>To configure channel security explicitly, you would define the following the filter in
|
||||
your application context: <programlisting><![CDATA[
|
||||
|
@ -74,14 +73,14 @@
|
|||
supported by the <literal>ChannelProcessingFilter</literal>.</para>
|
||||
<para>The <literal>ChannelProcessingFilter</literal> operates by filtering all web requests
|
||||
and determining the configuration attributes that apply. It then delegates to the
|
||||
<literal>ChannelDecisionManager</literal>. The default implementation,
|
||||
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most cases. It
|
||||
simply delegates to the list of configured <literal>ChannelProcessor</literal>
|
||||
instances. The attribute <literal>ANY_CHANNEL</literal> can be used to override this
|
||||
behaviour and skip a particular URL. Otherwise, a <literal>ChannelProcessor</literal>
|
||||
will review the request, and if it is unhappy with the request (e.g. if it was received
|
||||
across the incorrect transport protocol), it will perform a redirect, throw an exception
|
||||
or take whatever other action is appropriate.</para>
|
||||
<literal>ChannelDecisionManager</literal>. The default implementation,
|
||||
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most cases. It simply
|
||||
delegates to the list of configured <literal>ChannelProcessor</literal> instances. The
|
||||
attribute <literal>ANY_CHANNEL</literal> can be used to override this behaviour and skip
|
||||
a particular URL. Otherwise, a <literal>ChannelProcessor</literal> will review the
|
||||
request, and if it is unhappy with the request (e.g. if it was received across the
|
||||
incorrect transport protocol), it will perform a redirect, throw an exception or take
|
||||
whatever other action is appropriate.</para>
|
||||
<para>Included with Spring Security are two concrete <literal>ChannelProcessor</literal>
|
||||
implementations: <literal>SecureChannelProcessor</literal> ensures requests with a
|
||||
configuration attribute of <literal>REQUIRES_SECURE_CHANNEL</literal> are received over
|
||||
|
@ -89,27 +88,26 @@
|
|||
configuration attribute of <literal>REQUIRES_INSECURE_CHANNEL</literal> are received
|
||||
over HTTP. Both implementations delegate to a <literal>ChannelEntryPoint</literal> if
|
||||
the required transport protocol is not used. The two
|
||||
<literal>ChannelEntryPoint</literal> implementations included with Spring Security
|
||||
<literal>ChannelEntryPoint</literal> implementations included with Spring Security
|
||||
simply redirect the request to HTTP and HTTPS as appropriate. Appropriate defaults are
|
||||
assigned to the <literal>ChannelProcessor</literal> implementations for the
|
||||
configuration attribute keywords they respond to and the
|
||||
<interfacename>ChannelEntryPoint</interfacename> they delegate to, although you have
|
||||
the ability to override these using the application context.</para>
|
||||
<interfacename>ChannelEntryPoint</interfacename> they delegate to, although you have the
|
||||
ability to override these using the application context.</para>
|
||||
<para>Note that the redirections are absolute (eg
|
||||
<literal>http://www.company.com:8080/app/page</literal>), not relative (eg
|
||||
<literal>/app/page</literal>). During testing it was discovered that Internet
|
||||
Explorer 6 Service Pack 1 has a bug whereby it does not respond correctly to a
|
||||
redirection instruction which also changes the port to use. Accordingly, absolute URLs
|
||||
are used in conjunction with bug detection logic in the
|
||||
<classname>PortResolverImpl</classname> that is wired up by default to many Spring
|
||||
Security beans. Please refer to the JavaDocs for <classname>PortResolverImpl</classname>
|
||||
for further details.</para>
|
||||
<literal>http://www.company.com:8080/app/page</literal>), not relative (eg
|
||||
<literal>/app/page</literal>). During testing it was discovered that Internet Explorer 6
|
||||
Service Pack 1 has a bug whereby it does not respond correctly to a redirection
|
||||
instruction which also changes the port to use. Accordingly, absolute URLs are used in
|
||||
conjunction with bug detection logic in the <classname>PortResolverImpl</classname> that
|
||||
is wired up by default to many Spring Security beans. Please refer to the JavaDocs for
|
||||
<classname>PortResolverImpl</classname> for further details.</para>
|
||||
<para>You should note that using a secure channel is recommended if usernames and passwords
|
||||
are to be kept secure during the login process. If you do decide to use
|
||||
<classname>ChannelProcessingFilter</classname> with form-based login, please ensure
|
||||
that your login page is set to <literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
|
||||
<literal>LoginUrlAuthenticationEntryPoint.forceHttps</literal> property is
|
||||
<literal>true</literal>.</para>
|
||||
<classname>ChannelProcessingFilter</classname> with form-based login, please ensure that
|
||||
your login page is set to <literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
|
||||
<literal>LoginUrlAuthenticationEntryPoint.forceHttps</literal> property is
|
||||
<literal>true</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="channel-security-conclusion">
|
||||
<info>
|
||||
|
@ -118,25 +116,25 @@
|
|||
<para>Once configured, using the channel security filter is very easy. Simply request pages
|
||||
without regard to the protocol (ie HTTP or HTTPS) or port (eg 80, 8080, 443, 8443 etc).
|
||||
Obviously you'll still need a way of making the initial request (probably via the
|
||||
<literal>web.xml</literal>
|
||||
<literal><welcome-file></literal> or a well-known home page URL), but once this is
|
||||
done the filter will perform redirects as defined by your application context.</para>
|
||||
<literal>web.xml</literal> <literal><welcome-file></literal> or a well-known home
|
||||
page URL), but once this is done the filter will perform redirects as defined by your
|
||||
application context.</para>
|
||||
<para>You can also add your own <literal>ChannelProcessor</literal> implementations to the
|
||||
<literal>ChannelDecisionManagerImpl</literal>. For example, you might set a
|
||||
<literal>HttpSession</literal> attribute when a human user is detected via a "enter
|
||||
the contents of this graphic" procedure. Your <literal>ChannelProcessor</literal> would
|
||||
<literal>ChannelDecisionManagerImpl</literal>. For example, you might set a
|
||||
<literal>HttpSession</literal> attribute when a human user is detected via a "enter the
|
||||
contents of this graphic" procedure. Your <literal>ChannelProcessor</literal> would
|
||||
respond to say <literal>REQUIRES_HUMAN_USER</literal> configuration attributes and
|
||||
redirect to an appropriate entry point to start the human user validation process if the
|
||||
<literal>HttpSession</literal> attribute is not currently set.</para>
|
||||
<literal>HttpSession</literal> attribute is not currently set.</para>
|
||||
<para>To decide whether a security check belongs in a <literal>ChannelProcessor</literal> or
|
||||
an <interfacename>AccessDecisionVoter</interfacename>, remember that the former is
|
||||
designed to handle unauthenticated requests, whilst the latter is designed to handle
|
||||
authenticated requests. The latter therefore has access to the granted authorities of
|
||||
the authenticated principal. In addition, problems detected by a
|
||||
<literal>ChannelProcessor</literal> will generally cause an HTTP/HTTPS redirection
|
||||
so its requirements can be met, whilst problems detected by an
|
||||
<interfacename>AccessDecisionVoter</interfacename> will ultimately result in an
|
||||
<literal>AccessDeniedException</literal> (depending on the governing
|
||||
<interfacename>AccessDecisionManager</interfacename>).</para>
|
||||
<literal>ChannelProcessor</literal> will generally cause an HTTP/HTTPS redirection so
|
||||
its requirements can be met, whilst problems detected by an
|
||||
<interfacename>AccessDecisionVoter</interfacename> will ultimately result in an
|
||||
<literal>AccessDeniedException</literal> (depending on the governing
|
||||
<interfacename>AccessDecisionManager</interfacename>).</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
enhancement requests if you include corresponding unit tests. This is necessary to
|
||||
ensure project test coverage is adequately maintained.</para>
|
||||
<para>You can access the issue tracker at <link
|
||||
xlink:href="http://jira.springsource.org/browse/SEC"
|
||||
>http://jira.springsource.org/browse/SEC</link>. </para>
|
||||
xlink:href="http://jira.springsource.org/browse/SEC"
|
||||
>http://jira.springsource.org/browse/SEC</link>. </para>
|
||||
</section>
|
||||
<section xml:id="becoming-involved">
|
||||
<info>
|
||||
|
@ -42,7 +42,7 @@
|
|||
</info>
|
||||
<para>Questions and comments on Spring Security are welcome. You can use the Spring
|
||||
Community Forum web site at <uri xlink:href="http://forum.springsource.org"
|
||||
>http://forum.springsource.org</uri> to discuss Spring Security with other users of
|
||||
the framework. Remember to use JIRA for bug reports, as explained above.</para>
|
||||
>http://forum.springsource.org</uri> to discuss Spring Security with other users of the
|
||||
framework. Remember to use JIRA for bug reports, as explained above.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
<title><classname>FilterSecurityInterceptor</classname></title>
|
||||
<para>We've already seen <classname>FilterSecurityInterceptor</classname> briefly when
|
||||
discussing <link xlink:href="#tech-intro-access-control">access-control in
|
||||
general</link>, and we've already used it with the namespace where the
|
||||
<literal><intercept-url></literal> elements are combined to configure it
|
||||
internally. Now we'll see how to explicitly configure it for use with a
|
||||
<classname>FilterChainProxy</classname>, along with its companion filter
|
||||
<classname>ExceptionTranslationFilter</classname>. A typical configuration example
|
||||
is shown below: <programlisting language="xml"><![CDATA[
|
||||
general</link>, and we've already used it with the namespace where the
|
||||
<literal><intercept-url></literal> elements are combined to configure it internally.
|
||||
Now we'll see how to explicitly configure it for use with a
|
||||
<classname>FilterChainProxy</classname>, along with its companion filter
|
||||
<classname>ExceptionTranslationFilter</classname>. A typical configuration example is
|
||||
shown below: <programlisting language="xml"><![CDATA[
|
||||
<bean id="filterSecurityInterceptor"
|
||||
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
|
@ -28,43 +28,41 @@
|
|||
</bean>]]></programlisting></para>
|
||||
<para><classname>FilterSecurityInterceptor</classname> is responsible for handling the
|
||||
security of HTTP resources. It requires a reference to an
|
||||
<interfacename>AuthenticationManager</interfacename> and an
|
||||
<interfacename>AccessDecisionManager</interfacename>. It is also supplied with
|
||||
<interfacename>AuthenticationManager</interfacename> and an
|
||||
<interfacename>AccessDecisionManager</interfacename>. It is also supplied with
|
||||
configuration attributes that apply to different HTTP URL requests. Refer back to <link
|
||||
xlink:href="#tech-intro-config-attributes">the original discussion on these</link>
|
||||
in the technical introduction.</para>
|
||||
xlink:href="#tech-intro-config-attributes">the original discussion on these</link> in
|
||||
the technical introduction.</para>
|
||||
<para>The <classname>FilterSecurityInterceptor</classname> can be configured with
|
||||
configuration attributes in two ways. The first, which is shown above, is using the
|
||||
<literal><filter-security-metadata-source></literal> namespace element. This
|
||||
is similar to the <literal><filter-chain-map></literal> used to configure a
|
||||
<classname>FilterChainProxy</classname> but the
|
||||
<literal><intercept-url></literal> child elements only use the
|
||||
<literal>pattern</literal> and <literal>access</literal> attributes. Commas are used
|
||||
to delimit the different configuration attributes that apply to each HTTP URL. The
|
||||
second option is to write your own
|
||||
<literal><filter-security-metadata-source></literal> namespace element. This is
|
||||
similar to the <literal><filter-chain-map></literal> used to configure a
|
||||
<classname>FilterChainProxy</classname> but the <literal><intercept-url></literal>
|
||||
child elements only use the <literal>pattern</literal> and <literal>access</literal>
|
||||
attributes. Commas are used to delimit the different configuration attributes that apply
|
||||
to each HTTP URL. The second option is to write your own
|
||||
<interfacename>SecurityMetadataSource</interfacename>, but this is beyond the scope of
|
||||
this document. Irrespective of the approach used, the
|
||||
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning a
|
||||
<literal>List<ConfigAttribute></literal> containing all of the configuration
|
||||
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning a
|
||||
<literal>List<ConfigAttribute></literal> containing all of the configuration
|
||||
attributes associated with a single secure HTTP URL.</para>
|
||||
<para>It should be noted that the
|
||||
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal> method
|
||||
actually expects an instance of
|
||||
<interfacename>FilterSecurityMetadataSource</interfacename>. This is a marker
|
||||
interface which subclasses <interfacename>SecurityMetadataSource</interfacename>. It
|
||||
simply denotes the <interfacename>SecurityMetadataSource</interfacename> understands
|
||||
<classname>FilterInvocation</classname>s. In the interests of simplicity we'll
|
||||
continue to refer to the
|
||||
<interfacename>FilterInvocationSecurityMetadataSource</interfacename> as a
|
||||
<interfacename>SecurityMetadataSource</interfacename>, as the distinction is of
|
||||
little relevance to most users.</para>
|
||||
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal> method actually
|
||||
expects an instance of <interfacename>FilterSecurityMetadataSource</interfacename>. This
|
||||
is a marker interface which subclasses
|
||||
<interfacename>SecurityMetadataSource</interfacename>. It simply denotes the
|
||||
<interfacename>SecurityMetadataSource</interfacename> understands
|
||||
<classname>FilterInvocation</classname>s. In the interests of simplicity we'll continue
|
||||
to refer to the <interfacename>FilterInvocationSecurityMetadataSource</interfacename> as
|
||||
a <interfacename>SecurityMetadataSource</interfacename>, as the distinction is of little
|
||||
relevance to most users.</para>
|
||||
<para>The <interfacename>SecurityMetadataSource</interfacename> created by the namespace
|
||||
syntax obtains the configuration attributes for a particular
|
||||
<classname>FilterInvocation</classname> by matching the request URL against the
|
||||
<classname>FilterInvocation</classname> by matching the request URL against the
|
||||
configured <literal>pattern</literal> attributes. This behaves in the same way as it
|
||||
does for namespace configuration. The default is to treat all expressions as Apache Ant
|
||||
paths and regular expressions are also supported for more complex cases. The
|
||||
<literal>path-type</literal> attribute is used to specify the type of pattern being
|
||||
<literal>path-type</literal> attribute is used to specify the type of pattern being
|
||||
used. It is not possible to mix expression syntaxes within the same definition. As an
|
||||
example, the previous configuration using regular expressions instead of Ant paths would
|
||||
be written as follows:</para>
|
||||
|
@ -84,10 +82,10 @@
|
|||
<para>Patterns are always evaluated in the order they are defined. Thus it is important that
|
||||
more specific patterns are defined higher in the list than less specific patterns. This
|
||||
is reflected in our example above, where the more specific
|
||||
<literal>/secure/super/</literal> pattern appears higher than the less specific
|
||||
<literal>/secure/</literal> pattern. If they were reversed, the
|
||||
<literal>/secure/</literal> pattern would always match and the
|
||||
<literal>/secure/super/</literal> pattern would never be evaluated.</para>
|
||||
<literal>/secure/super/</literal> pattern appears higher than the less specific
|
||||
<literal>/secure/</literal> pattern. If they were reversed, the
|
||||
<literal>/secure/</literal> pattern would always match and the
|
||||
<literal>/secure/super/</literal> pattern would never be evaluated.</para>
|
||||
<!--
|
||||
TODO: Put in FAQ instead. Or drop.
|
||||
<para>As with other security interceptors, the <literal>validateConfigAttributes</literal>
|
||||
|
@ -101,10 +99,9 @@
|
|||
-->
|
||||
</section>
|
||||
<section xml:id="exception-translation-filter">
|
||||
<title>
|
||||
<classname>ExceptionTranslationFilter</classname></title>
|
||||
<title> <classname>ExceptionTranslationFilter</classname></title>
|
||||
<para>The <classname>ExceptionTranslationFilter</classname> sits above the
|
||||
<classname>FilterSecurityInterceptor</classname> in the security filter stack. It
|
||||
<classname>FilterSecurityInterceptor</classname> in the security filter stack. It
|
||||
doesn't do any actual security enforcement itself, but handles exceptions thrown by the
|
||||
security interceptors and provides suitable and HTTP responses. <programlisting language="xml"><![CDATA[
|
||||
<bean id="exceptionTranslationFilter"
|
||||
|
@ -127,11 +124,11 @@
|
|||
<title><interfacename>AuthenticationEntryPoint</interfacename></title>
|
||||
<para> The <interfacename>AuthenticationEntryPoint</interfacename> will be called if the
|
||||
user requests a secure HTTP resource but they are not authenticated. An appropriate
|
||||
<exceptionname>AuthenticationException</exceptionname> or
|
||||
<exceptionname>AccessDeniedException</exceptionname> will be thrown by a
|
||||
security interceptor further down the call stack, triggering the
|
||||
<methodname>commence</methodname> method on the entry point. This does the job
|
||||
of presenting the appropriate response to the user so that authentication can begin.
|
||||
<exceptionname>AuthenticationException</exceptionname> or
|
||||
<exceptionname>AccessDeniedException</exceptionname> will be thrown by a security
|
||||
interceptor further down the call stack, triggering the
|
||||
<methodname>commence</methodname> method on the entry point. This does the job of
|
||||
presenting the appropriate response to the user so that authentication can begin.
|
||||
The one we've used here is <classname>LoginUrlAuthenticationEntryPoint</classname>,
|
||||
which redirects the request to a different URL (typically a login page). The actual
|
||||
implementation used will depend on the authentication mechanism you want to be used
|
||||
|
@ -153,32 +150,31 @@
|
|||
<para>If an <exceptionname>AccessDeniedException</exceptionname> is thrown and a user
|
||||
has already been authenticated, then this means that an operation has been attempted
|
||||
for which they don't have enough permissions. In this case,
|
||||
<classname>ExceptionTranslationFilter</classname> will invoke a second strategy,
|
||||
the <interfacename>AccessDeniedHandler</interfacename>. By default, an
|
||||
<classname>AccessDeniedHandlerImpl</classname> is used, which just sends a 403
|
||||
<classname>ExceptionTranslationFilter</classname> will invoke a second strategy, the
|
||||
<interfacename>AccessDeniedHandler</interfacename>. By default, an
|
||||
<classname>AccessDeniedHandlerImpl</classname> is used, which just sends a 403
|
||||
(Forbidden) response to the client. Alternatively you can configure an instance
|
||||
explicitly (as in the above example) and set an error page URL which it will
|
||||
forwards the request to <footnote>
|
||||
<para>We use a forward so that the SecurityContextHolder still contains details
|
||||
of the principal, which may be useful for displaying to the user. In old
|
||||
releases of Spring Security we relied upon the servlet container to handle a
|
||||
403 error message, which lacked this useful contextual information.</para>
|
||||
<para>We use a forward so that the SecurityContextHolder still contains details of
|
||||
the principal, which may be useful for displaying to the user. In old releases
|
||||
of Spring Security we relied upon the servlet container to handle a 403 error
|
||||
message, which lacked this useful contextual information.</para>
|
||||
</footnote>. This can be a simple <quote>access denied</quote> page, such as a JSP,
|
||||
or it could be a more complex handler such as an MVC controller. And of course, you
|
||||
can implement the interface yourself and use your own implementation. </para>
|
||||
<para>It's also possible to supply a custom
|
||||
<interfacename>AccessDeniedHandler</interfacename> when you're using the
|
||||
namespace to configure your application. See <link
|
||||
xlink:href="#nsa-access-denied-handler">the namespace appendix</link> for more
|
||||
details.</para>
|
||||
<interfacename>AccessDeniedHandler</interfacename> when you're using the namespace
|
||||
to configure your application. See <link xlink:href="#nsa-access-denied-handler">the
|
||||
namespace appendix</link> for more details.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="security-context-persistence-filter">
|
||||
<title><classname>SecurityContextPersistenceFilter</classname></title>
|
||||
<para> We covered the purpose of this all-important filter in the <link
|
||||
xlink:href="#tech-intro-sec-context-persistence">Technical Overview</link> chapter
|
||||
so you might want to re-read that section at this point. Let's first take a look at how
|
||||
you would configure it for use with a <classname>FilterChainProxy</classname>. A basic
|
||||
xlink:href="#tech-intro-sec-context-persistence">Technical Overview</link> chapter so
|
||||
you might want to re-read that section at this point. Let's first take a look at how you
|
||||
would configure it for use with a <classname>FilterChainProxy</classname>. A basic
|
||||
configuration only requires the bean itself <programlisting><![CDATA[
|
||||
<bean id="securityContextPersistenceFilter"
|
||||
class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
|
||||
|
@ -205,19 +201,19 @@ public interface SecurityContextRepository {
|
|||
incoming request and response objects, allowing the implementation to replace these
|
||||
with wrapper classes. The returned contents will be passed to the filter chain. </para>
|
||||
<para> The default implementation is
|
||||
<classname>HttpSessionSecurityContextRepository</classname>, which stores the
|
||||
<classname>HttpSessionSecurityContextRepository</classname>, which stores the
|
||||
security context as an <interfacename>HttpSession</interfacename> attribute <footnote>
|
||||
<para>In Spring Security 2.0 and earlier, this filter was called
|
||||
<classname>HttpSessionContextIntegrationFilter</classname> and performed
|
||||
all the work of storing the context was performed by the filter itself. If
|
||||
you were familiar with this class, then most of the configuration options
|
||||
which were available can now be found on
|
||||
<classname>HttpSessionSecurityContextRepository</classname>. </para>
|
||||
<para>In Spring Security 2.0 and earlier, this filter was called
|
||||
<classname>HttpSessionContextIntegrationFilter</classname> and performed all the
|
||||
work of storing the context was performed by the filter itself. If you were
|
||||
familiar with this class, then most of the configuration options which were
|
||||
available can now be found on
|
||||
<classname>HttpSessionSecurityContextRepository</classname>. </para>
|
||||
</footnote>. The most important configuration parameter for this implementation is
|
||||
the <literal>allowSessionCreation</literal> property, which defaults to
|
||||
<literal>true</literal>, thus allowing the class to create a session if it needs
|
||||
one to store the security context for an authenticated user (it won't create one
|
||||
unless authentication has taken place and the contents of the security context have
|
||||
<literal>true</literal>, thus allowing the class to create a session if it needs one
|
||||
to store the security context for an authenticated user (it won't create one unless
|
||||
authentication has taken place and the contents of the security context have
|
||||
changed). If you don't want a session to be created, then you can set this property
|
||||
to <literal>false</literal>: <programlisting language="xml"><![CDATA[
|
||||
<bean id="securityContextPersistenceFilter"
|
||||
|
@ -229,7 +225,7 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
|
|||
</property>
|
||||
</bean>
|
||||
]]></programlisting> Alternatively you could provide a null implementation of the
|
||||
<interfacename>SecurityContextRepository</interfacename> interface, which will
|
||||
<interfacename>SecurityContextRepository</interfacename> interface, which will
|
||||
prevent the security context from being stored, even if a session has already been
|
||||
created during the request. </para>
|
||||
</section>
|
||||
|
@ -242,35 +238,35 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
|
|||
alternatives. The only thing that's missing now is an actual authentication mechanism,
|
||||
something that will allow a user to authenticate. This filter is the most commonly used
|
||||
authentication filter and the one that is most often customized <footnote>
|
||||
<para>For historical reasons, prior to Spring Security 3.0, this filter was called
|
||||
<classname>AuthenticationProcessingFilter</classname> and the entry point
|
||||
was called <classname>AuthenticationProcessingFilterEntryPoint</classname>.
|
||||
Since the framework now supports many different forms of authentication, they
|
||||
have both been given more specific names in 3.0.</para>
|
||||
<para>For historical reasons, prior to Spring Security 3.0, this filter was called
|
||||
<classname>AuthenticationProcessingFilter</classname> and the entry point was called
|
||||
<classname>AuthenticationProcessingFilterEntryPoint</classname>. Since the framework
|
||||
now supports many different forms of authentication, they have both been given more
|
||||
specific names in 3.0.</para>
|
||||
</footnote>. It also provides the implementation used by the
|
||||
<literal><form-login></literal> element from the namespace. There are three
|
||||
stages required to configure it. <orderedlist>
|
||||
<listitem>
|
||||
<para>Configure a <classname>LoginUrlAuthenticationEntryPoint</classname> with
|
||||
the URL of the login page, just as we did above, and set it on the
|
||||
<classname>ExceptionTranslationFilter</classname>. </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Implement the login page (using a JSP or MVC controller).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Configure an instance of
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname> in the
|
||||
application context</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Add the filter bean to your filter chain proxy (making sure you pay
|
||||
attention to the order). <!-- TODO: link --></para>
|
||||
</listitem>
|
||||
<literal><form-login></literal> element from the namespace. There are three stages
|
||||
required to configure it. <orderedlist>
|
||||
<listitem>
|
||||
<para>Configure a <classname>LoginUrlAuthenticationEntryPoint</classname> with the
|
||||
URL of the login page, just as we did above, and set it on the
|
||||
<classname>ExceptionTranslationFilter</classname>. </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Implement the login page (using a JSP or MVC controller).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Configure an instance of
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname> in the application
|
||||
context</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Add the filter bean to your filter chain proxy (making sure you pay attention
|
||||
to the order). <!-- TODO: link --></para>
|
||||
</listitem>
|
||||
</orderedlist> The login form simply contains <literal>j_username</literal> and
|
||||
<literal>j_password</literal> input fields, and posts to the URL that is monitored
|
||||
by the filter (by default this is <literal>/j_spring_security_check</literal>). The
|
||||
basic filter configuration looks something like this: <programlisting><![CDATA[
|
||||
<literal>j_password</literal> input fields, and posts to the URL that is monitored by
|
||||
the filter (by default this is <literal>/j_spring_security_check</literal>). The basic
|
||||
filter configuration looks something like this: <programlisting><![CDATA[
|
||||
<bean id="authenticationFilter" class=
|
||||
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
|
@ -280,38 +276,37 @@ class="org.springframework.security.web.context.SecurityContextPersistenceFilter
|
|||
<section xml:id="form-login-flow-handling">
|
||||
<title>Application Flow on Authentication Success and Failure</title>
|
||||
<para> The filter calls the configured
|
||||
<interfacename>AuthenticationManager</interfacename> to process each
|
||||
authentication request. The destination following a successful authentication or an
|
||||
authentication failure is controlled by the
|
||||
<interfacename>AuthenticationSuccessHandler</interfacename> and
|
||||
<interfacename>AuthenticationFailureHandler</interfacename> strategy interfaces,
|
||||
<interfacename>AuthenticationManager</interfacename> to process each authentication
|
||||
request. The destination following a successful authentication or an authentication
|
||||
failure is controlled by the
|
||||
<interfacename>AuthenticationSuccessHandler</interfacename> and
|
||||
<interfacename>AuthenticationFailureHandler</interfacename> strategy interfaces,
|
||||
respectively. The filter has properties which allow you to set these so you can
|
||||
customize the behaviour completely <footnote>
|
||||
<para>In versions prior to 3.0, the application flow at this point had evolved
|
||||
to a stage was controlled by a mix of properties on this class and strategy
|
||||
plugins. The decision was made for 3.0 to refactor the code to make these
|
||||
two strategies entirely responsible. </para>
|
||||
<para>In versions prior to 3.0, the application flow at this point had evolved to a
|
||||
stage was controlled by a mix of properties on this class and strategy plugins.
|
||||
The decision was made for 3.0 to refactor the code to make these two strategies
|
||||
entirely responsible. </para>
|
||||
</footnote>. Some standard implementations are supplied such as
|
||||
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
|
||||
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
|
||||
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
|
||||
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look
|
||||
at the Javadoc for these classes to see how they work. </para>
|
||||
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
|
||||
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
|
||||
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
|
||||
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at
|
||||
the Javadoc for these classes to see how they work. </para>
|
||||
<para>If authentication is successful, the resulting
|
||||
<interfacename>Authentication</interfacename> object will be placed into the
|
||||
<classname>SecurityContextHolder</classname>. The configured
|
||||
<interfacename>AuthenticationSuccessHandler</interfacename> will then be called
|
||||
to either redirect or forward the user to the appropriate destination. By default a
|
||||
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname> is used,
|
||||
which means that the user will be redirected to the original destination they
|
||||
requested before they were asked to login. <note>
|
||||
<para> The <classname>ExceptionTranslationFilter</classname> caches the original
|
||||
request a user makes. When the user authenticates, the request handler makes
|
||||
use of this cached request to obtain the original URL and redirect to it.
|
||||
The original request is then rebuilt and used as an alternative. </para>
|
||||
<interfacename>Authentication</interfacename> object will be placed into the
|
||||
<classname>SecurityContextHolder</classname>. The configured
|
||||
<interfacename>AuthenticationSuccessHandler</interfacename> will then be called to
|
||||
either redirect or forward the user to the appropriate destination. By default a
|
||||
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname> is used, which
|
||||
means that the user will be redirected to the original destination they requested
|
||||
before they were asked to login. <note>
|
||||
<para> The <classname>ExceptionTranslationFilter</classname> caches the original
|
||||
request a user makes. When the user authenticates, the request handler makes use
|
||||
of this cached request to obtain the original URL and redirect to it. The
|
||||
original request is then rebuilt and used as an alternative. </para>
|
||||
</note> If authentication fails, the configured
|
||||
<interfacename>AuthenticationFailureHandler</interfacename> will be invoked.
|
||||
</para>
|
||||
<interfacename>AuthenticationFailureHandler</interfacename> will be invoked. </para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -4,42 +4,40 @@
|
|||
<para> Now that we have a high-level overview of the Spring Security architecture and its core
|
||||
classes, let's take a closer look at one or two of the core interfaces and their
|
||||
implementations, in particular the <interfacename>AuthenticationManager</interfacename>,
|
||||
<interfacename>UserDetailsService</interfacename> and the
|
||||
<interfacename>AccessDecisionManager</interfacename>. These crop up regularly throughout
|
||||
the remainder of this document so it's important you know how they are configured and how
|
||||
they operate. </para>
|
||||
<interfacename>UserDetailsService</interfacename> and the
|
||||
<interfacename>AccessDecisionManager</interfacename>. These crop up regularly throughout the
|
||||
remainder of this document so it's important you know how they are configured and how they
|
||||
operate. </para>
|
||||
<section xml:id="core-services-authentication-manager">
|
||||
<title>The <interfacename>AuthenticationManager</interfacename>,
|
||||
<classname>ProviderManager</classname> and
|
||||
<classname>AuthenticationProvider</classname>s</title>
|
||||
<classname>ProviderManager</classname> and
|
||||
<classname>AuthenticationProvider</classname>s</title>
|
||||
<para>The <interfacename>AuthenticationManager</interfacename> is just an interface, so the
|
||||
implementation can be anything we choose, but how does it work in practice? What if we
|
||||
need to check multiple authentication databases or a combination of different
|
||||
authentication services such as a database and an LDAP server?</para>
|
||||
<para>The default implementation in Spring Security is called
|
||||
<classname>ProviderManager</classname> and rather than handling the authentication
|
||||
<classname>ProviderManager</classname> and rather than handling the authentication
|
||||
request itself, it delegates to a list of configured
|
||||
<classname>AuthenticationProvider</classname>s, each of which is queried in turn to
|
||||
see if it can perform the authentication. Each provider will either throw an exception
|
||||
or return a fully populated <interfacename>Authentication</interfacename> object.
|
||||
Remember our good friends, <interfacename>UserDetails</interfacename> and
|
||||
<interfacename>UserDetailsService</interfacename>? If not, head back to the previous
|
||||
<classname>AuthenticationProvider</classname>s, each of which is queried in turn to see
|
||||
if it can perform the authentication. Each provider will either throw an exception or
|
||||
return a fully populated <interfacename>Authentication</interfacename> object. Remember
|
||||
our good friends, <interfacename>UserDetails</interfacename> and
|
||||
<interfacename>UserDetailsService</interfacename>? If not, head back to the previous
|
||||
chapter and refresh your memory. The most common approach to verifying an authentication
|
||||
request is to load the corresponding <interfacename>UserDetails</interfacename> and
|
||||
check the loaded password against the one that has been entered by the user. This is the
|
||||
approach used by the <classname>DaoAuthenticationProvider</classname> (see below). The
|
||||
loaded <interfacename>UserDetails</interfacename> object - and particularly the
|
||||
<literal>GrantedAuthority</literal>s it contains - will be used when building the
|
||||
fully populated <interfacename>Authentication</interfacename> object which is returned
|
||||
from a successful authentication and stored in the
|
||||
<classname>SecurityContext</classname>. </para>
|
||||
<para> If you are using the namespace, an instance of
|
||||
<classname>ProviderManager</classname> is created and maintained internally, and
|
||||
you add providers to it by using the namespace authentication provider elements
|
||||
(see <link xlink:href="#ns-auth-manager">the namespace chapter</link>). In this
|
||||
case, you should not declare a <classname>ProviderManager</classname> bean in your
|
||||
application context. However, if you are not using the namespace then you would declare
|
||||
it like so: <programlisting language="xml"><![CDATA[
|
||||
<literal>GrantedAuthority</literal>s it contains - will be used when building the fully
|
||||
populated <interfacename>Authentication</interfacename> object which is returned from a
|
||||
successful authentication and stored in the <classname>SecurityContext</classname>. </para>
|
||||
<para> If you are using the namespace, an instance of <classname>ProviderManager</classname>
|
||||
is created and maintained internally, and you add providers to it by using the namespace
|
||||
authentication provider elements (see <link xlink:href="#ns-auth-manager">the namespace
|
||||
chapter</link>). In this case, you should not declare a
|
||||
<classname>ProviderManager</classname> bean in your application context. However, if you
|
||||
are not using the namespace then you would declare it like so: <programlisting language="xml"><![CDATA[
|
||||
<bean id="authenticationManager"
|
||||
class="org.springframework.security.authentication.ProviderManager">
|
||||
<property name="providers">
|
||||
|
@ -54,16 +52,16 @@
|
|||
is implied by the use of a <literal>List</literal>), with each provider able to attempt
|
||||
authentication, or skip authentication by simply returning <literal>null</literal>. If
|
||||
all implementations return null, the <literal>ProviderManager</literal> will throw a
|
||||
<exceptionname>ProviderNotFoundException</exceptionname>. If you're interested in
|
||||
<exceptionname>ProviderNotFoundException</exceptionname>. If you're interested in
|
||||
learning more about chaining providers, please refer to the
|
||||
<literal>ProviderManager</literal> JavaDocs.</para>
|
||||
<literal>ProviderManager</literal> JavaDocs.</para>
|
||||
<para> Authentication mechanisms such as a web form-login processing filter are injected
|
||||
with a reference to the <interfacename>ProviderManager</interfacename> and will call it
|
||||
to handle their authentication requests. The providers you require will sometimes be
|
||||
interchangeable with the authentication mechanisms, while at other times they will
|
||||
depend on a specific authentication mechanism. For example,
|
||||
<classname>DaoAuthenticationProvider</classname> and
|
||||
<classname>LdapAuthenticationProvider</classname> are compatible with any mechanism
|
||||
<classname>DaoAuthenticationProvider</classname> and
|
||||
<classname>LdapAuthenticationProvider</classname> are compatible with any mechanism
|
||||
which submits a simple username/password authentication request and so will work with
|
||||
form-based logins or HTTP Basic authentication. On the other hand, some authentication
|
||||
mechanisms create an authentication request object which can only be interpreted by a
|
||||
|
@ -78,49 +76,47 @@
|
|||
<para>The simplest <interfacename>AuthenticationProvider</interfacename> implemented by
|
||||
Spring Security is <literal>DaoAuthenticationProvider</literal>, which is also one
|
||||
of the earliest supported by the framework. It leverages a
|
||||
<interfacename>UserDetailsService</interfacename> (as a DAO) in order to lookup
|
||||
the username, password and <interfacename>GrantedAuthority</interfacename>s. It
|
||||
<interfacename>UserDetailsService</interfacename> (as a DAO) in order to lookup the
|
||||
username, password and <interfacename>GrantedAuthority</interfacename>s. It
|
||||
authenticates the user simply by comparing the password submitted in a
|
||||
<classname>UsernamePasswordAuthenticationToken</classname> against the one
|
||||
loaded by the <interfacename>UserDetailsService</interfacename>. Configuring the
|
||||
provider is quite simple: <programlisting language="xml"><![CDATA[
|
||||
<classname>UsernamePasswordAuthenticationToken</classname> against the one loaded by
|
||||
the <interfacename>UserDetailsService</interfacename>. Configuring the provider is
|
||||
quite simple: <programlisting language="xml"><![CDATA[
|
||||
<bean id="daoAuthenticationProvider"
|
||||
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
|
||||
<property name="saltSource" ref bean="saltSource"/>
|
||||
<property name="passwordEncoder" ref="passwordEncoder"/>
|
||||
</bean>]]></programlisting> The <interfacename>PasswordEncoder</interfacename> and
|
||||
<interfacename>SaltSource</interfacename> are optional. A
|
||||
<interfacename>PasswordEncoder</interfacename> provides encoding and decoding of
|
||||
<interfacename>SaltSource</interfacename> are optional. A
|
||||
<interfacename>PasswordEncoder</interfacename> provides encoding and decoding of
|
||||
passwords presented in the <interfacename>UserDetails</interfacename> object that is
|
||||
returned from the configured <interfacename>UserDetailsService</interfacename>. A
|
||||
<interfacename>SaltSource</interfacename> enables the passwords to be populated
|
||||
with a "salt", which enhances the security of the passwords in the authentication
|
||||
<interfacename>SaltSource</interfacename> enables the passwords to be populated with
|
||||
a "salt", which enhances the security of the passwords in the authentication
|
||||
repository. These will be discussed in more detail <link
|
||||
xlink:href="core-services-password-encodin">below</link>. </para>
|
||||
xlink:href="core-services-password-encodin">below</link>. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title><interfacename>UserDetailsService</interfacename> Implementations</title>
|
||||
<para>As mentioned in the earlier in this reference guide, most authentication providers
|
||||
take advantage of the <interfacename>UserDetails</interfacename> and
|
||||
<interfacename>UserDetailsService</interfacename> interfaces. Recall that the
|
||||
contract for <interfacename>UserDetailsService</interfacename> is a single
|
||||
method:</para>
|
||||
<interfacename>UserDetailsService</interfacename> interfaces. Recall that the contract
|
||||
for <interfacename>UserDetailsService</interfacename> is a single method:</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>The returned <interfacename>UserDetails</interfacename> is an interface that provides
|
||||
getters that guarantee non-null provision of authentication information such as the
|
||||
username, password, granted authorities and whether the user account is enabled or
|
||||
disabled. Most authentication providers will use a
|
||||
<interfacename>UserDetailsService</interfacename>, even if the username and password
|
||||
are not actually used as part of the authentication decision. They may use the returned
|
||||
<interfacename>UserDetails</interfacename> object just for its
|
||||
<literal>GrantedAuthority</literal> information, because some other system (like
|
||||
LDAP or X.509 or CAS etc) has undertaken the responsibility of actually validating the
|
||||
<interfacename>UserDetailsService</interfacename>, even if the username and password are
|
||||
not actually used as part of the authentication decision. They may use the returned
|
||||
<interfacename>UserDetails</interfacename> object just for its
|
||||
<literal>GrantedAuthority</literal> information, because some other system (like LDAP or
|
||||
X.509 or CAS etc) has undertaken the responsibility of actually validating the
|
||||
credentials.</para>
|
||||
<para>Given <interfacename>UserDetailsService</interfacename> is so simple to implement, it
|
||||
should be easy for users to retrieve authentication information using a persistence
|
||||
|
@ -133,8 +129,8 @@
|
|||
many applications do not require such complexity. This is particularly true if
|
||||
you're building a prototype application or just starting integrating Spring
|
||||
Security, when you don't really want to spend time configuring databases or writing
|
||||
<interfacename>UserDetailsService</interfacename> implementations. For this sort
|
||||
of situation, a simple option is to use the <literal>user-service</literal> element
|
||||
<interfacename>UserDetailsService</interfacename> implementations. For this sort of
|
||||
situation, a simple option is to use the <literal>user-service</literal> element
|
||||
from the security <link xlink:href="#ns-minimal">namespace</link>: <programlisting><![CDATA[
|
||||
<user-service id="userDetailsService">
|
||||
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
|
||||
|
@ -158,11 +154,10 @@
|
|||
Spring JDBC is used, so it avoids the complexity of a fully-featured object
|
||||
relational mapper (ORM) just to store user details. If your application does use an
|
||||
ORM tool, you might prefer to write a custom
|
||||
<interfacename>UserDetailsService</interfacename> to reuse the mapping files
|
||||
you've probably already created. Returning to <literal>JdbcDaoImpl</literal>, an
|
||||
example configuration is shown below:</para>
|
||||
<para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<interfacename>UserDetailsService</interfacename> to reuse the mapping files you've
|
||||
probably already created. Returning to <literal>JdbcDaoImpl</literal>, an example
|
||||
configuration is shown below:</para>
|
||||
<para> <programlisting language="xml"><![CDATA[
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
|
||||
|
@ -173,19 +168,17 @@
|
|||
<bean id="userDetailsService"
|
||||
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean> ]]> </programlisting>
|
||||
</para>
|
||||
</bean> ]]> </programlisting> </para>
|
||||
<para>You can use different relational database management systems by modifying the
|
||||
<literal>DriverManagerDataSource</literal> shown above. You can also use a
|
||||
global data source obtained from JNDI, as with any other Spring
|
||||
configuration.</para>
|
||||
<literal>DriverManagerDataSource</literal> shown above. You can also use a global
|
||||
data source obtained from JNDI, as with any other Spring configuration.</para>
|
||||
<section>
|
||||
<title>Authority Groups</title>
|
||||
<para>By default, <classname>JdbcDaoImpl</classname> loads the authorities for a
|
||||
single user with the assumption that the authorities are mapped directly to
|
||||
users (see the <link xlink:href="#appendix-schema">database schema
|
||||
appendix</link>). An alternative approach is to partition the authorities
|
||||
into groups and assign groups to the user. Some people prefer this approach as a
|
||||
appendix</link>). An alternative approach is to partition the authorities into
|
||||
groups and assign groups to the user. Some people prefer this approach as a
|
||||
means of administering user rights. See the <classname>JdbcDaoImpl</classname>
|
||||
Javadoc for more information on how to enable the use of group authorities. The
|
||||
group schema is also included in the appendix.</para>
|
||||
|
@ -218,7 +211,7 @@
|
|||
<programlisting>
|
||||
5f4dcc3b5aa765d61d8327deb882cf99
|
||||
</programlisting> A hash is
|
||||
<quote>one-way</quote> in the sense that it is very difficult (effectively
|
||||
<quote>one-way</quote> in the sense that it is very difficult (effectively
|
||||
impossible) to obtain the original input given the hash value, or indeed any
|
||||
possible input which would produce that hash value. This property makes hash values
|
||||
very useful for authentication purposes. They can be stored in your user database as
|
||||
|
@ -231,16 +224,16 @@
|
|||
<para> One potential problem with the use of password hashes that it is relatively easy
|
||||
to get round the one-way property of the hash if a common word is used for the
|
||||
input. For example, if you search for the hash value
|
||||
<literal>5f4dcc3b5aa765d61d8327deb882cf99</literal> using google, you will
|
||||
quickly find the original word <quote>password</quote>. In a similar way, an
|
||||
attacker can build a dictionary of hashes from a standard word list and use this to
|
||||
lookup the original password. One way to help prevent this is to have a suitably
|
||||
strong password policy to try to prevent common words from being used. Another is to
|
||||
use a <quote>salt</quote> when calculating the hashes. This is an additional string
|
||||
of known data for each user which is combined with the password before calculating
|
||||
the hash. Ideally the data should be as random as possible, but in practice any salt
|
||||
<literal>5f4dcc3b5aa765d61d8327deb882cf99</literal> using google, you will quickly
|
||||
find the original word <quote>password</quote>. In a similar way, an attacker can
|
||||
build a dictionary of hashes from a standard word list and use this to lookup the
|
||||
original password. One way to help prevent this is to have a suitably strong
|
||||
password policy to try to prevent common words from being used. Another is to use a
|
||||
<quote>salt</quote> when calculating the hashes. This is an additional string of
|
||||
known data for each user which is combined with the password before calculating the
|
||||
hash. Ideally the data should be as random as possible, but in practice any salt
|
||||
value is usually preferable to none. Spring Security has a
|
||||
<interfacename>SaltSource</interfacename> interface which can be used by an
|
||||
<interfacename>SaltSource</interfacename> interface which can be used by an
|
||||
authentication provider to generate a salt value for a particular user. Using a salt
|
||||
means that an attacker has to build a separate dictionary of hashes for each salt
|
||||
value, making the attack more complicated (but not impossible).</para>
|
||||
|
@ -248,32 +241,32 @@
|
|||
<section>
|
||||
<title> Hashing and Authentication</title>
|
||||
<para>When an authentication provider (such as Spring Security's
|
||||
<classname>DaoAuthenticationProvider</classname> needs to check the password in
|
||||
a submitted authentication request against the known value for a user, and the
|
||||
stored password is encoded in some way, then the submitted value must be encoded
|
||||
using exactly the same algorithm. It's up to you to check that these are compatible
|
||||
as Spring Security has no control over the persistent values. If you add password
|
||||
<classname>DaoAuthenticationProvider</classname> needs to check the password in a
|
||||
submitted authentication request against the known value for a user, and the stored
|
||||
password is encoded in some way, then the submitted value must be encoded using
|
||||
exactly the same algorithm. It's up to you to check that these are compatible as
|
||||
Spring Security has no control over the persistent values. If you add password
|
||||
hashing to your authentication configuration in Spring Security, and your database
|
||||
contains plaintext passwords, then there is no way authentication can succeed. Even
|
||||
if you are aware that your database is using MD5 to encode the passwords, for
|
||||
example, and your application is configured to use Spring Security's
|
||||
<classname>Md5PasswordEncoder</classname>, there are still things that can go
|
||||
wrong. The database may have the passwords encoded in Base 64, for example while the
|
||||
enocoder is using hexadecimal strings (the default)<footnote><para>You can configure
|
||||
the encoder to use Base 64 instead of hex by setting the
|
||||
<literal>encodeHashAsBase64</literal> property to
|
||||
<literal>true</literal>. Check the Javadoc for
|
||||
<classname>MessageDigestPasswordEncoder</classname> and its parent
|
||||
classes for more information.</para></footnote>. Alternatively your database
|
||||
may be using upper-case while the output from the encoder is lower-case. Make sure
|
||||
you write a test to check the output from your configured password encoder with a
|
||||
known password and salt combination and check that it matches the database value
|
||||
before going further and attempting to authenticate through your application. For
|
||||
more information on the default method for merging salt and password, see the
|
||||
Javadoc for <classname>BasePasswordEncoder</classname>. If you want to generate
|
||||
encoded passwords directly in Java for storage in your user database, then you can
|
||||
use the <methodname>encodePassword</methodname> method on the
|
||||
<interfacename>PasswordEncoder</interfacename>.</para>
|
||||
<classname>Md5PasswordEncoder</classname>, there are still things that can go wrong.
|
||||
The database may have the passwords encoded in Base 64, for example while the
|
||||
enocoder is using hexadecimal strings (the default)<footnote>
|
||||
<para>You can configure the encoder to use Base 64 instead of hex by setting the
|
||||
<literal>encodeHashAsBase64</literal> property to <literal>true</literal>. Check
|
||||
the Javadoc for <classname>MessageDigestPasswordEncoder</classname> and its
|
||||
parent classes for more information.</para>
|
||||
</footnote>. Alternatively your database may be using upper-case while the output
|
||||
from the encoder is lower-case. Make sure you write a test to check the output from
|
||||
your configured password encoder with a known password and salt combination and
|
||||
check that it matches the database value before going further and attempting to
|
||||
authenticate through your application. For more information on the default method
|
||||
for merging salt and password, see the Javadoc for
|
||||
<classname>BasePasswordEncoder</classname>. If you want to generate encoded
|
||||
passwords directly in Java for storage in your user database, then you can use the
|
||||
<methodname>encodePassword</methodname> method on the
|
||||
<interfacename>PasswordEncoder</interfacename>.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
<title>Overview</title>
|
||||
</info>
|
||||
<para>Spring Security includes a production-quality
|
||||
<classname>AuthenticationProvider</classname> implementation called
|
||||
<literal>DaoAuthenticationProvider</literal>. This authentication provider is
|
||||
compatible with all of the authentication mechanisms that generate a
|
||||
<literal>UsernamePasswordAuthenticationToken</literal>, and is probably the most
|
||||
<classname>AuthenticationProvider</classname> implementation called
|
||||
<literal>DaoAuthenticationProvider</literal>. This authentication provider is compatible
|
||||
with all of the authentication mechanisms that generate a
|
||||
<literal>UsernamePasswordAuthenticationToken</literal>, and is probably the most
|
||||
commonly used provider in the framework. Like most of the other authentication
|
||||
providers, the DaoAuthenticationProvider leverages a UserDetailsService in order to
|
||||
lookup the username, password and GrantedAuthority[]s. Unlike most of the other
|
||||
|
@ -27,8 +27,7 @@
|
|||
at the start of this part of the reference guide), and ensuring a suitable
|
||||
authentication mechanism is configured to present a UsernamePasswordAuthenticationToken,
|
||||
the configuration of the provider itself is rather simple:</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
<para> <programlisting>
|
||||
<![CDATA[
|
||||
<bean id="daoAuthenticationProvider"
|
||||
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||
|
@ -36,15 +35,14 @@
|
|||
<property name="saltSource" ref bean="saltSource"/>
|
||||
<property name="passwordEncoder" ref="passwordEncoder"/>
|
||||
</bean> ]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>The <literal>PasswordEncoder</literal> and <literal>SaltSource</literal> are optional.
|
||||
A <literal>PasswordEncoder</literal> provides encoding and decoding of passwords
|
||||
presented in the <interfacename>UserDetails</interfacename> object that is returned from
|
||||
the configured <interfacename>UserDetailsService</interfacename>. A
|
||||
<literal>SaltSource</literal> enables the passwords to be populated with a "salt",
|
||||
which enhances the security of the passwords in the authentication repository.
|
||||
<literal>PasswordEncoder</literal> implementations are provided with Spring Security
|
||||
<literal>SaltSource</literal> enables the passwords to be populated with a "salt", which
|
||||
enhances the security of the passwords in the authentication repository.
|
||||
<literal>PasswordEncoder</literal> implementations are provided with Spring Security
|
||||
covering MD5, SHA and cleartext encodings. Two <literal>SaltSource</literal>
|
||||
implementations are also provided: <literal>SystemWideSaltSource</literal> which encodes
|
||||
all passwords with the same salt, and <literal>ReflectionSaltSource</literal>, which
|
||||
|
@ -53,16 +51,14 @@
|
|||
optional features.</para>
|
||||
<para>In addition to the properties above, the <literal>DaoAuthenticationProvider</literal>
|
||||
supports optional caching of <interfacename>UserDetails</interfacename> objects. The
|
||||
<literal>UserCache</literal> interface enables the
|
||||
<literal>DaoAuthenticationProvider</literal> to place a
|
||||
<interfacename>UserDetails</interfacename> object into the cache, and retrieve it
|
||||
from the cache upon subsequent authentication attempts for the same username. By default
|
||||
the <literal>DaoAuthenticationProvider</literal> uses the
|
||||
<literal>NullUserCache</literal>, which performs no caching. A usable caching
|
||||
implementation is also provided, <literal>EhCacheBasedUserCache</literal>, which is
|
||||
configured as follows:</para>
|
||||
<para>
|
||||
<programlisting><![CDATA[
|
||||
<literal>UserCache</literal> interface enables the
|
||||
<literal>DaoAuthenticationProvider</literal> to place a
|
||||
<interfacename>UserDetails</interfacename> object into the cache, and retrieve it from
|
||||
the cache upon subsequent authentication attempts for the same username. By default the
|
||||
<literal>DaoAuthenticationProvider</literal> uses the <literal>NullUserCache</literal>,
|
||||
which performs no caching. A usable caching implementation is also provided,
|
||||
<literal>EhCacheBasedUserCache</literal>, which is configured as follows:</para>
|
||||
<para> <programlisting><![CDATA[
|
||||
<bean id="daoAuthenticationProvider"
|
||||
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService" ref="userDetailsService"/>
|
||||
|
@ -82,15 +78,14 @@
|
|||
class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
|
||||
<property name="cache" ref="userCacheBackend"/>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
<para>All Spring Security EH-CACHE implementations (including
|
||||
<literal>EhCacheBasedUserCache</literal>) require an EH-CACHE
|
||||
<literal>Cache</literal> object. The <literal>Cache</literal> object can be obtained
|
||||
from wherever you like, although we recommend you use Spring's factory classes as shown
|
||||
in the above configuration. If using Spring's factory classes, please refer to the
|
||||
Spring documentation for further details on how to optimise the cache storage location,
|
||||
memory usage, eviction policies, timeouts etc.</para>
|
||||
<literal>EhCacheBasedUserCache</literal>) require an EH-CACHE <literal>Cache</literal>
|
||||
object. The <literal>Cache</literal> object can be obtained from wherever you like,
|
||||
although we recommend you use Spring's factory classes as shown in the above
|
||||
configuration. If using Spring's factory classes, please refer to the Spring
|
||||
documentation for further details on how to optimise the cache storage location, memory
|
||||
usage, eviction policies, timeouts etc.</para>
|
||||
<note>
|
||||
<para>In the majority of cases, where your application is a stateful web application,
|
||||
you don't need to use a cache as the user's authentication information will be
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
<para>Complex applications often will find the need to define access permissions not simply
|
||||
at a web request or method invocation level. Instead, security decisions need to
|
||||
comprise both who (<interfacename>Authentication</interfacename>), where
|
||||
(<classname>MethodInvocation</classname>) and what (<literal>SomeDomainObject</literal>). In
|
||||
other words, authorization decisions also need to consider the actual domain object
|
||||
instance subject of a method invocation.</para>
|
||||
(<classname>MethodInvocation</classname>) and what
|
||||
(<literal>SomeDomainObject</literal>). In other words, authorization decisions also need
|
||||
to consider the actual domain object instance subject of a method invocation.</para>
|
||||
<para>Imagine you're designing an application for a pet clinic. There will be two main
|
||||
groups of users of your Spring-based application: staff of the pet clinic, as well as
|
||||
the pet clinic's customers. The staff will have access to all of the data, whilst your
|
||||
|
@ -19,52 +19,52 @@
|
|||
interesting, your customers can allow other users to see their customer records, such as
|
||||
their "puppy preschool" mentor or president of their local "Pony Club". Using Spring
|
||||
Security as the foundation, you have several approaches that can be used:<orderedlist
|
||||
inheritnum="ignore" continuation="restarts">
|
||||
<listitem>
|
||||
<para>Write your business methods to enforce the security. You could consult a
|
||||
collection within the <literal>Customer</literal> domain object instance to
|
||||
determine which users have access. By using the
|
||||
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
|
||||
you'll be able to access the <interfacename>Authentication</interfacename>
|
||||
inheritnum="ignore" continuation="restarts">
|
||||
<listitem>
|
||||
<para>Write your business methods to enforce the security. You could consult a
|
||||
collection within the <literal>Customer</literal> domain object instance to
|
||||
determine which users have access. By using the
|
||||
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
|
||||
you'll be able to access the <interfacename>Authentication</interfacename>
|
||||
object.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the security
|
||||
from the <literal>GrantedAuthority[]</literal>s stored in the
|
||||
<interfacename>Authentication</interfacename> object. This would mean your
|
||||
<interfacename>AuthenticationManager</interfacename> would need to populate the
|
||||
<interfacename>Authentication</interfacename> with custom
|
||||
<interfacename>GrantedAuthority</interfacename>[]s representing each of the
|
||||
<literal>Customer</literal> domain object instances the principal has
|
||||
access to.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the security
|
||||
and open the target <literal>Customer</literal> domain object directly. This
|
||||
would mean your voter needs access to a DAO that allows it to retrieve the
|
||||
<literal>Customer</literal> object. It would then access the
|
||||
<literal>Customer</literal> object's collection of approved users and
|
||||
make the appropriate decision.</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the
|
||||
security from the <literal>GrantedAuthority[]</literal>s stored in the
|
||||
<interfacename>Authentication</interfacename> object. This would mean your
|
||||
<interfacename>AuthenticationManager</interfacename> would need to populate the
|
||||
<interfacename>Authentication</interfacename> with custom
|
||||
<interfacename>GrantedAuthority</interfacename>[]s representing each of the
|
||||
<literal>Customer</literal> domain object instances the principal has access
|
||||
to.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Write an <interfacename>AccessDecisionVoter</interfacename> to enforce the
|
||||
security and open the target <literal>Customer</literal> domain object directly.
|
||||
This would mean your voter needs access to a DAO that allows it to retrieve the
|
||||
<literal>Customer</literal> object. It would then access the
|
||||
<literal>Customer</literal> object's collection of approved users and make the
|
||||
appropriate decision.</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
<para>Each one of these approaches is perfectly legitimate. However, the first couples your
|
||||
authorization checking to your business code. The main problems with this include the
|
||||
enhanced difficulty of unit testing and the fact it would be more difficult to reuse the
|
||||
<literal>Customer</literal> authorization logic elsewhere. Obtaining the
|
||||
<literal>GrantedAuthority[]</literal>s from the <interfacename>Authentication</interfacename>
|
||||
object is also fine, but will not scale to large numbers of
|
||||
<literal>Customer</literal>s. If a user might be able to access 5,000
|
||||
<literal>Customer</literal> authorization logic elsewhere. Obtaining the
|
||||
<literal>GrantedAuthority[]</literal>s from the
|
||||
<interfacename>Authentication</interfacename> object is also fine, but will not scale to
|
||||
large numbers of <literal>Customer</literal>s. If a user might be able to access 5,000
|
||||
<literal>Customer</literal>s (unlikely in this case, but imagine if it were a popular
|
||||
vet for a large Pony Club!) the amount of memory consumed and time required to construct
|
||||
the <interfacename>Authentication</interfacename> object would be undesirable. The final method,
|
||||
opening the <literal>Customer</literal> directly from external code, is probably the
|
||||
best of the three. It achieves separation of concerns, and doesn't misuse memory or CPU
|
||||
cycles, but it is still inefficient in that both the
|
||||
<interfacename>AccessDecisionVoter</interfacename> and the eventual business method itself will
|
||||
perform a call to the DAO responsible for retrieving the <literal>Customer</literal>
|
||||
object. Two accesses per method invocation is clearly undesirable. In addition, with
|
||||
every approach listed you'll need to write your own access control list (ACL)
|
||||
persistence and business logic from scratch.</para>
|
||||
the <interfacename>Authentication</interfacename> object would be undesirable. The final
|
||||
method, opening the <literal>Customer</literal> directly from external code, is probably
|
||||
the best of the three. It achieves separation of concerns, and doesn't misuse memory or
|
||||
CPU cycles, but it is still inefficient in that both the
|
||||
<interfacename>AccessDecisionVoter</interfacename> and the eventual business method
|
||||
itself will perform a call to the DAO responsible for retrieving the
|
||||
<literal>Customer</literal> object. Two accesses per method invocation is clearly
|
||||
undesirable. In addition, with every approach listed you'll need to write your own
|
||||
access control list (ACL) persistence and business logic from scratch.</para>
|
||||
<para>Fortunately, there is another alternative, which we'll talk about below.</para>
|
||||
</section>
|
||||
<section xml:id="domain-acls-key-concepts">
|
||||
|
@ -78,18 +78,18 @@
|
|||
of an access control list (ACL). Every domain object instance in your system has its own
|
||||
ACL, and the ACL records details of who can and can't work with that domain object. With
|
||||
this in mind, Spring Security delivers three main ACL-related capabilities to your application:<itemizedlist>
|
||||
<listitem>
|
||||
<para>A way of efficiently retrieving ACL entries for all of your domain objects
|
||||
(and modifying those ACLs)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>A way of ensuring a given principal is permitted to work with your
|
||||
objects, before methods are called</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>A way of ensuring a given principal is permitted to work with your objects
|
||||
(or something they return), after methods are called</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>A way of efficiently retrieving ACL entries for all of your domain objects
|
||||
(and modifying those ACLs)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>A way of ensuring a given principal is permitted to work with your objects,
|
||||
before methods are called</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>A way of ensuring a given principal is permitted to work with your objects (or
|
||||
something they return), after methods are called</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
<para>As indicated by the first bullet point, one of the main capabilities of the Spring
|
||||
Security ACL module is providing a high-performance way of retrieving ACLs. This ACL
|
||||
|
@ -105,49 +105,46 @@
|
|||
main tables used by default in the implementation. The tables are presented below in
|
||||
order of size in a typical Spring Security ACL deployment, with the table with the most
|
||||
rows listed last:</para>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>ACL_SID allows us to uniquely identify any principal or authority in the
|
||||
system ("SID" stands for "security identity"). The only columns are the ID,
|
||||
a textual representation of the SID, and a flag to indicate whether the
|
||||
textual representation refers to a principal name or a
|
||||
<interfacename>GrantedAuthority</interfacename>. Thus, there is a single row for
|
||||
each unique principal or <interfacename>GrantedAuthority</interfacename>. When used in
|
||||
the context of receiving a permission, a SID is generally called a
|
||||
"recipient".</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>ACL_CLASS allows us to uniquely identify any domain object class in the
|
||||
system. The only columns are the ID and the Java class name. Thus, there is
|
||||
a single row for each unique Class we wish to store ACL permissions
|
||||
for.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>ACL_OBJECT_IDENTITY stores information for each unique domain object
|
||||
instance in the system. Columns include the ID, a foreign key to the
|
||||
ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance
|
||||
we're providing information for, the parent, a foreign key to the ACL_SID
|
||||
table to represent the owner of the domain object instance, and whether we
|
||||
allow ACL entries to inherit from any parent ACL. We have a single row for
|
||||
every domain object instance we're storing ACL permissions for.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Finally, ACL_ENTRY stores the individual permissions assigned to each
|
||||
recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the
|
||||
recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not,
|
||||
and the integer bit mask that represents the actual permission being granted
|
||||
or denied. We have a single row for every recipient that receives a
|
||||
permission to work with a domain object.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para> <itemizedlist>
|
||||
<listitem>
|
||||
<para>ACL_SID allows us to uniquely identify any principal or authority in the
|
||||
system ("SID" stands for "security identity"). The only columns are the ID, a
|
||||
textual representation of the SID, and a flag to indicate whether the textual
|
||||
representation refers to a principal name or a
|
||||
<interfacename>GrantedAuthority</interfacename>. Thus, there is a single row for
|
||||
each unique principal or <interfacename>GrantedAuthority</interfacename>. When
|
||||
used in the context of receiving a permission, a SID is generally called a
|
||||
"recipient".</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>ACL_CLASS allows us to uniquely identify any domain object class in the
|
||||
system. The only columns are the ID and the Java class name. Thus, there is a
|
||||
single row for each unique Class we wish to store ACL permissions for.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>ACL_OBJECT_IDENTITY stores information for each unique domain object instance
|
||||
in the system. Columns include the ID, a foreign key to the ACL_CLASS table, a
|
||||
unique identifier so we know which ACL_CLASS instance we're providing
|
||||
information for, the parent, a foreign key to the ACL_SID table to represent the
|
||||
owner of the domain object instance, and whether we allow ACL entries to inherit
|
||||
from any parent ACL. We have a single row for every domain object instance we're
|
||||
storing ACL permissions for.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Finally, ACL_ENTRY stores the individual permissions assigned to each
|
||||
recipient. Columns include a foreign key to the ACL_OBJECT_IDENTITY, the
|
||||
recipient (ie a foreign key to ACL_SID), whether we'll be auditing or not, and
|
||||
the integer bit mask that represents the actual permission being granted or
|
||||
denied. We have a single row for every recipient that receives a permission to
|
||||
work with a domain object.</para>
|
||||
</listitem>
|
||||
</itemizedlist> </para>
|
||||
<para>As mentioned in the last paragraph, the ACL system uses integer bit masking. Don't
|
||||
worry, you need not be aware of the finer points of bit shifting to use the ACL system,
|
||||
but suffice to say that we have 32 bits we can switch on or off. Each of these bits
|
||||
represents a permission, and by default the permissions are read (bit 0), write (bit 1),
|
||||
create (bit 2), delete (bit 3) and administer (bit 4). It's easy to implement your own
|
||||
<literal>Permission</literal> instance if you wish to use other permissions, and the
|
||||
<literal>Permission</literal> instance if you wish to use other permissions, and the
|
||||
remainder of the ACL framework will operate without knowledge of your extensions.</para>
|
||||
<para>It is important to understand that the number of domain objects in your system has
|
||||
absolutely no bearing on the fact we've chosen to use integer bit masking. Whilst you
|
||||
|
@ -162,16 +159,16 @@
|
|||
<listitem>
|
||||
<para><literal>Acl</literal>: Every domain object has one and only one
|
||||
<literal>Acl</literal> object, which internally holds the
|
||||
<literal>AccessControlEntry</literal>s as well as knows the owner of the
|
||||
<literal>Acl</literal>. An Acl does not refer directly to the domain object,
|
||||
but instead to an <literal>ObjectIdentity</literal>. The <literal>Acl</literal>
|
||||
is stored in the ACL_OBJECT_IDENTITY table.</para>
|
||||
<literal>AccessControlEntry</literal>s as well as knows the owner of the
|
||||
<literal>Acl</literal>. An Acl does not refer directly to the domain object, but
|
||||
instead to an <literal>ObjectIdentity</literal>. The <literal>Acl</literal> is
|
||||
stored in the ACL_OBJECT_IDENTITY table.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>AccessControlEntry</literal>: An <literal>Acl</literal> holds
|
||||
multiple <literal>AccessControlEntry</literal>s, which are often abbreviated as
|
||||
ACEs in the framework. Each ACE refers to a specific tuple of
|
||||
<literal>Permission</literal>, <literal>Sid</literal> and
|
||||
<literal>Permission</literal>, <literal>Sid</literal> and
|
||||
<literal>Acl</literal>. An ACE can also be granting or non-granting and contain
|
||||
audit settings. The ACE is stored in the ACL_ENTRY table.</para>
|
||||
</listitem>
|
||||
|
@ -183,11 +180,11 @@
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>Sid</literal>: The ACL module needs to refer to principals and
|
||||
<literal>GrantedAuthority[]</literal>s. A level of indirection is provided
|
||||
by the <literal>Sid</literal> interface, which is an abbreviation of "security
|
||||
<literal>GrantedAuthority[]</literal>s. A level of indirection is provided by
|
||||
the <literal>Sid</literal> interface, which is an abbreviation of "security
|
||||
identity". Common classes include <literal>PrincipalSid</literal> (to represent
|
||||
the principal inside an <interfacename>Authentication</interfacename> object) and
|
||||
<literal>GrantedAuthoritySid</literal>. The security identity information is
|
||||
the principal inside an <interfacename>Authentication</interfacename> object)
|
||||
and <literal>GrantedAuthoritySid</literal>. The security identity information is
|
||||
stored in the ACL_SID table.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -198,8 +195,8 @@
|
|||
<listitem>
|
||||
<para><literal>AclService</literal>: Retrieves the <literal>Acl</literal> applicable
|
||||
for a given <literal>ObjectIdentity</literal>. In the included implementation
|
||||
(<literal>JdbcAclService</literal>), retrieval operations are delegated to a
|
||||
<literal>LookupStrategy</literal>. The <literal>LookupStrategy</literal>
|
||||
(<literal>JdbcAclService</literal>), retrieval operations are delegated to a
|
||||
<literal>LookupStrategy</literal>. The <literal>LookupStrategy</literal>
|
||||
provides a highly optimized strategy for retrieving ACL information, using
|
||||
batched retrievals <literal>(BasicLookupStrategy</literal>) and supporting
|
||||
custom implementations that leverage materialized views, hierarchical queries
|
||||
|
@ -227,16 +224,15 @@
|
|||
ACL information somewhere. This necessitates the instantiation of a
|
||||
<literal>DataSource</literal> using Spring. The <literal>DataSource</literal> is then
|
||||
injected into a <literal>JdbcMutableAclService</literal> and
|
||||
<literal>BasicLookupStrategy</literal> instance. The latter provides
|
||||
high-performance ACL retrieval capabilities, and the former provides mutator
|
||||
capabilities. Refer to one of the samples that ship with Spring Security for an example
|
||||
configuration. You'll also need to populate the database with the four ACL-specific
|
||||
tables listed in the last section (refer to the ACL samples for the appropriate SQL
|
||||
statements).</para>
|
||||
<literal>BasicLookupStrategy</literal> instance. The latter provides high-performance
|
||||
ACL retrieval capabilities, and the former provides mutator capabilities. Refer to one
|
||||
of the samples that ship with Spring Security for an example configuration. You'll also
|
||||
need to populate the database with the four ACL-specific tables listed in the last
|
||||
section (refer to the ACL samples for the appropriate SQL statements).</para>
|
||||
<para>Once you've created the required schema and instantiated
|
||||
<literal>JdbcMutableAclService</literal>, you'll next need to ensure your domain
|
||||
model supports interoperability with the Spring Security ACL package. Hopefully
|
||||
<literal>ObjectIdentityImpl</literal> will prove sufficient, as it provides a large
|
||||
<literal>JdbcMutableAclService</literal>, you'll next need to ensure your domain model
|
||||
supports interoperability with the Spring Security ACL package. Hopefully
|
||||
<literal>ObjectIdentityImpl</literal> will prove sufficient, as it provides a large
|
||||
number of ways in which it can be used. Most people will have domain objects that
|
||||
contain a <literal>public Serializable getId()</literal> method. If the return type is
|
||||
long, or compatible with long (eg an int), you will find you need not give further
|
||||
|
@ -272,7 +268,8 @@ aclService.updateAcl(acl);
|
|||
position in the Acl the new entry will be inserted. In the example above, we're just
|
||||
putting the new ACE at the end of the existing ACEs. The final argument is a boolean
|
||||
indicating whether the ACE is granting or denying. Most of the time it will be granting
|
||||
(true), but if it is denying (false), the permissions are effectively being blocked.</para>
|
||||
(true), but if it is denying (false), the permissions are effectively being
|
||||
blocked.</para>
|
||||
<para>Spring Security does not provide any special integration to automatically create,
|
||||
update or delete ACLs as part of your DAO or repository operations. Instead, you will
|
||||
need to write code like shown above for your individual domain objects. It's worth
|
||||
|
@ -282,15 +279,15 @@ aclService.updateAcl(acl);
|
|||
<para>Once you've used the above techniques to store some ACL information in the database,
|
||||
the next step is to actually use the ACL information as part of authorization decision
|
||||
logic. You have a number of choices here. You could write your own
|
||||
<interfacename>AccessDecisionVoter</interfacename> or <literal>AfterInvocationProvider</literal>
|
||||
that respectively fires before or after a method invocation. Such classes would use
|
||||
<literal>AclService</literal> to retrieve the relevant ACL and then call
|
||||
<literal>Acl.isGranted(Permission[] permission, Sid[] sids, boolean
|
||||
administrativeMode)</literal> to decide whether permission is granted or denied.
|
||||
<interfacename>AccessDecisionVoter</interfacename> or
|
||||
<literal>AfterInvocationProvider</literal> that respectively fires before or after a
|
||||
method invocation. Such classes would use <literal>AclService</literal> to retrieve the
|
||||
relevant ACL and then call <literal>Acl.isGranted(Permission[] permission, Sid[] sids,
|
||||
boolean administrativeMode)</literal> to decide whether permission is granted or denied.
|
||||
Alternately, you could use our <literal>AclEntryVoter</literal>,
|
||||
<literal>AclEntryAfterInvocationProvider</literal> or
|
||||
<literal>AclEntryAfterInvocationCollectionFilteringProvider</literal> classes. All
|
||||
of these classes provide a declarative-based approach to evaluating ACL information at
|
||||
<literal>AclEntryAfterInvocationProvider</literal> or
|
||||
<literal>AclEntryAfterInvocationCollectionFilteringProvider</literal> classes. All of
|
||||
these classes provide a declarative-based approach to evaluating ACL information at
|
||||
runtime, freeing you from needing to write any code. Please refer to the sample
|
||||
applications to learn how to use these classes.</para>
|
||||
</section>
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<section xml:id="el-common-built-in">
|
||||
<title>Common Built-In Expressions</title>
|
||||
<para>The base class for expression root objects is
|
||||
<classname>SecurityExpressionRoot</classname>. This provides some common
|
||||
expressions which are available in both web and method security.</para>
|
||||
<classname>SecurityExpressionRoot</classname>. This provides some common expressions
|
||||
which are available in both web and method security.</para>
|
||||
<table frame="none">
|
||||
<title>Common built-in expressions</title>
|
||||
<tgroup cols="2">
|
||||
|
@ -51,8 +51,8 @@
|
|||
<row>
|
||||
<entry><literal>authentication</literal></entry>
|
||||
<entry>Allows direct access to the current
|
||||
<interfacename>Authentication</interfacename> object obtained
|
||||
from the <interfacename>SecurityContext</interfacename></entry>
|
||||
<interfacename>Authentication</interfacename> object obtained from
|
||||
the <interfacename>SecurityContext</interfacename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>permitAll</literal></entry>
|
||||
|
@ -90,9 +90,9 @@
|
|||
<section xml:id="el-access-web">
|
||||
<title>Web Security Expressions</title>
|
||||
<para> To use expressions to secure individual URLs, you would first need to set the
|
||||
<literal>use-expressions</literal> attribute in the <literal><http></literal>
|
||||
element to <literal>true</literal>. Spring Security will then expect the
|
||||
<literal>access</literal> attributes of the <literal><intercept-url></literal>
|
||||
<literal>use-expressions</literal> attribute in the <literal><http></literal> element
|
||||
to <literal>true</literal>. Spring Security will then expect the
|
||||
<literal>access</literal> attributes of the <literal><intercept-url></literal>
|
||||
elements to contain Spring EL expressions. The expressions should evaluate to a boolean,
|
||||
defining whether access should be allowed or not. For example:<programlisting><![CDATA[
|
||||
<http use-expressions="true">
|
||||
|
@ -106,8 +106,8 @@
|
|||
already seen the built-in <literal>hasRole</literal> expression in the previous section.
|
||||
The expression <literal>hasIpAddress</literal> is an additional built-in expression
|
||||
which is specific to web security. It is defined by the
|
||||
<classname>WebSecurityExpressionRoot</classname> class, an instance of which is used
|
||||
as the expression root object when evaluation web-access expressions. This object also
|
||||
<classname>WebSecurityExpressionRoot</classname> class, an instance of which is used as
|
||||
the expression root object when evaluation web-access expressions. This object also
|
||||
directly exposed the <interfacename>HttpServletRequest</interfacename> object under the
|
||||
name <literal>request</literal> so you can invoke the request directly in an
|
||||
expression.</para>
|
||||
|
@ -126,16 +126,16 @@
|
|||
<para>There are four annotations which support expression attributes to allow pre and
|
||||
post-invocation authorization checks and also to support filtering of submitted
|
||||
collection arguments or return values. They are <literal>@PreAuthorize</literal>,
|
||||
<literal>@PreFilter</literal>, <literal>@PostAuthorize</literal> and
|
||||
<literal>@PostFilter</literal>. Their use is enabled through the
|
||||
<literal>global-method-security</literal> namespace
|
||||
<literal>@PreFilter</literal>, <literal>@PostAuthorize</literal> and
|
||||
<literal>@PostFilter</literal>. Their use is enabled through the
|
||||
<literal>global-method-security</literal> namespace
|
||||
element:<programlisting><![CDATA[<global-method-security pre-post-annotations="enabled"/>]]></programlisting></para>
|
||||
<section>
|
||||
<title>Access Control using <literal>@PreAuthorize</literal> and
|
||||
<literal>@PostAuthorize</literal></title>
|
||||
<literal>@PostAuthorize</literal></title>
|
||||
<para>The most obviously useful annotation is <literal>@PreAuthorize</literal> which
|
||||
decides whether a method can actually be invoked or not. For example (from the
|
||||
<quote>Contacts</quote> sample
|
||||
<quote>Contacts</quote> sample
|
||||
application)<programlisting>
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public void create(Contact contact);</programlisting>which
|
||||
|
@ -150,30 +150,30 @@
|
|||
whether the current user has the <quote>admin</quote>permission for the given
|
||||
contact. The built-in <literal>hasPermission()</literal> expression is linked
|
||||
into the Spring Security ACL module through the application context, as we'll
|
||||
<link xlink:href="#el-permission-evaluator">see below</link>. You can access
|
||||
any of the method arguments by name as expression variables, provided your code
|
||||
has debug information compiled in. Any Spring-EL functionality is available
|
||||
within the expression, so you can also access properties on the arguments. For
|
||||
example, if you wanted a particular method to only allow access to a user whose
|
||||
username matched that of the contact, you could write</para>
|
||||
<link xlink:href="#el-permission-evaluator">see below</link>. You can access any
|
||||
of the method arguments by name as expression variables, provided your code has
|
||||
debug information compiled in. Any Spring-EL functionality is available within
|
||||
the expression, so you can also access properties on the arguments. For example,
|
||||
if you wanted a particular method to only allow access to a user whose username
|
||||
matched that of the contact, you could write</para>
|
||||
<programlisting>
|
||||
@PreAuthorize("#contact.name == principal.name)")
|
||||
public void doSomething(Contact contact);</programlisting>
|
||||
<para>Here we are accessing another built–in expression, which is the
|
||||
<literal>principal</literal> of the current Spring Security
|
||||
<interfacename>Authentication</interfacename> object obtained from the
|
||||
security context. You can also access the
|
||||
<interfacename>Authentication</interfacename> object itself directly using
|
||||
the expression name <literal>authentication</literal>.</para>
|
||||
<literal>principal</literal> of the current Spring Security
|
||||
<interfacename>Authentication</interfacename> object obtained from the security
|
||||
context. You can also access the <interfacename>Authentication</interfacename>
|
||||
object itself directly using the expression name
|
||||
<literal>authentication</literal>.</para>
|
||||
<para>Less commonly, you may wish to perform an access-control check after the
|
||||
method has been invoked. This can be achieved using the
|
||||
<literal>@PostAuthorize</literal> annotation. To access the return value
|
||||
from a method, use the built–in name <literal>returnObject</literal> in the
|
||||
<literal>@PostAuthorize</literal> annotation. To access the return value from a
|
||||
method, use the built–in name <literal>returnObject</literal> in the
|
||||
expression.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Filtering using <literal>@PreFilter</literal> and
|
||||
<literal>@PostFilter</literal></title>
|
||||
<literal>@PostFilter</literal></title>
|
||||
<para>As you may already be aware, Spring Security supports filtering of collections
|
||||
and arrays and this can now be achieved using expressions. This is most commonly
|
||||
performed on the return value of a method. For
|
||||
|
@ -187,7 +187,7 @@
|
|||
using <literal>@PreFilter</literal>, though this is a less common requirement.
|
||||
The syntax is just the same, but if there is more than one argument which is a
|
||||
collection type then you have to select one by name using the
|
||||
<literal>filterTarget</literal> property of this annotation.</para>
|
||||
<literal>filterTarget</literal> property of this annotation.</para>
|
||||
<para>Note that filtering is obviously not a substitute for tuning your data
|
||||
retrieval queries. If you are filtering large collections and removing many of
|
||||
the entries then this is likely to be inefficient.</para>
|
||||
|
@ -197,12 +197,12 @@
|
|||
<title>Built-In Expressions</title>
|
||||
<para>There are some built-in expressions which are specific to method security, which
|
||||
we have already seen in use above. The <literal>filterTarget</literal> and
|
||||
<literal>returnValue</literal> values are simple enough, but the use of the
|
||||
<literal>hasPermission()</literal> expression warrants a closer look.</para>
|
||||
<literal>returnValue</literal> values are simple enough, but the use of the
|
||||
<literal>hasPermission()</literal> expression warrants a closer look.</para>
|
||||
<section xml:id="el-permission-evaluator">
|
||||
<title>The <interfacename>PermissionEvaluator</interfacename> interface</title>
|
||||
<para><literal>hasPermission()</literal> expressions are delegated to an instance of
|
||||
<interfacename>PermissionEvaluator</interfacename>. It is intended to bridge
|
||||
<interfacename>PermissionEvaluator</interfacename>. It is intended to bridge
|
||||
between the expression system and Spring Security's ACL system, allowing you to
|
||||
specify authorization constraints on domain objects, based on abstract
|
||||
permissions. It has no explicit dependencies on the ACL module, so you could
|
||||
|
@ -227,8 +227,7 @@
|
|||
long as it is consistent with how the permissions are loaded.</para>
|
||||
<para>To use <literal>hasPermission()</literal> expressions, you have to explicitly
|
||||
configure a <interfacename>PermissionEvaluator</interfacename> in your
|
||||
application context. This would look something like this:
|
||||
<programlisting language="xml"> <![CDATA[
|
||||
application context. This would look something like this: <programlisting language="xml"> <![CDATA[
|
||||
<security:global-method-security pre-post-annotations="enabled">
|
||||
<security:expression-handler ref="expressionHandler"/>
|
||||
</security:global-method-security>
|
||||
|
@ -239,9 +238,8 @@
|
|||
</bean>]]></programlisting>Where <literal>myPermissionEvaluator</literal> is the bean which
|
||||
implements <interfacename>PermissionEvaluator</interfacename>. Usually this will
|
||||
be the implementation from the ACL module which is called
|
||||
<classname>AclPermissionEvaluator</classname>. See the
|
||||
<quote>Contacts</quote> sample application configuration for more
|
||||
details.</para>
|
||||
<classname>AclPermissionEvaluator</classname>. See the <quote>Contacts</quote>
|
||||
sample application configuration for more details.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
@ -1,67 +1,68 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="form">
|
||||
<info><title>Form Authentication Mechanism</title></info>
|
||||
<info>
|
||||
<title>Form Authentication Mechanism</title>
|
||||
</info>
|
||||
|
||||
<section xml:id="form-overview">
|
||||
<info><title>Overview</title></info>
|
||||
<info>
|
||||
<title>Overview</title>
|
||||
</info>
|
||||
|
||||
<para>HTTP Form Authentication involves using the
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal> to process a login
|
||||
form. This is the most common way for an application to authenticate end
|
||||
users. Form-based authentication is entirely compatible with the DAO, LDAP
|
||||
and JAAS authentication providers.</para>
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal> to process a login form. This is
|
||||
the most common way for an application to authenticate end users. Form-based
|
||||
authentication is entirely compatible with the DAO, LDAP and JAAS authentication
|
||||
providers.</para>
|
||||
<para>This is also the mechanism used by the <form-login> element from the namespace
|
||||
and it's recommended that you use that unless you have specific customization requirements.
|
||||
</para>
|
||||
and it's recommended that you use that unless you have specific customization
|
||||
requirements. </para>
|
||||
</section>
|
||||
|
||||
<section xml:id="form-config">
|
||||
<info><title>Configuration</title></info>
|
||||
<info>
|
||||
<title>Configuration</title>
|
||||
</info>
|
||||
|
||||
<para>The login form simply contains <literal>j_username</literal> and
|
||||
<literal>j_password</literal> input fields, and posts to a URL that is
|
||||
monitored by the filter (by default
|
||||
<literal>/j_spring_security_check</literal>). You should add an
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal> to your application context:
|
||||
<programlisting><![CDATA[
|
||||
<literal>j_password</literal> input fields, and posts to a URL that is monitored by the
|
||||
filter (by default <literal>/j_spring_security_check</literal>). You should add an
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal> to your application context: <programlisting><![CDATA[
|
||||
<bean id="authenticationProcessingFilter" class=
|
||||
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
|
||||
</bean> ]]>
|
||||
</programlisting></para>
|
||||
<para>
|
||||
The configured <interfacename>AuthenticationManager</interfacename>
|
||||
processes each authentication request. The destination following a successful authentication
|
||||
or an authentication failure is controlled by the <interfacename>AuthenticationSuccessHandler</interfacename>
|
||||
and <interfacename>AuthenticationFailureHandler</interfacename> interfaces, respectively.
|
||||
The filter has properties which allow you to set these
|
||||
<footnote><para>In versions prior to 3.0, the application flow at this point had evolved to a stage
|
||||
was controlled by a mix of properties on this class and strategy plugins. The
|
||||
decision was made for 3.0 to refactor the code to make these two strategies entirely responsible.
|
||||
</para></footnote>.
|
||||
Some standard implementations are supplied for these such as
|
||||
<para> The configured <interfacename>AuthenticationManager</interfacename> processes each
|
||||
authentication request. The destination following a successful authentication or an
|
||||
authentication failure is controlled by the
|
||||
<interfacename>AuthenticationSuccessHandler</interfacename> and
|
||||
<interfacename>AuthenticationFailureHandler</interfacename> interfaces, respectively.
|
||||
The filter has properties which allow you to set these <footnote>
|
||||
<para>In versions prior to 3.0, the application flow at this point had evolved to a
|
||||
stage was controlled by a mix of properties on this class and strategy plugins. The
|
||||
decision was made for 3.0 to refactor the code to make these two strategies entirely
|
||||
responsible. </para>
|
||||
</footnote>. Some standard implementations are supplied for these such as
|
||||
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
|
||||
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
|
||||
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
|
||||
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at the Javadoc
|
||||
for these classes to see how they work.
|
||||
</para>
|
||||
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at the
|
||||
Javadoc for these classes to see how they work. </para>
|
||||
|
||||
<para>If authentication is successful, the resulting
|
||||
<interfacename>Authentication</interfacename> object will be placed into the
|
||||
<classname>SecurityContextHolder</classname>.
|
||||
The configured AuthenticationSuccessHandler will then be called to either redirect or forward
|
||||
the user to the appropriate destination. By default a <classname>SavedRequestAwareAuthenticationSuccessHandler</classname>
|
||||
is used, which means that the user will be redirected to the original destination they requested before they were asked to
|
||||
login.
|
||||
<note>
|
||||
<para>
|
||||
The <classname>ExceptionTranslationFilter</classname> caches the original request a user makes.
|
||||
When the user authenticates, the request handler makes use of this cached request to obtain the original
|
||||
URL and redirect to it. The original request is then rebuilt and used as an alternative.
|
||||
</para>
|
||||
</note>
|
||||
If authentication fails, the configured <interfacename>AuthenticationFailureHandler</interfacename> will be invoked.
|
||||
</para>
|
||||
<classname>SecurityContextHolder</classname>. The configured
|
||||
AuthenticationSuccessHandler will then be called to either redirect or forward the user
|
||||
to the appropriate destination. By default a
|
||||
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname> is used, which
|
||||
means that the user will be redirected to the original destination they requested before
|
||||
they were asked to login. <note>
|
||||
<para> The <classname>ExceptionTranslationFilter</classname> caches the original request
|
||||
a user makes. When the user authenticates, the request handler makes use of this
|
||||
cached request to obtain the original URL and redirect to it. The original request
|
||||
is then rebuilt and used as an alternative. </para>
|
||||
</note> If authentication fails, the configured
|
||||
<interfacename>AuthenticationFailureHandler</interfacename> will be invoked. </para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
Security overcomes these problems, and also brings you dozens of other useful,
|
||||
customisable security features.</para>
|
||||
<para>As you probably know two major areas of application security are
|
||||
<quote>authentication</quote> and <quote>authorization</quote> (or
|
||||
<quote>access-control</quote>). These are the two main areas that Spring Security
|
||||
<quote>authentication</quote> and <quote>authorization</quote> (or
|
||||
<quote>access-control</quote>). These are the two main areas that Spring Security
|
||||
targets. <quote>Authentication</quote> is the process of establishing a principal is who
|
||||
they claim to be (a <quote>principal</quote> generally means a user, device or some
|
||||
other system which can perform an action in your application).
|
||||
<quote>Authorization</quote> refers to the process of deciding whether a principal
|
||||
is allowed to perform an action within your application. To arrive at the point where an
|
||||
<quote>Authorization</quote> refers to the process of deciding whether a principal is
|
||||
allowed to perform an action within your application. To arrive at the point where an
|
||||
authorization decision is needed, the identity of the principal has already been
|
||||
established by the authentication process. These concepts are common, and not at all
|
||||
specific to Spring Security. </para>
|
||||
|
@ -134,8 +134,8 @@
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>(* Denotes provided by a third party; check our <link
|
||||
xlink:href="http://acegisecurity.org/powering.html">integration page</link> for
|
||||
links to the latest details)</para>
|
||||
xlink:href="http://acegisecurity.org/powering.html">integration page</link> for links to
|
||||
the latest details)</para>
|
||||
<para>Many independent software vendors (ISVs) adopt Spring Security because of this
|
||||
significant choice of flexible authentication models. Doing so allows them to quickly
|
||||
integrate their solutions with whatever their end clients need, without undertaking a
|
||||
|
@ -165,7 +165,7 @@
|
|||
<section xml:id="history">
|
||||
<title>History</title>
|
||||
<para>Spring Security began in late 2003 as <quote>The Acegi Security System for
|
||||
Spring</quote>. A question was posed on the Spring Developers' mailing list asking
|
||||
Spring</quote>. A question was posed on the Spring Developers' mailing list asking
|
||||
whether there had been any consideration given to a Spring-based security
|
||||
implementation. At the time the Spring community was relatively small (especially
|
||||
compared with the size today!), and indeed Spring itself had only existed as a
|
||||
|
@ -202,21 +202,21 @@
|
|||
you identify the effort (or lack thereof) involved in migrating to future releases of
|
||||
the project. Officially, we use the Apache Portable Runtime Project versioning
|
||||
guidelines, which can be viewed at
|
||||
<literal>http://apr.apache.org/versioning.html</literal>. We quote the introduction
|
||||
<literal>http://apr.apache.org/versioning.html</literal>. We quote the introduction
|
||||
contained on that page for your convenience:</para>
|
||||
<para><quote>Versions are denoted using a standard triplet of integers: MAJOR.MINOR.PATCH.
|
||||
The basic intent is that MAJOR versions are incompatible, large-scale upgrades of
|
||||
the API. MINOR versions retain source and binary compatibility with older minor
|
||||
versions, and changes in the PATCH level are perfectly compatible, forwards and
|
||||
backwards.</quote></para>
|
||||
The basic intent is that MAJOR versions are incompatible, large-scale upgrades of the
|
||||
API. MINOR versions retain source and binary compatibility with older minor versions,
|
||||
and changes in the PATCH level are perfectly compatible, forwards and
|
||||
backwards.</quote></para>
|
||||
</section>
|
||||
<section xml:id="get-spring-security">
|
||||
<title>Getting Spring Security</title>
|
||||
<para>You can get hold of Spring Security in several ways. You can download a packaged
|
||||
distribution from the main Spring <link
|
||||
xlink:href="http://www.springsource.com/download/community?project=Spring%20Security"
|
||||
>download page</link>, download individual jars (and sample WAR files) from the
|
||||
Maven Central repository (or a SpringSource Maven repository for snapshot and milestone
|
||||
xlink:href="http://www.springsource.com/download/community?project=Spring%20Security"
|
||||
>download page</link>, download individual jars (and sample WAR files) from the Maven
|
||||
Central repository (or a SpringSource Maven repository for snapshot and milestone
|
||||
releases) or, alternatively, you can build the project from source yourself. See the
|
||||
project web site for more details. </para>
|
||||
<section xml:id="modules">
|
||||
|
@ -233,28 +233,43 @@
|
|||
<para>Contains core authentication and access-contol classes and interfaces,
|
||||
remoting support and basic provisioning APIs. Required by any application which
|
||||
uses Spring Security. Supports standalone applications, remote clients, method
|
||||
(service layer) security and JDBC user provisioning. Contains the top-level
|
||||
packages:<itemizedlist><listitem><para><literal>org.springframework.security.core</literal></para></listitem><listitem><para><literal>org.springframework.security.access</literal></para></listitem><listitem><para><literal>org.springframework.security.authentication</literal></para></listitem><listitem><para><literal>org.springframework.security.provisioning</literal></para></listitem><listitem><para><literal>org.springframework.security.remoting</literal></para></listitem></itemizedlist></para>
|
||||
(service layer) security and JDBC user provisioning. Contains the top-level packages:<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>org.springframework.security.core</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>org.springframework.security.access</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>org.springframework.security.authentication</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>org.springframework.security.provisioning</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>org.springframework.security.remoting</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</section>
|
||||
<section xml:id="spring-security-web">
|
||||
<title>Web - <literal>spring-security-web.jar</literal></title>
|
||||
<para>Contains filters and related web-security infrastructure code. Anything with a
|
||||
servlet API dependency. You'll need it if you require Spring Security web
|
||||
authentication services and URL-based access-control. The main package is
|
||||
<literal>org.springframework.security.web</literal>.</para>
|
||||
<literal>org.springframework.security.web</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="spring-security-config">
|
||||
<title>Config - <literal>spring-security-config.jar</literal></title>
|
||||
<para>Contains the security namespace parsing code (and hence nothing that you are
|
||||
likely yo use directly in your application). You need it if you are using the
|
||||
Spring Security XML namespace for configuration. The main package is
|
||||
<literal>org.springframework.security.config</literal>.</para>
|
||||
<literal>org.springframework.security.config</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="spring-security-ldap">
|
||||
<title>LDAP - <literal>spring-security-ldap.jar</literal></title>
|
||||
<para>LDAP authentication and provisioning code. Required if you need to use LDAP
|
||||
authentication or manage LDAP user entries. The top-level package is
|
||||
<literal>org.springframework.security.ldap</literal>.</para>
|
||||
<literal>org.springframework.security.ldap</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="spring-security-acl">
|
||||
<title>ACL - <literal>spring-security-acl.jar</literal></title>
|
||||
|
@ -266,7 +281,7 @@
|
|||
<title>CAS - <literal>spring-security-cas-client.jar</literal></title>
|
||||
<para>Spring Security's CAS client integration. If you want to use Spring Security
|
||||
web authentication with a CAS single sign-on server. The top-level package is
|
||||
<literal>org.springframework.security.cas</literal>.</para>
|
||||
<literal>org.springframework.security.cas</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="spring-security-openid">
|
||||
<title>OpenID - <literal>spring-security-openid.jar</literal></title>
|
||||
|
@ -290,7 +305,7 @@
|
|||
git clone git://git.springsource.org/spring-security/spring-security.git
|
||||
</programlisting>
|
||||
You can checkout specific versions from
|
||||
<literal>https://src.springframework.org/svn/spring-security/tags/</literal>.
|
||||
<literal>https://src.springframework.org/svn/spring-security/tags/</literal>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="jaas">
|
||||
<info><title>Java Authentication and Authorization Service (JAAS) Provider</title></info>
|
||||
<info>
|
||||
<title>Java Authentication and Authorization Service (JAAS) Provider</title>
|
||||
</info>
|
||||
|
||||
<section xml:id="jaas-overview">
|
||||
<info><title>Overview</title></info>
|
||||
<para>Spring Security provides a package able to delegate
|
||||
authentication requests to the Java Authentication and Authorization
|
||||
Service (JAAS). This package is discussed in detail below.</para>
|
||||
<info>
|
||||
<title>Overview</title>
|
||||
</info>
|
||||
<para>Spring Security provides a package able to delegate authentication requests to the
|
||||
Java Authentication and Authorization Service (JAAS). This package is discussed in
|
||||
detail below.</para>
|
||||
|
||||
<para>Central to JAAS operation are login configuration files. To
|
||||
learn more about JAAS login configuration files, consult the JAAS
|
||||
reference documentation available from Sun Microsystems. We expect you
|
||||
to have a basic understanding of JAAS and its login configuration file
|
||||
syntax in order to understand this section.</para>
|
||||
<para>Central to JAAS operation are login configuration files. To learn more about JAAS
|
||||
login configuration files, consult the JAAS reference documentation available from Sun
|
||||
Microsystems. We expect you to have a basic understanding of JAAS and its login
|
||||
configuration file syntax in order to understand this section.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="jaas-config">
|
||||
<info><title>Configuration</title></info>
|
||||
<para>The <literal>JaasAuthenticationProvider</literal> attempts to
|
||||
authenticate a user’s principal and credentials through JAAS.</para>
|
||||
<info>
|
||||
<title>Configuration</title>
|
||||
</info>
|
||||
<para>The <literal>JaasAuthenticationProvider</literal> attempts to authenticate a user’s
|
||||
principal and credentials through JAAS.</para>
|
||||
|
||||
<para>Let’s assume we have a JAAS login configuration file,
|
||||
<literal>/WEB-INF/login.conf</literal>, with the following
|
||||
contents:
|
||||
<programlisting>
|
||||
<literal>/WEB-INF/login.conf</literal>, with the following contents:
|
||||
<programlisting>
|
||||
JAASTest {
|
||||
sample.SampleLoginModule required;
|
||||
};</programlisting></para>
|
||||
<para>Like all Spring Security beans, the
|
||||
<classname>JaasAuthenticationProvider</classname> is configured via the
|
||||
application context. The following definitions would correspond to the
|
||||
above JAAS login configuration file:
|
||||
<programlisting><![CDATA[
|
||||
<para>Like all Spring Security beans, the <classname>JaasAuthenticationProvider</classname>
|
||||
is configured via the application context. The following definitions would correspond to
|
||||
the above JAAS login configuration file: <programlisting><![CDATA[
|
||||
<bean id="jaasAuthenticationProvider"
|
||||
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
|
||||
<property name="loginConfig" value="/WEB-INF/login.conf"/>
|
||||
|
@ -55,82 +57,76 @@ JAASTest {
|
|||
<interfacename>AuthorityGranter</interfacename>s are discussed below.</para>
|
||||
|
||||
<section xml:id="jaas-callbackhandler">
|
||||
<info><title xml:id="jaas-callback-handler">JAAS CallbackHandler</title></info>
|
||||
<info>
|
||||
<title xml:id="jaas-callback-handler">JAAS CallbackHandler</title>
|
||||
</info>
|
||||
|
||||
<para>Most JAAS <literal>LoginModule</literal>s require a callback
|
||||
of some sort. These callbacks are usually used to obtain the
|
||||
username and password from the user.</para>
|
||||
<para>Most JAAS <literal>LoginModule</literal>s require a callback of some sort. These
|
||||
callbacks are usually used to obtain the username and password from the user.</para>
|
||||
|
||||
<para>In a Spring Security deployment, Spring Security is
|
||||
responsible for this user interaction (via the authentication
|
||||
mechanism). Thus, by the time the authentication request is
|
||||
delegated through to JAAS, Spring Security's authentication
|
||||
mechanism will already have fully-populated an
|
||||
<interfacename>Authentication</interfacename> object containing all the
|
||||
information required by the JAAS
|
||||
<para>In a Spring Security deployment, Spring Security is responsible for this user
|
||||
interaction (via the authentication mechanism). Thus, by the time the authentication
|
||||
request is delegated through to JAAS, Spring Security's authentication mechanism
|
||||
will already have fully-populated an <interfacename>Authentication</interfacename>
|
||||
object containing all the information required by the JAAS
|
||||
<literal>LoginModule</literal>.</para>
|
||||
|
||||
<para>Therefore, the JAAS package for Spring Security provides two
|
||||
default callback handlers,
|
||||
<literal>JaasNameCallbackHandler</literal> and
|
||||
<literal>JaasPasswordCallbackHandler</literal>. Each of these
|
||||
callback handlers implement
|
||||
<literal>JaasAuthenticationCallbackHandler</literal>. In most cases
|
||||
these callback handlers can simply be used without understanding the
|
||||
internal mechanics.</para>
|
||||
<para>Therefore, the JAAS package for Spring Security provides two default callback
|
||||
handlers, <literal>JaasNameCallbackHandler</literal> and
|
||||
<literal>JaasPasswordCallbackHandler</literal>. Each of these callback handlers
|
||||
implement <literal>JaasAuthenticationCallbackHandler</literal>. In most cases these
|
||||
callback handlers can simply be used without understanding the internal
|
||||
mechanics.</para>
|
||||
|
||||
<para>For those needing full control over the callback behavior,
|
||||
internally <literal>JaasAuthenticationProvider</literal> wraps these
|
||||
<para>For those needing full control over the callback behavior, internally
|
||||
<literal>JaasAuthenticationProvider</literal> wraps these
|
||||
<literal>JaasAuthenticationCallbackHandler</literal>s with an
|
||||
<literal>InternalCallbackHandler</literal>. The
|
||||
<literal>InternalCallbackHandler</literal> is the class that
|
||||
actually implements JAAS’ normal <literal>CallbackHandler</literal>
|
||||
interface. Any time that the JAAS <literal>LoginModule</literal> is
|
||||
used, it is passed a list of application context configured
|
||||
<literal>InternalCallbackHandler</literal>s. If the
|
||||
<literal>InternalCallbackHandler</literal> is the class that actually implements
|
||||
JAAS’ normal <literal>CallbackHandler</literal> interface. Any time that the JAAS
|
||||
<literal>LoginModule</literal> is used, it is passed a list of application context
|
||||
configured <literal>InternalCallbackHandler</literal>s. If the
|
||||
<literal>LoginModule</literal> requests a callback against the
|
||||
<literal>InternalCallbackHandler</literal>s, the callback is in-turn
|
||||
passed to the <literal>JaasAuthenticationCallbackHandler</literal>s
|
||||
being wrapped.</para>
|
||||
<literal>InternalCallbackHandler</literal>s, the callback is in-turn passed to the
|
||||
<literal>JaasAuthenticationCallbackHandler</literal>s being wrapped.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="jaas-authoritygranter">
|
||||
<info><title xml:id="jaas-authority-granter">JAAS AuthorityGranter</title></info>
|
||||
<info>
|
||||
<title xml:id="jaas-authority-granter">JAAS AuthorityGranter</title>
|
||||
</info>
|
||||
|
||||
<para>JAAS works with principals. Even "roles" are represented as
|
||||
principals in JAAS. Spring Security, on the other hand, works with
|
||||
<para>JAAS works with principals. Even "roles" are represented as principals in JAAS.
|
||||
Spring Security, on the other hand, works with
|
||||
<interfacename>Authentication</interfacename> objects. Each
|
||||
<interfacename>Authentication</interfacename> object contains a single
|
||||
principal, and multiple <interfacename>GrantedAuthority</interfacename>[]s. To
|
||||
facilitate mapping between these different concepts, Spring
|
||||
Security's JAAS package includes an
|
||||
<interfacename>Authentication</interfacename> object contains a single principal,
|
||||
and multiple <interfacename>GrantedAuthority</interfacename>[]s. To facilitate
|
||||
mapping between these different concepts, Spring Security's JAAS package includes an
|
||||
<literal>AuthorityGranter</literal> interface.</para>
|
||||
|
||||
<para>An <literal>AuthorityGranter</literal> is responsible for
|
||||
inspecting a JAAS principal and returning a set of
|
||||
<literal>String</literal>s, representing the authorities assigned to the principal.
|
||||
For each returned authority string, the
|
||||
<para>An <literal>AuthorityGranter</literal> is responsible for inspecting a JAAS
|
||||
principal and returning a set of <literal>String</literal>s, representing the
|
||||
authorities assigned to the principal. For each returned authority string, the
|
||||
<classname>JaasAuthenticationProvider</classname> creates a
|
||||
<classname>JaasGrantedAuthority</classname> (which implements Spring
|
||||
Security’s <interfacename>GrantedAuthority</interfacename> interface) containing
|
||||
the authority string and the JAAS principal that the
|
||||
<classname>JaasGrantedAuthority</classname> (which implements Spring Security’s
|
||||
<interfacename>GrantedAuthority</interfacename> interface) containing the authority
|
||||
string and the JAAS principal that the
|
||||
<interfacename>AuthorityGranter</interfacename> was passed. The
|
||||
<classname>JaasAuthenticationProvider</classname> obtains the JAAS
|
||||
principals by firstly successfully authenticating the user’s
|
||||
credentials using the JAAS <literal>LoginModule</literal>, and then
|
||||
accessing the <literal>LoginContext</literal> it returns. A call to
|
||||
<literal>LoginContext.getSubject().getPrincipals()</literal> is
|
||||
made, with each resulting principal passed to each
|
||||
<interfacename>AuthorityGranter</interfacename> defined against the
|
||||
<classname>JaasAuthenticationProvider</classname> obtains the JAAS principals by
|
||||
firstly successfully authenticating the user’s credentials using the JAAS
|
||||
<literal>LoginModule</literal>, and then accessing the
|
||||
<literal>LoginContext</literal> it returns. A call to
|
||||
<literal>LoginContext.getSubject().getPrincipals()</literal> is made, with each
|
||||
resulting principal passed to each <interfacename>AuthorityGranter</interfacename>
|
||||
defined against the
|
||||
<literal>JaasAuthenticationProvider.setAuthorityGranters(List)</literal>
|
||||
property.</para>
|
||||
|
||||
<para>Spring Security does not include any production
|
||||
<interfacename>AuthorityGranter</interfacename>s given that every JAAS principal
|
||||
has an implementation-specific meaning. However, there is a
|
||||
<literal>TestAuthorityGranter</literal> in the unit tests that
|
||||
demonstrates a simple <literal>AuthorityGranter</literal>
|
||||
implementation.</para>
|
||||
<interfacename>AuthorityGranter</interfacename>s given that every JAAS principal has
|
||||
an implementation-specific meaning. However, there is a
|
||||
<literal>TestAuthorityGranter</literal> in the unit tests that demonstrates a simple
|
||||
<literal>AuthorityGranter</literal> implementation.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -16,13 +16,12 @@
|
|||
<para>You should be familiar with LDAP before trying to use it with Spring Security. The
|
||||
following link provides a good introduction to the concepts involved and a guide to
|
||||
setting up a directory using the free LDAP server OpenLDAP: <uri
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="http://www.zytrax.com/books/ldap/"
|
||||
>http://www.zytrax.com/books/ldap/</uri>. Some familiarity with the JNDI APIs used
|
||||
to access LDAP from Java may also be useful. We don't use any third-party LDAP libraries
|
||||
(Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so
|
||||
some familiarity with that project may be useful if you plan on adding your own
|
||||
customizations.</para>
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="http://www.zytrax.com/books/ldap/">http://www.zytrax.com/books/ldap/</uri>.
|
||||
Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. We
|
||||
don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but
|
||||
extensive use is made of Spring LDAP, so some familiarity with that project may be
|
||||
useful if you plan on adding your own customizations.</para>
|
||||
</section>
|
||||
<section>
|
||||
<info>
|
||||
|
@ -30,19 +29,19 @@
|
|||
</info>
|
||||
<para> LDAP authentication in Spring Security can be roughly divided into the following
|
||||
stages. <orderedlist inheritnum="ignore" continuation="restarts">
|
||||
<listitem>
|
||||
<para>Obtaining the unique LDAP <quote>Distinguished Name</quote>, or DN, from
|
||||
the login name. This will often mean performing a search in the directory,
|
||||
unless the exact mapping of usernames to DNs is known in advance.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Authenticating the user, either by binding as that user or by performing a
|
||||
remote <quote>compare</quote> operation of the user's password against the
|
||||
password attribute in the directory entry for the DN.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Loading the list of authorities for the user.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Obtaining the unique LDAP <quote>Distinguished Name</quote>, or DN, from the
|
||||
login name. This will often mean performing a search in the directory, unless
|
||||
the exact mapping of usernames to DNs is known in advance.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Authenticating the user, either by binding as that user or by performing a
|
||||
remote <quote>compare</quote> operation of the user's password against the
|
||||
password attribute in the directory entry for the DN.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Loading the list of authorities for the user.</para>
|
||||
</listitem>
|
||||
</orderedlist> The exception is when the LDAP directory is just being used to retrieve
|
||||
user information and authenticate against it locally. This may not be possible as
|
||||
directories are often set up with limited read access for attributes such as user
|
||||
|
@ -72,8 +71,8 @@
|
|||
<ldap-server root="dc=springframework,dc=org"/>
|
||||
]]>
|
||||
</programlisting> Here we've specified that the root DIT of the directory should be
|
||||
<quote>dc=springframework,dc=org</quote>, which is the default. Used this way,
|
||||
the namespace parser will create an embedded Apache Directory server and scan the
|
||||
<quote>dc=springframework,dc=org</quote>, which is the default. Used this way, the
|
||||
namespace parser will create an embedded Apache Directory server and scan the
|
||||
classpath for any LDIF files, which it will attempt to load into the server. You can
|
||||
customize this behaviour using the <literal>ldif</literal> attribute, which defines
|
||||
an LDIF resource to be loaded: <programlisting><![CDATA[
|
||||
|
@ -102,7 +101,7 @@
|
|||
perform a search under the DN <literal>ou=people,dc=springframework,dc=org</literal>
|
||||
using the value of the <literal>user-search-filter</literal> attribute as a filter.
|
||||
Again the user login name is substituted for the parameter in the filter name. If
|
||||
<literal>user-search-base</literal> isn't supplied, the search will be performed
|
||||
<literal>user-search-base</literal> isn't supplied, the search will be performed
|
||||
from the root. </para>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -111,41 +110,37 @@
|
|||
</info>
|
||||
<para> How authorities are loaded from groups in the LDAP directory is controlled by the
|
||||
following attributes. <itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>group-search-base</literal>. Defines the part of the directory
|
||||
tree under which group searches should be performed.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>group-role-attribute</literal>. The attribute which contains
|
||||
the name of the authority defined by the group entry. Defaults to
|
||||
<literal>cn</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>group-search-filter</literal>. The filter which is used to
|
||||
search for group membership. The default is
|
||||
<literal>uniqueMember={0}</literal>, corresponding to the
|
||||
<literal>groupOfUniqueMembers</literal> LDAP class. In this case,
|
||||
the substituted parameter is the full distinguished name of the user.
|
||||
The parameter <literal>{1}</literal> can be used if you want to filter
|
||||
on the login name.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para> <literal>group-search-base</literal>. Defines the part of the directory
|
||||
tree under which group searches should be performed.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para> <literal>group-role-attribute</literal>. The attribute which contains the
|
||||
name of the authority defined by the group entry. Defaults to
|
||||
<literal>cn</literal> </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para> <literal>group-search-filter</literal>. The filter which is used to
|
||||
search for group membership. The default is
|
||||
<literal>uniqueMember={0}</literal>, corresponding to the
|
||||
<literal>groupOfUniqueMembers</literal> LDAP class. In this case, the
|
||||
substituted parameter is the full distinguished name of the user. The
|
||||
parameter <literal>{1}</literal> can be used if you want to filter on the
|
||||
login name.</para>
|
||||
</listitem>
|
||||
</itemizedlist> So if we used the following configuration <programlisting><![CDATA[
|
||||
<ldap-authentication-provider user-dn-pattern="uid={0},ou=people"
|
||||
group-search-base="ou=groups" />
|
||||
]]></programlisting> and authenticated successfully as user <quote>ben</quote>, the subsequent
|
||||
loading of authorities would perform a search under the directory entry
|
||||
<literal>ou=groups,dc=springframework,dc=org</literal>, looking for entries
|
||||
which contain the attribute <literal>uniqueMember</literal> with value
|
||||
<literal>uid=ben,ou=people,dc=springframework,dc=org</literal>. By default the
|
||||
<literal>ou=groups,dc=springframework,dc=org</literal>, looking for entries which
|
||||
contain the attribute <literal>uniqueMember</literal> with value
|
||||
<literal>uid=ben,ou=people,dc=springframework,dc=org</literal>. By default the
|
||||
authority names will have the prefix <literal>ROLE_</literal> prepended. You can
|
||||
change this using the <literal>role-prefix</literal> attribute. If you don't want
|
||||
any prefix, use <literal>role-prefix="none"</literal>. For more information on
|
||||
loading authorities, see the Javadoc for the
|
||||
<classname>DefaultLdapAuthoritiesPopulator</classname> class. </para>
|
||||
<classname>DefaultLdapAuthoritiesPopulator</classname> class. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -159,10 +154,10 @@
|
|||
using namespace configuration then you can skip this section and the next one. </para>
|
||||
<para> The main LDAP provider class, <classname>LdapAuthenticationProvider</classname>,
|
||||
doesn't actually do much itself but delegates the work to two other beans, an
|
||||
<interfacename>LdapAuthenticator</interfacename> and an
|
||||
<interfacename>LdapAuthoritiesPopulator</interfacename> which are responsible for
|
||||
<interfacename>LdapAuthenticator</interfacename> and an
|
||||
<interfacename>LdapAuthoritiesPopulator</interfacename> which are responsible for
|
||||
authenticating the user and retrieving the user's set of
|
||||
<interfacename>GrantedAuthority</interfacename>s respectively.</para>
|
||||
<interfacename>GrantedAuthority</interfacename>s respectively.</para>
|
||||
<section xml:id="ldap-ldap-authenticators">
|
||||
<info>
|
||||
<title>LdapAuthenticator Implementations</title>
|
||||
|
@ -172,18 +167,16 @@
|
|||
authentication being used. For example, if binding as the user, it may be necessary
|
||||
to read them with the user's own permissions.</para>
|
||||
<para>There are currently two authentication strategies supplied with Spring Security: <itemizedlist>
|
||||
<listitem>
|
||||
<para>Authentication directly to the LDAP server ("bind"
|
||||
authentication).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Password comparison, where the password supplied by the user is
|
||||
compared with the one stored in the repository. This can either be done
|
||||
by retrieving the value of the password attribute and checking it
|
||||
locally or by performing an LDAP "compare" operation, where the supplied
|
||||
password is passed to the server for comparison and the real password
|
||||
value is never retrieved.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Authentication directly to the LDAP server ("bind" authentication).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Password comparison, where the password supplied by the user is compared
|
||||
with the one stored in the repository. This can either be done by retrieving
|
||||
the value of the password attribute and checking it locally or by performing
|
||||
an LDAP "compare" operation, where the supplied password is passed to the
|
||||
server for comparison and the real password value is never retrieved.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
<section xml:id="ldap-ldap-authenticators-common">
|
||||
<info>
|
||||
|
@ -192,33 +185,32 @@
|
|||
<para>Before it is possible to authenticate a user (by either strategy), the
|
||||
distinguished name (DN) has to be obtained from the login name supplied to the
|
||||
application. This can be done either by simple pattern-matching (by setting the
|
||||
<property>setUserDnPatterns</property> array property) or by setting the
|
||||
<property>userSearch</property> property. For the DN pattern-matching
|
||||
approach, a standard Java pattern format is used, and the login name will be
|
||||
substituted for the parameter <parameter>{0}</parameter>. The pattern should be
|
||||
relative to the DN that the configured
|
||||
<interfacename>SpringSecurityContextSource</interfacename> will bind to (see
|
||||
the section on <link linkend="ldap-context-source">connecting to the LDAP
|
||||
server</link> for more information on this). For example, if you are using
|
||||
an LDAP server with the URL
|
||||
<literal>ldap://monkeymachine.co.uk/dc=springframework,dc=org</literal>, and
|
||||
<property>setUserDnPatterns</property> array property) or by setting the
|
||||
<property>userSearch</property> property. For the DN pattern-matching approach,
|
||||
a standard Java pattern format is used, and the login name will be substituted
|
||||
for the parameter <parameter>{0}</parameter>. The pattern should be relative to
|
||||
the DN that the configured
|
||||
<interfacename>SpringSecurityContextSource</interfacename> will bind to (see the
|
||||
section on <link linkend="ldap-context-source">connecting to the LDAP
|
||||
server</link> for more information on this). For example, if you are using an
|
||||
LDAP server with the URL
|
||||
<literal>ldap://monkeymachine.co.uk/dc=springframework,dc=org</literal>, and
|
||||
have a pattern <literal>uid={0},ou=greatapes</literal>, then a login name of
|
||||
"gorilla" will map to a DN
|
||||
<literal>uid=gorilla,ou=greatapes,dc=springframework,dc=org</literal>. Each
|
||||
<literal>uid=gorilla,ou=greatapes,dc=springframework,dc=org</literal>. Each
|
||||
configured DN pattern will be tried in turn until a match is found. For
|
||||
information on using a search, see the section on <link
|
||||
linkend="ldap-searchobjects">search objects</link> below. A combination of
|
||||
the two approaches can also be used - the patterns will be checked first and if
|
||||
no matching DN is found, the search will be used.</para>
|
||||
linkend="ldap-searchobjects">search objects</link> below. A combination of the
|
||||
two approaches can also be used - the patterns will be checked first and if no
|
||||
matching DN is found, the search will be used.</para>
|
||||
</section>
|
||||
<section xml:id="ldap-ldap-authenticators-bind">
|
||||
<info>
|
||||
<title>BindAuthenticator</title>
|
||||
</info>
|
||||
<para>The class <classname>BindAuthenticator</classname> in the package
|
||||
<filename>org.springframework.security.ldap.authentication</filename>
|
||||
implements the bind authentication strategy. It simply attempts to bind as the
|
||||
user.</para>
|
||||
<filename>org.springframework.security.ldap.authentication</filename> implements
|
||||
the bind authentication strategy. It simply attempts to bind as the user.</para>
|
||||
</section>
|
||||
<section xml:id="ldap-ldap-authenticators-password">
|
||||
<info>
|
||||
|
@ -243,7 +235,7 @@
|
|||
to be supplied with a <interfacename>SpringSecurityContextSource</interfacename>
|
||||
which is an extension of Spring LDAP's <interfacename>ContextSource</interfacename>.
|
||||
Unless you have special requirements, you will usually configure a
|
||||
<classname>DefaultSpringSecurityContextSource</classname> bean, which can be
|
||||
<classname>DefaultSpringSecurityContextSource</classname> bean, which can be
|
||||
configured with the URL of your LDAP server and optionally with the username and
|
||||
password of a "manager" user which will be used by default when binding to the
|
||||
server (instead of binding anonymously). For more information read the Javadoc for
|
||||
|
@ -254,38 +246,37 @@
|
|||
<info>
|
||||
<title>LDAP Search Objects</title>
|
||||
</info>
|
||||
<para>Often a more complicated strategy than simple DN-matching is required to
|
||||
locate a user entry in the directory. This can be encapsulated in an
|
||||
<interfacename>LdapUserSearch</interfacename> instance which can be supplied to
|
||||
the authenticator implementations, for example, to allow them to locate a user. The
|
||||
<para>Often a more complicated strategy than simple DN-matching is required to locate a
|
||||
user entry in the directory. This can be encapsulated in an
|
||||
<interfacename>LdapUserSearch</interfacename> instance which can be supplied to the
|
||||
authenticator implementations, for example, to allow them to locate a user. The
|
||||
supplied implementation is <classname>FilterBasedLdapUserSearch</classname>.</para>
|
||||
<section xml:id="ldap-searchobjects-filter">
|
||||
<info>
|
||||
<title xml:id="ldap-searchobjects-filter-based">
|
||||
<classname>FilterBasedLdapUserSearch</classname>
|
||||
</title>
|
||||
<classname>FilterBasedLdapUserSearch</classname> </title>
|
||||
</info>
|
||||
<para>This bean uses an LDAP filter to match the user object in the directory. The
|
||||
process is explained in the Javadoc for the corresponding search method on the
|
||||
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)"
|
||||
>JDK DirContext class</link>. As explained there, the search filter can be
|
||||
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)"
|
||||
>JDK DirContext class</link>. As explained there, the search filter can be
|
||||
supplied with parameters. For this class, the only valid parameter is
|
||||
<parameter>{0}</parameter> which will be replaced with the user's login
|
||||
<parameter>{0}</parameter> which will be replaced with the user's login
|
||||
name.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="ldap-authorities">
|
||||
<title>LdapAuthoritiesPopulator</title>
|
||||
<para> After authenticating the user successfully, the
|
||||
<classname>LdapAuthenticationProvider</classname> will attempt to load a set of
|
||||
<classname>LdapAuthenticationProvider</classname> will attempt to load a set of
|
||||
authorities for the user by calling the configured
|
||||
<interfacename>LdapAuthoritiesPopulator</interfacename> bean. The
|
||||
<classname>DefaultLdapAuthoritiesPopulator</classname> is an implementation
|
||||
which will load the authorities by searching the directory for groups of which the
|
||||
user is a member (typically these will be <literal>groupOfNames</literal> or
|
||||
<literal>groupOfUniqueNames</literal> entries in the directory). Consult the
|
||||
Javadoc for this class for more details on how it works. </para>
|
||||
<interfacename>LdapAuthoritiesPopulator</interfacename> bean. The
|
||||
<classname>DefaultLdapAuthoritiesPopulator</classname> is an implementation which
|
||||
will load the authorities by searching the directory for groups of which the user is
|
||||
a member (typically these will be <literal>groupOfNames</literal> or
|
||||
<literal>groupOfUniqueNames</literal> entries in the directory). Consult the Javadoc
|
||||
for this class for more details on how it works. </para>
|
||||
<para>If you want to use LDAP only for authentication, but load the authorities from a
|
||||
difference source (such as a database) then you can provide your own implementation
|
||||
of this interface and inject that instead.</para>
|
||||
|
@ -325,14 +316,14 @@
|
|||
</programlisting> This would set up the provider to access an LDAP server
|
||||
with URL <literal>ldap://monkeymachine:389/dc=springframework,dc=org</literal>.
|
||||
Authentication will be performed by attempting to bind with the DN
|
||||
<literal>uid=<user-login-name>,ou=people,dc=springframework,dc=org</literal>.
|
||||
<literal>uid=<user-login-name>,ou=people,dc=springframework,dc=org</literal>.
|
||||
After successful authentication, roles will be assigned to the user by searching
|
||||
under the DN <literal>ou=groups,dc=springframework,dc=org</literal> with the default
|
||||
filter <literal>(member=<user's-DN>)</literal>. The role name will be taken
|
||||
from the <quote>ou</quote> attribute of each match.</para>
|
||||
<para>To configure a user search object, which uses the filter
|
||||
<literal>(uid=<user-login-name>)</literal> for use instead of the
|
||||
DN-pattern (or in addition to it), you would configure the following bean <programlisting><![CDATA[
|
||||
<literal>(uid=<user-login-name>)</literal> for use instead of the DN-pattern
|
||||
(or in addition to it), you would configure the following bean <programlisting><![CDATA[
|
||||
<bean id="userSearch"
|
||||
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
|
||||
<constructor-arg index="0" value=""/>
|
||||
|
@ -340,40 +331,40 @@
|
|||
<constructor-arg index="2" ref="contextSource" />
|
||||
</bean> ]]>
|
||||
</programlisting> and use it by setting the
|
||||
<classname>BindAuthenticator</classname> bean's <property>userSearch</property>
|
||||
<classname>BindAuthenticator</classname> bean's <property>userSearch</property>
|
||||
property. The authenticator would then call the search object to obtain the correct
|
||||
user's DN before attempting to bind as this user.</para>
|
||||
</section>
|
||||
<section xml:id="ldap-custom-user-details">
|
||||
<title>LDAP Attributes and Customized UserDetails</title>
|
||||
<para> The net result of an authentication using
|
||||
<classname>LdapAuthenticationProvider</classname> is the same as a normal Spring
|
||||
<classname>LdapAuthenticationProvider</classname> is the same as a normal Spring
|
||||
Security authentication using the standard
|
||||
<interfacename>UserDetailsService</interfacename> interface. A
|
||||
<interfacename>UserDetails</interfacename> object is created and stored in the
|
||||
<interfacename>UserDetailsService</interfacename> interface. A
|
||||
<interfacename>UserDetails</interfacename> object is created and stored in the
|
||||
returned <interfacename>Authentication</interfacename> object. As with using a
|
||||
<interfacename>UserDetailsService</interfacename>, a common requirement is to be
|
||||
<interfacename>UserDetailsService</interfacename>, a common requirement is to be
|
||||
able to customize this implementation and add extra properties. When using LDAP,
|
||||
these will normally be attributes from the user entry. The creation of the
|
||||
<interfacename>UserDetails</interfacename> object is controlled by the
|
||||
provider's <interfacename>UserDetailsContextMapper</interfacename> strategy, which
|
||||
is responsible for mapping user objects to and from LDAP context data: <programlisting><![CDATA[
|
||||
<interfacename>UserDetails</interfacename> object is controlled by the provider's
|
||||
<interfacename>UserDetailsContextMapper</interfacename> strategy, which is
|
||||
responsible for mapping user objects to and from LDAP context data: <programlisting><![CDATA[
|
||||
public interface UserDetailsContextMapper {
|
||||
UserDetails mapUserFromContext(DirContextOperations ctx, String username,
|
||||
Collection<GrantedAuthority> authorities);
|
||||
|
||||
void mapUserToContext(UserDetails user, DirContextAdapter ctx);
|
||||
}]]>
|
||||
</programlisting> Only the first method is relevant for
|
||||
authentication. If you provide an implementation of this interface, you can control
|
||||
exactly how the UserDetails object is created. The first parameter is an instance of
|
||||
Spring LDAP's <interfacename>DirContextOperations</interfacename> which gives you
|
||||
access to the LDAP attributes which were loaded. The <literal>username</literal>
|
||||
parameter is the name used to authenticate and the final parameter is the collection
|
||||
of authorities loaded for the user. </para>
|
||||
</programlisting> Only the first method is relevant for authentication. If you
|
||||
provide an implementation of this interface, you can control exactly how the
|
||||
UserDetails object is created. The first parameter is an instance of Spring LDAP's
|
||||
<interfacename>DirContextOperations</interfacename> which gives you access to the
|
||||
LDAP attributes which were loaded. The <literal>username</literal> parameter is the
|
||||
name used to authenticate and the final parameter is the collection of authorities
|
||||
loaded for the user. </para>
|
||||
<para> The way the context data is loaded varies slightly depending on the type of
|
||||
authentication you are using. With the <classname>BindAuthenticator</classname>,
|
||||
the context returned from the bind operation will be used to read the attributes,
|
||||
authentication you are using. With the <classname>BindAuthenticator</classname>, the
|
||||
context returned from the bind operation will be used to read the attributes,
|
||||
otherwise the data will be read using the standard context obtained from the
|
||||
configured <interfacename>ContextSource</interfacename> (when a search is configured
|
||||
to locate the user, this will be the data returned by the search object). </para>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,142 +1,154 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="preauth"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Pre-Authentication Scenarios</title>
|
||||
</info>
|
||||
<para> There are situations where you want to use Spring Security for authorization, but the user
|
||||
has already been reliably authenticated by some external system prior to accessing the
|
||||
application. We refer to these situations as <quote>pre-authenticated</quote> scenarios.
|
||||
Examples include X.509, Siteminder and authentication by the J2EE container in which the
|
||||
application is running. When using pre-authentication, Spring Security has to
|
||||
<orderedlist><listitem><para>Identify the user making the request.
|
||||
</para></listitem><listitem><para>Obtain the authorities for the
|
||||
user.</para></listitem></orderedlist>The details will depend on the external authentication
|
||||
mechanism. A user might be identified by their certificate information in the case of X.509, or
|
||||
by an HTTP request header in the case of Siteminder. If relying on container authentication, the
|
||||
user will be identified by calling the <methodname>getUserPrincipal()</methodname> method on the
|
||||
incoming HTTP request. In some cases, the external mechanism may supply role/authority
|
||||
information for the user but in others the authorities must be obtained from a separate source,
|
||||
such as a <interfacename>UserDetailsService</interfacename>. </para>
|
||||
<section>
|
||||
<title>Pre-Authentication Framework Classes</title>
|
||||
<para> Because most pre-authentication mechanisms follow the same pattern, Spring Security has a
|
||||
set of classes which provide an internal framework for implementing pre-authenticated
|
||||
authentication providers. This removes duplication and allows new implementations to be added
|
||||
in a structured fashion, without having to write everything from scratch. You don't need to
|
||||
know about these classes if you want to use something like <link xlink:href="#x509">X.509
|
||||
authentication</link>, as it already has a namespace configuration option which is simpler
|
||||
to use and get started with. If you need to use explicit bean configuration or are planning on
|
||||
writing your own implementation then an understanding of how the provided implementations work
|
||||
will be useful. You will find classes under the
|
||||
<package>org.springframework.security.web.authentication.preauth</package>. We just provide
|
||||
an outline here so you should consult the Javadoc and source where appropriate. </para>
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Pre-Authentication Scenarios</title>
|
||||
</info>
|
||||
<para> There are situations where you want to use Spring Security for authorization, but the
|
||||
user has already been reliably authenticated by some external system prior to accessing the
|
||||
application. We refer to these situations as <quote>pre-authenticated</quote> scenarios.
|
||||
Examples include X.509, Siteminder and authentication by the J2EE container in which the
|
||||
application is running. When using pre-authentication, Spring Security has to <orderedlist>
|
||||
<listitem>
|
||||
<para>Identify the user making the request. </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Obtain the authorities for the user.</para>
|
||||
</listitem>
|
||||
</orderedlist>The details will depend on the external authentication mechanism. A user might
|
||||
be identified by their certificate information in the case of X.509, or by an HTTP request
|
||||
header in the case of Siteminder. If relying on container authentication, the user will be
|
||||
identified by calling the <methodname>getUserPrincipal()</methodname> method on the incoming
|
||||
HTTP request. In some cases, the external mechanism may supply role/authority information
|
||||
for the user but in others the authorities must be obtained from a separate source, such as
|
||||
a <interfacename>UserDetailsService</interfacename>. </para>
|
||||
<section>
|
||||
<title>AbstractPreAuthenticatedProcessingFilter</title>
|
||||
<para> This class will check the current contents of the security context and, if empty, it
|
||||
will attempt to extract user information from the HTTP request and submit it to the
|
||||
<interfacename>AuthenticationManager</interfacename>. Subclasses override the following
|
||||
methods to obtain this information:
|
||||
<programlisting language="java">
|
||||
<title>Pre-Authentication Framework Classes</title>
|
||||
<para> Because most pre-authentication mechanisms follow the same pattern, Spring Security
|
||||
has a set of classes which provide an internal framework for implementing
|
||||
pre-authenticated authentication providers. This removes duplication and allows new
|
||||
implementations to be added in a structured fashion, without having to write everything
|
||||
from scratch. You don't need to know about these classes if you want to use something
|
||||
like <link xlink:href="#x509">X.509 authentication</link>, as it already has a namespace
|
||||
configuration option which is simpler to use and get started with. If you need to use
|
||||
explicit bean configuration or are planning on writing your own implementation then an
|
||||
understanding of how the provided implementations work will be useful. You will find
|
||||
classes under the
|
||||
<package>org.springframework.security.web.authentication.preauth</package>. We just
|
||||
provide an outline here so you should consult the Javadoc and source where appropriate. </para>
|
||||
<section>
|
||||
<title>AbstractPreAuthenticatedProcessingFilter</title>
|
||||
<para> This class will check the current contents of the security context and, if empty,
|
||||
it will attempt to extract user information from the HTTP request and submit it to
|
||||
the <interfacename>AuthenticationManager</interfacename>. Subclasses override the
|
||||
following methods to obtain this information:
|
||||
<programlisting language="java">
|
||||
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
|
||||
|
||||
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
|
||||
</programlisting>
|
||||
After calling these, the filter will create a
|
||||
<classname>PreAuthenticatedAuthenticationToken</classname> containing the returned data
|
||||
and submit it for authentication. By <quote>authentication</quote> here, we really just mean
|
||||
further processing to perhaps load the user's authorities, but the standard Spring Security
|
||||
authentication architecture is followed. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>AbstractPreAuthenticatedAuthenticationDetailsSource</title>
|
||||
<para> Like other Spring Security authentication filters, the pre-authentication filter has an
|
||||
<literal>authenticationDetailsSource</literal> property which by default will create a
|
||||
<classname>WebAuthenticationDetails</classname> object to store additional information
|
||||
such as the session-identifier and originating IP address in the <literal>details</literal>
|
||||
property of the <interfacename>Authentication</interfacename> object. In cases where user
|
||||
role information can be obtained from the pre-authentication mechanism, the data is also
|
||||
stored in this property. Subclasses of
|
||||
<classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an extended
|
||||
details object which implements the
|
||||
<interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling the
|
||||
authentication provider to read the authorities which were externally allocated to the user.
|
||||
We'll look at a concrete example next. </para>
|
||||
<section xml:id="j2ee-preauth-details">
|
||||
<title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title>
|
||||
<para> If the filter is configured with an <literal>authenticationDetailsSource</literal>
|
||||
which is an instance of this class, the authority information is obtained by calling the
|
||||
<methodname>isUserInRole(String role)</methodname> method for each of a pre-determined
|
||||
set of <quote>mappable roles</quote>. The class gets these from a configured
|
||||
<interfacename>MappableAttributesRetriever</interfacename>. Possible implementations
|
||||
include hard-coding a list in the application context and reading the role information
|
||||
from the <literal><security-role></literal> information in a
|
||||
<filename>web.xml</filename> file. The pre-authentication sample application uses the
|
||||
latter approach. </para>
|
||||
<para>There is an additional stage where the roles (or attributes) are mapped to Spring
|
||||
Security <interfacename>GrantedAuthority</interfacename> objects using a configured
|
||||
<interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>. The default will
|
||||
just add the usual <literal>ROLE_</literal> prefix to the names, but it gives you full
|
||||
control over the behaviour. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>PreAuthenticatedAuthenticationProvider</title>
|
||||
<para> The pre-authenticated provider has little more to do than load the
|
||||
<interfacename>UserDetails</interfacename> object for the user. It does this by delegating
|
||||
to a <interfacename>AuthenticationUserDetailsService</interfacename>. The latter is similar
|
||||
to the standard <interfacename>UserDetailsService</interfacename> but takes an
|
||||
<interfacename>Authentication</interfacename> object rather than just user name:
|
||||
<programlisting language="java">
|
||||
After calling these, the filter will create a
|
||||
<classname>PreAuthenticatedAuthenticationToken</classname> containing the returned
|
||||
data and submit it for authentication. By <quote>authentication</quote> here, we
|
||||
really just mean further processing to perhaps load the user's authorities, but the
|
||||
standard Spring Security authentication architecture is followed. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>AbstractPreAuthenticatedAuthenticationDetailsSource</title>
|
||||
<para> Like other Spring Security authentication filters, the pre-authentication filter
|
||||
has an <literal>authenticationDetailsSource</literal> property which by default will
|
||||
create a <classname>WebAuthenticationDetails</classname> object to store additional
|
||||
information such as the session-identifier and originating IP address in the
|
||||
<literal>details</literal> property of the
|
||||
<interfacename>Authentication</interfacename> object. In cases where user role
|
||||
information can be obtained from the pre-authentication mechanism, the data is also
|
||||
stored in this property. Subclasses of
|
||||
<classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an
|
||||
extended details object which implements the
|
||||
<interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling
|
||||
the authentication provider to read the authorities which were externally allocated
|
||||
to the user. We'll look at a concrete example next. </para>
|
||||
<section xml:id="j2ee-preauth-details">
|
||||
<title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title>
|
||||
<para> If the filter is configured with an
|
||||
<literal>authenticationDetailsSource</literal> which is an instance of this
|
||||
class, the authority information is obtained by calling the
|
||||
<methodname>isUserInRole(String role)</methodname> method for each of a
|
||||
pre-determined set of <quote>mappable roles</quote>. The class gets these from a
|
||||
configured <interfacename>MappableAttributesRetriever</interfacename>. Possible
|
||||
implementations include hard-coding a list in the application context and
|
||||
reading the role information from the <literal><security-role></literal>
|
||||
information in a <filename>web.xml</filename> file. The pre-authentication
|
||||
sample application uses the latter approach. </para>
|
||||
<para>There is an additional stage where the roles (or attributes) are mapped to
|
||||
Spring Security <interfacename>GrantedAuthority</interfacename> objects using a
|
||||
configured <interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>.
|
||||
The default will just add the usual <literal>ROLE_</literal> prefix to the
|
||||
names, but it gives you full control over the behaviour. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>PreAuthenticatedAuthenticationProvider</title>
|
||||
<para> The pre-authenticated provider has little more to do than load the
|
||||
<interfacename>UserDetails</interfacename> object for the user. It does this by
|
||||
delegating to a <interfacename>AuthenticationUserDetailsService</interfacename>. The
|
||||
latter is similar to the standard <interfacename>UserDetailsService</interfacename>
|
||||
but takes an <interfacename>Authentication</interfacename> object rather than just
|
||||
user name:
|
||||
<programlisting language="java">
|
||||
public interface AuthenticationUserDetailsService {
|
||||
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
|
||||
}
|
||||
</programlisting>
|
||||
This interface may have also other uses but with pre-authentication it allows access to the
|
||||
authorities which were packaged in the <interfacename>Authentication</interfacename> object,
|
||||
as we saw in the previous section. The
|
||||
<classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class does
|
||||
this. Alternatively, it may delegate to a standard
|
||||
<interfacename>UserDetailsService</interfacename> via the
|
||||
<classname>UserDetailsByNameServiceWrapper</classname> implementation. </para>
|
||||
This interface may have also other uses but with pre-authentication it allows access
|
||||
to the authorities which were packaged in the
|
||||
<interfacename>Authentication</interfacename> object, as we saw in the previous
|
||||
section. The
|
||||
<classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class
|
||||
does this. Alternatively, it may delegate to a standard
|
||||
<interfacename>UserDetailsService</interfacename> via the
|
||||
<classname>UserDetailsByNameServiceWrapper</classname> implementation. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Http403ForbiddenEntryPoint</title>
|
||||
<para> The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the
|
||||
<link xlink:href="#tech-intro-auth-entry-point">technical overview</link> chapter.
|
||||
Normally it is responsible for kick-starting the authentication process for an
|
||||
unauthenticated user (when they try to access a protected resource), but in the
|
||||
pre-authenticated case this doesn't apply. You would only configure the
|
||||
<classname>ExceptionTranslationFilter</classname> with an instance of this class if
|
||||
you aren't using pre-authentication in combination with other authentication
|
||||
mechanisms. It will be called if the user is rejected by the
|
||||
<classname>AbstractPreAuthenticatedProcessingFilter</classname> resulting in a null
|
||||
authentication. It always returns a <literal>403</literal>-forbidden response code
|
||||
if called. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Http403ForbiddenEntryPoint</title>
|
||||
<para> The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the <link
|
||||
xlink:href="#tech-intro-auth-entry-point">technical overview</link> chapter. Normally it
|
||||
is responsible for kick-starting the authentication process for an unauthenticated user
|
||||
(when they try to access a protected resource), but in the pre-authenticated case this
|
||||
doesn't apply. You would only configure the
|
||||
<classname>ExceptionTranslationFilter</classname> with an instance of this class if you
|
||||
aren't using pre-authentication in combination with other authentication mechanisms. It will
|
||||
be called if the user is rejected by the
|
||||
<classname>AbstractPreAuthenticatedProcessingFilter</classname> resulting in a null
|
||||
authentication. It always returns a <literal>403</literal>-forbidden response code if
|
||||
called. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Concrete Implementations</title>
|
||||
<para> X.509 authentication is covered in its <link xlink:href="#x509">own chapter</link>. Here
|
||||
we'll look at some classes which provide support for other pre-authenticated scenarios. </para>
|
||||
<section>
|
||||
<title>Request-Header Authentication (Siteminder)</title>
|
||||
<para> An external authentication system may supply information to the application by setting
|
||||
specific headers on the HTTP request. A well known example of this is Siteminder, which
|
||||
passes the username in a header called <literal>SM_USER</literal>. This mechanism is
|
||||
supported by the class <classname>RequestHeaderAuthenticationFilter</classname> which simply
|
||||
extracts the username from the header. It defaults to using the name
|
||||
<literal>SM_USER</literal> as the header name. See the Javadoc for more details. </para>
|
||||
<tip>
|
||||
<para>Note that when using a system like this, the framework performs no authentication
|
||||
checks at all and it is <emphasis>extremely</emphasis> important that the external system
|
||||
is configured properly and protects all access to the application. If an attacker is able
|
||||
to forge the headers in their original request without this being detected then they could
|
||||
potentially choose any username they wished. </para>
|
||||
</tip>
|
||||
<section>
|
||||
<title>Siteminder Example Configuration</title>
|
||||
<para> A typical configuration using this filter would look like this: <programlisting><![CDATA[
|
||||
<title>Concrete Implementations</title>
|
||||
<para> X.509 authentication is covered in its <link xlink:href="#x509">own chapter</link>.
|
||||
Here we'll look at some classes which provide support for other pre-authenticated
|
||||
scenarios. </para>
|
||||
<section>
|
||||
<title>Request-Header Authentication (Siteminder)</title>
|
||||
<para> An external authentication system may supply information to the application by
|
||||
setting specific headers on the HTTP request. A well known example of this is
|
||||
Siteminder, which passes the username in a header called <literal>SM_USER</literal>.
|
||||
This mechanism is supported by the class
|
||||
<classname>RequestHeaderAuthenticationFilter</classname> which simply extracts the
|
||||
username from the header. It defaults to using the name <literal>SM_USER</literal>
|
||||
as the header name. See the Javadoc for more details. </para>
|
||||
<tip>
|
||||
<para>Note that when using a system like this, the framework performs no
|
||||
authentication checks at all and it is <emphasis>extremely</emphasis> important
|
||||
that the external system is configured properly and protects all access to the
|
||||
application. If an attacker is able to forge the headers in their original
|
||||
request without this being detected then they could potentially choose any
|
||||
username they wished. </para>
|
||||
</tip>
|
||||
<section>
|
||||
<title>Siteminder Example Configuration</title>
|
||||
<para> A typical configuration using this filter would look like this: <programlisting><![CDATA[
|
||||
<security:http>
|
||||
<!-- Additional http configuration omitted -->
|
||||
<security:custom-filter ref="siteminderFilter" />
|
||||
|
@ -162,27 +174,28 @@ class="org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
|||
<security:authentication-provider ref="preauthAuthProvider" />
|
||||
</security-authentication-manager>
|
||||
]]>
|
||||
</programlisting> We've assumed here that the security namespace is being used for
|
||||
configuration (hence the user of the <literal>custom-filter</literal>,
|
||||
<literal>authentication-manager</literal> and
|
||||
<literal>custom-authentication-provider</literal> elements (you can read more about them
|
||||
in the <link xlink:href="ns-config">namespace chapter</link>). You would leave these out
|
||||
of a traditional bean configuration. It's also assumed that you have added a
|
||||
<interfacename>UserDetailsService</interfacename> (called
|
||||
<quote>userDetailsService</quote>) to your configuration to load the user's roles.
|
||||
</para>
|
||||
</section>
|
||||
</programlisting> We've assumed here that the security namespace is being used for configuration
|
||||
(hence the user of the <literal>custom-filter</literal>,
|
||||
<literal>authentication-manager</literal> and
|
||||
<literal>custom-authentication-provider</literal> elements (you can read more
|
||||
about them in the <link xlink:href="ns-config">namespace chapter</link>). You
|
||||
would leave these out of a traditional bean configuration. It's also assumed
|
||||
that you have added a <interfacename>UserDetailsService</interfacename> (called
|
||||
<quote>userDetailsService</quote>) to your configuration to load the user's
|
||||
roles. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>J2EE Container Authentication</title>
|
||||
<para> The class <classname>J2eePreAuthenticatedProcessingFilter</classname> will
|
||||
extract the username from the <literal>userPrincipal</literal> property of the
|
||||
<interfacename>HttpServletRequest</interfacename>. Use of this filter would usually
|
||||
be combined with the use of J2EE roles as described above in <xref
|
||||
linkend="j2ee-preauth-details"/>. </para>
|
||||
<para> There is a sample application in the codebase which uses this approach, so get
|
||||
hold of the code from subversion and have a look at the application context file if
|
||||
you are interested. The code is in the <filename>samples/preauth</filename>
|
||||
directory. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>J2EE Container Authentication</title>
|
||||
<para> The class <classname>J2eePreAuthenticatedProcessingFilter</classname> will extract the
|
||||
username from the <literal>userPrincipal</literal> property of the
|
||||
<interfacename>HttpServletRequest</interfacename>. Use of this filter would usually be
|
||||
combined with the use of J2EE roles as described above in <xref
|
||||
linkend="j2ee-preauth-details"/>. </para>
|
||||
<para> There is a sample application in the codebase which uses this approach, so get hold of
|
||||
the code from subversion and have a look at the application context file if you are
|
||||
interested. The code is in the <filename>samples/preauth</filename> directory. </para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
One uses hashing to preserve the security of cookie-based tokens and the other uses a
|
||||
database or other persistent storage mechanism to store the generated tokens. </para>
|
||||
<para> Note that both implemementations require a
|
||||
<interfacename>UserDetailsService</interfacename>. If you are using an
|
||||
authentication provider which doesn't use a
|
||||
<interfacename>UserDetailsService</interfacename> (for example, the LDAP provider)
|
||||
then it won't work unless you also have a
|
||||
<interfacename>UserDetailsService</interfacename> bean in your application context.
|
||||
<interfacename>UserDetailsService</interfacename>. If you are using an authentication
|
||||
provider which doesn't use a <interfacename>UserDetailsService</interfacename> (for
|
||||
example, the LDAP provider) then it won't work unless you also have a
|
||||
<interfacename>UserDetailsService</interfacename> bean in your application context.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="remember-me-hash-token">
|
||||
|
@ -46,7 +45,7 @@
|
|||
more significant security is needed you should use the approach described in the next
|
||||
section. Alternatively remember-me services should simply not be used at all.</para>
|
||||
<para>If you are familiar with the topics discussed in the chapter on <link
|
||||
xlink:href="#ns-config">namespace configuration</link>, you can enable remember-me
|
||||
xlink:href="#ns-config">namespace configuration</link>, you can enable remember-me
|
||||
authentication just by adding the <literal><remember-me></literal> element: <programlisting><![CDATA[
|
||||
<http>
|
||||
...
|
||||
|
@ -56,26 +55,27 @@
|
|||
</programlisting> The <interfacename>UserDetailsService</interfacename> will
|
||||
normally be selected automatically. If you have more than one in your application
|
||||
context, you need to specify which one should be used with the
|
||||
<literal>user-service-ref</literal> attribute, where the value is the name of your
|
||||
<interfacename>UserDetailsService</interfacename> bean. </para>
|
||||
<literal>user-service-ref</literal> attribute, where the value is the name of your
|
||||
<interfacename>UserDetailsService</interfacename> bean. </para>
|
||||
</section>
|
||||
<section xml:id="remember-me-persistent-token">
|
||||
<title>Persistent Token Approach</title>
|
||||
<para>This approach is based on the article <link
|
||||
xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice"
|
||||
>http://jaspan.com/improved_persistent_login_cookie_best_practice</link> with some
|
||||
minor modifications <footnote><para>Essentially, the username is not included in the
|
||||
cookie, to prevent exposing a valid login name unecessarily. There is a
|
||||
discussion on this in the comments section of this article.</para></footnote>.
|
||||
To use the this approach with namespace configuration, you would supply a datasource
|
||||
reference: <programlisting><![CDATA[
|
||||
xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice"
|
||||
>http://jaspan.com/improved_persistent_login_cookie_best_practice</link> with some minor
|
||||
modifications <footnote>
|
||||
<para>Essentially, the username is not included in the cookie, to prevent exposing a
|
||||
valid login name unecessarily. There is a discussion on this in the comments section
|
||||
of this article.</para>
|
||||
</footnote>. To use the this approach with namespace configuration, you would supply a
|
||||
datasource reference: <programlisting><![CDATA[
|
||||
<http>
|
||||
...
|
||||
<remember-me data-source-ref="someDataSource"/>
|
||||
</http>
|
||||
]]>
|
||||
</programlisting> The database should contain a
|
||||
<literal>persistent_logins</literal> table, created using the following SQL (or
|
||||
<literal>persistent_logins</literal> table, created using the following SQL (or
|
||||
equivalent):
|
||||
<programlisting>
|
||||
create table persistent_logins (username varchar(64) not null,
|
||||
|
@ -91,10 +91,10 @@
|
|||
</info>
|
||||
<para>Remember-me authentication is not used with basic authentication, given it is often
|
||||
not used with <literal>HttpSession</literal>s. Remember-me is used with
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal>, and is implemented via
|
||||
hooks in the <literal>AbstractAuthenticationProcessingFilter</literal> superclass. The
|
||||
hooks will invoke a concrete <interfacename>RememberMeServices</interfacename> at the
|
||||
appropriate times. The interface looks like this:
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal>, and is implemented via hooks in
|
||||
the <literal>AbstractAuthenticationProcessingFilter</literal> superclass. The hooks will
|
||||
invoke a concrete <interfacename>RememberMeServices</interfacename> at the appropriate
|
||||
times. The interface looks like this:
|
||||
<programlisting language="java">
|
||||
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
|
||||
void loginFail(HttpServletRequest request, HttpServletResponse response);
|
||||
|
@ -105,9 +105,9 @@
|
|||
note at this stage that <literal>AbstractAuthenticationProcessingFilter</literal> only
|
||||
calls the <literal>loginFail()</literal> and <literal>loginSuccess()</literal> methods.
|
||||
The <literal>autoLogin()</literal> method is called by
|
||||
<classname>RememberMeAuthenticationFilter</classname> whenever the
|
||||
<classname>SecurityContextHolder</classname> does not contain an
|
||||
<interfacename>Authentication</interfacename>. This interface therefore provides the
|
||||
<classname>RememberMeAuthenticationFilter</classname> whenever the
|
||||
<classname>SecurityContextHolder</classname> does not contain an
|
||||
<interfacename>Authentication</interfacename>. This interface therefore provides the
|
||||
underlying remember-me implementation with sufficient notification of
|
||||
authentication-related events, and delegates to the implementation whenever a candidate
|
||||
web request might contain a cookie and wish to be remembered. This design allows any
|
||||
|
@ -116,18 +116,18 @@
|
|||
<section>
|
||||
<title>TokenBasedRememberMeServices</title>
|
||||
<para> This implementation supports the simpler approach described in <xref
|
||||
linkend="remember-me-hash-token"/>.
|
||||
<classname>TokenBasedRememberMeServices</classname> generates a
|
||||
<literal>RememberMeAuthenticationToken</literal>, which is processed by
|
||||
<literal>RememberMeAuthenticationProvider</literal>. A <literal>key</literal> is
|
||||
linkend="remember-me-hash-token"/>.
|
||||
<classname>TokenBasedRememberMeServices</classname> generates a
|
||||
<literal>RememberMeAuthenticationToken</literal>, which is processed by
|
||||
<literal>RememberMeAuthenticationProvider</literal>. A <literal>key</literal> is
|
||||
shared between this authentication provider and the
|
||||
<literal>TokenBasedRememberMeServices</literal>. In addition,
|
||||
<literal>TokenBasedRememberMeServices</literal> requires A UserDetailsService
|
||||
from which it can retrieve the username and password for signature comparison
|
||||
purposes, and generate the <literal>RememberMeAuthenticationToken</literal> to
|
||||
contain the correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of
|
||||
logout command should be provided by the application that invalidates the cookie if
|
||||
the user requests this. <classname>TokenBasedRememberMeServices</classname> also
|
||||
<literal>TokenBasedRememberMeServices</literal>. In addition,
|
||||
<literal>TokenBasedRememberMeServices</literal> requires A UserDetailsService from
|
||||
which it can retrieve the username and password for signature comparison purposes,
|
||||
and generate the <literal>RememberMeAuthenticationToken</literal> to contain the
|
||||
correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of logout
|
||||
command should be provided by the application that invalidates the cookie if the
|
||||
user requests this. <classname>TokenBasedRememberMeServices</classname> also
|
||||
implements Spring Security's <interfacename>LogoutHandler</interfacename> interface
|
||||
so can be used with <classname>LogoutFilter</classname> to have the cookie cleared
|
||||
automatically. </para>
|
||||
|
@ -151,26 +151,30 @@
|
|||
</bean>
|
||||
]]>
|
||||
</programlisting>Don't forget to add your
|
||||
<interfacename>RememberMeServices</interfacename> implementation to your
|
||||
<literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal>
|
||||
<interfacename>RememberMeServices</interfacename> implementation to your
|
||||
<literal>UsernamePasswordAuthenticationFilter.setRememberMeServices()</literal>
|
||||
property, include the <literal>RememberMeAuthenticationProvider</literal> in your
|
||||
<literal>AuthenticationManager.setProviders()</literal> list, and add
|
||||
<classname>RememberMeAuthenticationFilter</classname> into your
|
||||
<classname>FilterChainProxy</classname> (typically immediately after your
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal>).</para>
|
||||
<literal>AuthenticationManager.setProviders()</literal> list, and add
|
||||
<classname>RememberMeAuthenticationFilter</classname> into your
|
||||
<classname>FilterChainProxy</classname> (typically immediately after your
|
||||
<literal>UsernamePasswordAuthenticationFilter</literal>).</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>PersistentTokenBasedRememberMeServices</title>
|
||||
<para> This class can be used in the same way as
|
||||
<classname>TokenBasedRememberMeServices</classname>, but it additionally needs
|
||||
to be configured with a <interfacename>PersistentTokenRepository</interfacename> to
|
||||
store the tokens. There are two standard implementations.
|
||||
<itemizedlist><listitem><para><classname>InMemoryTokenRepositoryImpl</classname>
|
||||
which is intended for testing
|
||||
only.</para></listitem><listitem><para><classname>JdbcTokenRepositoryImpl</classname>
|
||||
which stores the tokens in a database. </para></listitem></itemizedlist>
|
||||
The database schema is described above in <xref
|
||||
linkend="remember-me-persistent-token"/>. </para>
|
||||
<classname>TokenBasedRememberMeServices</classname>, but it additionally needs to be
|
||||
configured with a <interfacename>PersistentTokenRepository</interfacename> to store
|
||||
the tokens. There are two standard implementations. <itemizedlist>
|
||||
<listitem>
|
||||
<para><classname>InMemoryTokenRepositoryImpl</classname> which is intended for
|
||||
testing only.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>JdbcTokenRepositoryImpl</classname> which stores the tokens in
|
||||
a database. </para>
|
||||
</listitem>
|
||||
</itemizedlist> The database schema is described above in <xref
|
||||
linkend="remember-me-persistent-token"/>. </para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -1,92 +1,84 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="runas"><info><title>Run-As Authentication Replacement</title></info>
|
||||
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="runas">
|
||||
<info>
|
||||
<title>Run-As Authentication Replacement</title>
|
||||
</info>
|
||||
|
||||
<section xml:id="runas-overview">
|
||||
<info><title>Overview</title></info>
|
||||
<info>
|
||||
<title>Overview</title>
|
||||
</info>
|
||||
|
||||
<para>The <classname>AbstractSecurityInterceptor</classname> is able to
|
||||
temporarily replace the <interfacename>Authentication</interfacename> object in
|
||||
the <interfacename>SecurityContext</interfacename> and
|
||||
<classname>SecurityContextHolder</classname> during the secure object
|
||||
callback phase. This only occurs if the original
|
||||
<interfacename>Authentication</interfacename> object was successfully processed by
|
||||
the <interfacename>AuthenticationManager</interfacename> and
|
||||
<interfacename>AccessDecisionManager</interfacename>. The
|
||||
<para>The <classname>AbstractSecurityInterceptor</classname> is able to temporarily replace
|
||||
the <interfacename>Authentication</interfacename> object in the
|
||||
<interfacename>SecurityContext</interfacename> and
|
||||
<classname>SecurityContextHolder</classname> during the secure object callback phase.
|
||||
This only occurs if the original <interfacename>Authentication</interfacename> object
|
||||
was successfully processed by the <interfacename>AuthenticationManager</interfacename>
|
||||
and <interfacename>AccessDecisionManager</interfacename>. The
|
||||
<literal>RunAsManager</literal> will indicate the replacement
|
||||
<interfacename>Authentication</interfacename> object, if any, that should be used
|
||||
during the <literal>SecurityInterceptorCallback</literal>.</para>
|
||||
<interfacename>Authentication</interfacename> object, if any, that should be used during
|
||||
the <literal>SecurityInterceptorCallback</literal>.</para>
|
||||
|
||||
<para>By temporarily replacing the <interfacename>Authentication</interfacename>
|
||||
object during the secure object callback phase, the secured invocation
|
||||
will be able to call other objects which require different
|
||||
authentication and authorization credentials. It will also be able to
|
||||
perform any internal security checks for specific
|
||||
<para>By temporarily replacing the <interfacename>Authentication</interfacename> object
|
||||
during the secure object callback phase, the secured invocation will be able to call
|
||||
other objects which require different authentication and authorization credentials. It
|
||||
will also be able to perform any internal security checks for specific
|
||||
<interfacename>GrantedAuthority</interfacename> objects. Because Spring Security
|
||||
provides a number of helper classes that automatically configure
|
||||
remoting protocols based on the contents of the
|
||||
<classname>SecurityContextHolder</classname>, these run-as replacements
|
||||
are particularly useful when calling remote web services</para>
|
||||
provides a number of helper classes that automatically configure remoting protocols
|
||||
based on the contents of the <classname>SecurityContextHolder</classname>, these run-as
|
||||
replacements are particularly useful when calling remote web services</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="runas-config">
|
||||
<info><title>Configuration</title></info>
|
||||
<info>
|
||||
<title>Configuration</title>
|
||||
</info>
|
||||
<para>A <literal>RunAsManager</literal> interface is provided by Spring Security:
|
||||
<programlisting>
|
||||
Authentication buildRunAs(Authentication authentication, Object object,
|
||||
List<ConfigAttribute> config);
|
||||
boolean supports(ConfigAttribute attribute);
|
||||
boolean supports(Class clazz);
|
||||
</programlisting>
|
||||
</para>
|
||||
</programlisting> </para>
|
||||
|
||||
<para>The first method returns the <interfacename>Authentication</interfacename>
|
||||
object that should replace the existing
|
||||
<interfacename>Authentication</interfacename> object for the duration of the
|
||||
method invocation. If the method returns <literal>null</literal>, it
|
||||
indicates no replacement should be made. The second method is used by
|
||||
the <classname>AbstractSecurityInterceptor</classname> as part of its
|
||||
startup validation of configuration attributes. The
|
||||
<literal>supports(Class)</literal> method is called by a security
|
||||
interceptor implementation to ensure the configured
|
||||
<literal>RunAsManager</literal> supports the type of secure object
|
||||
that the security interceptor will present.</para>
|
||||
<para>The first method returns the <interfacename>Authentication</interfacename> object that
|
||||
should replace the existing <interfacename>Authentication</interfacename> object for the
|
||||
duration of the method invocation. If the method returns <literal>null</literal>, it
|
||||
indicates no replacement should be made. The second method is used by the
|
||||
<classname>AbstractSecurityInterceptor</classname> as part of its startup validation of
|
||||
configuration attributes. The <literal>supports(Class)</literal> method is called by a
|
||||
security interceptor implementation to ensure the configured
|
||||
<literal>RunAsManager</literal> supports the type of secure object that the security
|
||||
interceptor will present.</para>
|
||||
|
||||
<para>One concrete implementation of a <literal>RunAsManager</literal>
|
||||
is provided with Spring Security. The
|
||||
<literal>RunAsManagerImpl</literal> class returns a replacement
|
||||
<literal>RunAsUserToken</literal> if any
|
||||
<literal>ConfigAttribute</literal> starts with
|
||||
<literal>RUN_AS_</literal>. If any such
|
||||
<literal>ConfigAttribute</literal> is found, the replacement
|
||||
<literal>RunAsUserToken</literal> will contain the same principal,
|
||||
<para>One concrete implementation of a <literal>RunAsManager</literal> is provided with
|
||||
Spring Security. The <literal>RunAsManagerImpl</literal> class returns a replacement
|
||||
<literal>RunAsUserToken</literal> if any <literal>ConfigAttribute</literal> starts with
|
||||
<literal>RUN_AS_</literal>. If any such <literal>ConfigAttribute</literal> is found, the
|
||||
replacement <literal>RunAsUserToken</literal> will contain the same principal,
|
||||
credentials and granted authorities as the original
|
||||
<interfacename>Authentication</interfacename> object, along with a new
|
||||
<literal>GrantedAuthorityImpl</literal> for each
|
||||
<literal>RUN_AS_</literal> <literal>ConfigAttribute</literal>. Each
|
||||
new <literal>GrantedAuthorityImpl</literal> will be prefixed with
|
||||
<literal>ROLE_</literal>, followed by the <literal>RUN_AS</literal>
|
||||
<literal>ConfigAttribute</literal>. For example, a
|
||||
<literal>GrantedAuthorityImpl</literal> for each <literal>RUN_AS_</literal>
|
||||
<literal>ConfigAttribute</literal>. Each new <literal>GrantedAuthorityImpl</literal>
|
||||
will be prefixed with <literal>ROLE_</literal>, followed by the
|
||||
<literal>RUN_AS</literal> <literal>ConfigAttribute</literal>. For example, a
|
||||
<literal>RUN_AS_SERVER</literal> will result in the replacement
|
||||
<literal>RunAsUserToken</literal> containing a
|
||||
<literal>ROLE_RUN_AS_SERVER</literal> granted authority.</para>
|
||||
<literal>RunAsUserToken</literal> containing a <literal>ROLE_RUN_AS_SERVER</literal>
|
||||
granted authority.</para>
|
||||
|
||||
<para>The replacement <literal>RunAsUserToken</literal> is just like
|
||||
any other <interfacename>Authentication</interfacename> object. It needs to be
|
||||
authenticated by the <interfacename>AuthenticationManager</interfacename>,
|
||||
probably via delegation to a suitable
|
||||
<classname>AuthenticationProvider</classname>. The
|
||||
<literal>RunAsImplAuthenticationProvider</literal> performs such
|
||||
authentication. It simply accepts as valid any
|
||||
<literal>RunAsUserToken</literal> presented.</para>
|
||||
<para>The replacement <literal>RunAsUserToken</literal> is just like any other
|
||||
<interfacename>Authentication</interfacename> object. It needs to be authenticated by
|
||||
the <interfacename>AuthenticationManager</interfacename>, probably via delegation to a
|
||||
suitable <classname>AuthenticationProvider</classname>. The
|
||||
<literal>RunAsImplAuthenticationProvider</literal> performs such authentication. It
|
||||
simply accepts as valid any <literal>RunAsUserToken</literal> presented.</para>
|
||||
|
||||
<para>To ensure malicious code does not create a
|
||||
<literal>RunAsUserToken</literal> and present it for guaranteed
|
||||
acceptance by the <literal>RunAsImplAuthenticationProvider</literal>,
|
||||
the hash of a key is stored in all generated tokens. The
|
||||
<literal>RunAsManagerImpl</literal> and
|
||||
<literal>RunAsImplAuthenticationProvider</literal> is created in the
|
||||
bean context with the same key:
|
||||
<programlisting>
|
||||
<para>To ensure malicious code does not create a <literal>RunAsUserToken</literal> and
|
||||
present it for guaranteed acceptance by the
|
||||
<literal>RunAsImplAuthenticationProvider</literal>, the hash of a key is stored in all
|
||||
generated tokens. The <literal>RunAsManagerImpl</literal> and
|
||||
<literal>RunAsImplAuthenticationProvider</literal> is created in the bean context with
|
||||
the same key: <programlisting>
|
||||
<![CDATA[
|
||||
<bean id="runAsManager"
|
||||
class="org.springframework.security.access.intercept.RunAsManagerImpl">
|
||||
|
@ -97,10 +89,9 @@
|
|||
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
|
||||
<property name="key" value="my_run_as_password"/>
|
||||
</bean>]]></programlisting></para>
|
||||
<para>By using the same key, each <literal>RunAsUserToken</literal>
|
||||
can be validated it was created by an approved
|
||||
<literal>RunAsManagerImpl</literal>. The
|
||||
<literal>RunAsUserToken</literal> is immutable after creation for
|
||||
security reasons</para>
|
||||
<para>By using the same key, each <literal>RunAsUserToken</literal> can be validated it was
|
||||
created by an approved <literal>RunAsManagerImpl</literal>. The
|
||||
<literal>RunAsUserToken</literal> is immutable after creation for security
|
||||
reasons</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -9,23 +9,23 @@
|
|||
files individually from the central Maven repository. We'd recommend the former. You can get
|
||||
the source as described in <link xlink:href="#get-source">the introduction</link> and it's
|
||||
easy to build the project using Maven. There is more information on the project web site at
|
||||
<link xlink:href="http://www.springsource.org/security/">
|
||||
http://www.springsource.org/security/ </link> if you need it. All paths referred to in
|
||||
this chapter are relative to the project source directory. </para>
|
||||
<link xlink:href="http://www.springsource.org/security/">
|
||||
http://www.springsource.org/security/ </link> if you need it. All paths referred to in this
|
||||
chapter are relative to the project source directory. </para>
|
||||
<section xml:id="tutorial-sample">
|
||||
<title>Tutorial Sample</title>
|
||||
<para> The tutorial sample is a nice basic example to get you started. It uses simple
|
||||
namespace configuration throughout. The compiled application is included in the
|
||||
distribution zip file, ready to be deployed into your web container
|
||||
(<filename>spring-security-samples-tutorial-3.0.x.war</filename>). The <link
|
||||
xlink:href="#ns-form-and-basic">form-based</link> authentication mechanism is used
|
||||
in combination with the commonly-used <link xlink:href="#remember-me">remember-me</link>
|
||||
(<filename>spring-security-samples-tutorial-3.0.x.war</filename>). The <link
|
||||
xlink:href="#ns-form-and-basic">form-based</link> authentication mechanism is used in
|
||||
combination with the commonly-used <link xlink:href="#remember-me">remember-me</link>
|
||||
authentication provider to automatically remember the login using cookies.</para>
|
||||
<para>We recommend you start with the tutorial sample, as the XML is minimal and easy to
|
||||
follow. Most importantly, you can easily add this one XML file (and its corresponding
|
||||
<literal>web.xml</literal> entries) to your existing application. Only when this
|
||||
basic integration is achieved do we suggest you attempt adding in method authorization
|
||||
or domain object security.</para>
|
||||
<literal>web.xml</literal> entries) to your existing application. Only when this basic
|
||||
integration is achieved do we suggest you attempt adding in method authorization or
|
||||
domain object security.</para>
|
||||
</section>
|
||||
<section xml:id="contacts-sample">
|
||||
<title>Contacts</title>
|
||||
|
@ -35,11 +35,11 @@
|
|||
administer a simple database of contacts (the domain objects).</para>
|
||||
<para>To deploy, simply copy the WAR file from Spring Security distribution into your
|
||||
container’s <literal>webapps</literal> directory. The war should be called
|
||||
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended
|
||||
version number will vary depending on what release you are using). </para>
|
||||
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended version
|
||||
number will vary depending on what release you are using). </para>
|
||||
<para>After starting your container, check the application can load. Visit
|
||||
<literal>http://localhost:8080/contacts</literal> (or whichever URL is appropriate
|
||||
for your web container and the WAR you deployed). </para>
|
||||
<literal>http://localhost:8080/contacts</literal> (or whichever URL is appropriate for
|
||||
your web container and the WAR you deployed). </para>
|
||||
<para>Next, click "Debug". You will be prompted to authenticate, and a series of usernames
|
||||
and passwords are suggested on that page. Simply authenticate with any of these and view
|
||||
the resulting page. It should contain a success message similar to the following:
|
||||
|
@ -71,8 +71,8 @@ Success! Your web filters appear to be properly configured!
|
|||
<para>Once you successfully receive the above message, return to the sample application's
|
||||
home page and click "Manage". You can then try out the application. Notice that only the
|
||||
contacts available to the currently logged on user are displayed, and only users with
|
||||
<literal>ROLE_SUPERVISOR</literal> are granted access to delete their contacts.
|
||||
Behind the scenes, the <classname>MethodSecurityInterceptor</classname> is securing the
|
||||
<literal>ROLE_SUPERVISOR</literal> are granted access to delete their contacts. Behind
|
||||
the scenes, the <classname>MethodSecurityInterceptor</classname> is securing the
|
||||
business objects. </para>
|
||||
<para>The application allows you to modify the access control lists associated with
|
||||
different contacts. Be sure to give this a try and understand how it works by reviewing
|
||||
|
@ -103,17 +103,17 @@ Success! Your web filters appear to be properly configured!
|
|||
<title>CAS Sample</title>
|
||||
<para> The CAS sample requires that you run both a CAS server and CAS client. It isn't
|
||||
included in the distribution so you should check out the project code as described in
|
||||
<link xlink:href="get-source">the introduction</link>. You'll find the relevant
|
||||
files under the <filename>sample/cas</filename> directory. There's also a
|
||||
<filename>Readme.txt</filename> file in there which explains how to run both the
|
||||
server and the client directly from the source tree, complete with SSL support. You have
|
||||
to download the CAS Server web application (a war file) from the CAS site and drop it
|
||||
into the <filename>samples/cas/server</filename> directory. </para>
|
||||
<link xlink:href="get-source">the introduction</link>. You'll find the relevant files
|
||||
under the <filename>sample/cas</filename> directory. There's also a
|
||||
<filename>Readme.txt</filename> file in there which explains how to run both the server
|
||||
and the client directly from the source tree, complete with SSL support. You have to
|
||||
download the CAS Server web application (a war file) from the CAS site and drop it into
|
||||
the <filename>samples/cas/server</filename> directory. </para>
|
||||
</section>
|
||||
<section xml:id="preauth-sample">
|
||||
<title>Pre-Authentication Sample</title>
|
||||
<para> This sample application demonstrates how to wire up beans from the <link
|
||||
xlink:href="#preauth">pre-authentication</link> framework to make use of login
|
||||
xlink:href="#preauth">pre-authentication</link> framework to make use of login
|
||||
information from a J2EE container. The user name and roles are those setup by the
|
||||
container. </para>
|
||||
<para> The code is in <filename>samples/preauth</filename>. </para>
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Secure Object Implementations</title>
|
||||
</info>
|
||||
<section xml:id="aop-alliance">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
|
||||
<title>Secure Object Implementations</title>
|
||||
</info>
|
||||
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed
|
||||
quite a lot of boiler plate configuration. Now the recommended approach for method security is
|
||||
to use <link xlink:href="#ns-method-security">namespace configuration</link>. This way the
|
||||
method security infrastructure beans are configured automatically for you so you don't really
|
||||
need to know about the implementation classes. We'll just provide a quick overview of the
|
||||
classes that are involved here. </para>
|
||||
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
|
||||
which secures <classname>MethodInvocation</classname>s. Depending on the configuration
|
||||
approach, an interceptor may be specific to a single bean or shared between multiple beans.
|
||||
The interceptor uses a <interfacename>MethodSecurityMetadataSource</interfacename> instance to
|
||||
obtain the configuration attributes that apply to a particular method invocation.
|
||||
<classname>MapBasedMethodSecurityMetadataSource</classname> is used to store configuration
|
||||
attributes keyed by method names (which can be wildcarded) and will be used internally when
|
||||
the attributes are defined in the application context using the
|
||||
<literal><intercept-methods></literal> or <literal><protect-point></literal>
|
||||
elements. Other implementations will be used to handle annotation-based configuration. </para>
|
||||
<section>
|
||||
<title>Explicit MethodSecurityInterceptor Configuration</title>
|
||||
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname> directly
|
||||
in your application context for use with one of Spring AOP's proxying mechanisms: <programlisting><![CDATA[
|
||||
<section xml:id="aop-alliance">
|
||||
<info>
|
||||
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
|
||||
</info>
|
||||
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s
|
||||
needed quite a lot of boiler plate configuration. Now the recommended approach for
|
||||
method security is to use <link xlink:href="#ns-method-security">namespace
|
||||
configuration</link>. This way the method security infrastructure beans are configured
|
||||
automatically for you so you don't really need to know about the implementation classes.
|
||||
We'll just provide a quick overview of the classes that are involved here. </para>
|
||||
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
|
||||
which secures <classname>MethodInvocation</classname>s. Depending on the configuration
|
||||
approach, an interceptor may be specific to a single bean or shared between multiple
|
||||
beans. The interceptor uses a
|
||||
<interfacename>MethodSecurityMetadataSource</interfacename> instance to obtain the
|
||||
configuration attributes that apply to a particular method invocation.
|
||||
<classname>MapBasedMethodSecurityMetadataSource</classname> is used to store
|
||||
configuration attributes keyed by method names (which can be wildcarded) and will be
|
||||
used internally when the attributes are defined in the application context using the
|
||||
<literal><intercept-methods></literal> or <literal><protect-point></literal>
|
||||
elements. Other implementations will be used to handle annotation-based configuration. </para>
|
||||
<section>
|
||||
<title>Explicit MethodSecurityInterceptor Configuration</title>
|
||||
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname>
|
||||
directly in your application context for use with one of Spring AOP's proxying
|
||||
mechanisms: <programlisting><![CDATA[
|
||||
<bean id="bankManagerSecurity" class=
|
||||
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
|
@ -40,26 +42,27 @@
|
|||
</property>
|
||||
</bean> ]]>
|
||||
</programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="aspectj">
|
||||
<info>
|
||||
<title>AspectJ (JoinPoint) Security Interceptor</title>
|
||||
</info>
|
||||
<para>The AspectJ security interceptor is very similar to the AOP Alliance security interceptor
|
||||
discussed in the previous section. Indeed we will only discuss the differences in this
|
||||
section.</para>
|
||||
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike the
|
||||
AOP Alliance security interceptor, which relies on the Spring application context to weave in
|
||||
the security interceptor via proxying, the <literal>AspectJSecurityInterceptor</literal> is
|
||||
weaved in via the AspectJ compiler. It would not be uncommon to use both types of security
|
||||
interceptors in the same application, with <literal>AspectJSecurityInterceptor</literal> being
|
||||
used for domain object instance security and the AOP Alliance
|
||||
<classname>MethodSecurityInterceptor</classname> being used for services layer
|
||||
security.</para>
|
||||
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is configured
|
||||
in the Spring application context:</para>
|
||||
<programlisting><![CDATA[
|
||||
<section xml:id="aspectj">
|
||||
<info>
|
||||
<title>AspectJ (JoinPoint) Security Interceptor</title>
|
||||
</info>
|
||||
<para>The AspectJ security interceptor is very similar to the AOP Alliance security
|
||||
interceptor discussed in the previous section. Indeed we will only discuss the
|
||||
differences in this section.</para>
|
||||
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike
|
||||
the AOP Alliance security interceptor, which relies on the Spring application context to
|
||||
weave in the security interceptor via proxying, the
|
||||
<literal>AspectJSecurityInterceptor</literal> is weaved in via the AspectJ compiler. It
|
||||
would not be uncommon to use both types of security interceptors in the same
|
||||
application, with <literal>AspectJSecurityInterceptor</literal> being used for domain
|
||||
object instance security and the AOP Alliance
|
||||
<classname>MethodSecurityInterceptor</classname> being used for services layer
|
||||
security.</para>
|
||||
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is
|
||||
configured in the Spring application context:</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="bankManagerSecurity" class=
|
||||
"org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
|
@ -72,18 +75,18 @@
|
|||
</value>
|
||||
</property>
|
||||
</bean>]]> </programlisting>
|
||||
<para>As you can see, aside from the class name, the
|
||||
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
|
||||
security interceptor. Indeed the two interceptors can share the same
|
||||
<literal>securityMetadataSource</literal>, as the
|
||||
<interfacename>SecurityMetadataSource</interfacename> works with
|
||||
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class. Of
|
||||
course, your access decisions have access to the relevant AOP library-specific invocation (ie
|
||||
<classname>MethodInvocation</classname> or <literal>JoinPoint</literal>) and as such can
|
||||
consider a range of addition criteria when making access decisions (such as method
|
||||
arguments).</para>
|
||||
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
|
||||
<programlisting language="java">
|
||||
<para>As you can see, aside from the class name, the
|
||||
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
|
||||
security interceptor. Indeed the two interceptors can share the same
|
||||
<literal>securityMetadataSource</literal>, as the
|
||||
<interfacename>SecurityMetadataSource</interfacename> works with
|
||||
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class.
|
||||
Of course, your access decisions have access to the relevant AOP library-specific
|
||||
invocation (ie <classname>MethodInvocation</classname> or <literal>JoinPoint</literal>)
|
||||
and as such can consider a range of addition criteria when making access decisions (such
|
||||
as method arguments).</para>
|
||||
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
|
||||
<programlisting language="java">
|
||||
package org.springframework.security.samples.aspectj;
|
||||
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
|
||||
|
@ -126,25 +129,26 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
|
|||
}
|
||||
}
|
||||
</programlisting>
|
||||
<para>In the above example, the security interceptor will be applied to every instance of
|
||||
<literal>PersistableEntity</literal>, which is an abstract class not shown (you can use any
|
||||
other class or <literal>pointcut</literal> expression you like). For those curious,
|
||||
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
|
||||
statement has special meaning only within an <literal>around()</literal> body. The
|
||||
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
|
||||
<literal>AspectJCallback</literal> class when it wants the target object to continue.</para>
|
||||
<para>You will need to configure Spring to load the aspect and wire it with the
|
||||
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
|
||||
shown below:</para>
|
||||
<programlisting><![CDATA[
|
||||
<para>In the above example, the security interceptor will be applied to every instance of
|
||||
<literal>PersistableEntity</literal>, which is an abstract class not shown (you can use
|
||||
any other class or <literal>pointcut</literal> expression you like). For those curious,
|
||||
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
|
||||
statement has special meaning only within an <literal>around()</literal> body. The
|
||||
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
|
||||
<literal>AspectJCallback</literal> class when it wants the target object to
|
||||
continue.</para>
|
||||
<para>You will need to configure Spring to load the aspect and wire it with the
|
||||
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
|
||||
shown below:</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="domainObjectInstanceSecurityAspect"
|
||||
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
|
||||
factory-method="aspectOf">
|
||||
<property name="securityInterceptor" ref="bankManagerSecurity"/>
|
||||
</bean>]]>
|
||||
</programlisting>
|
||||
<para>That's it! Now you can create your beans from anywhere within your application, using
|
||||
whatever means you think fit (eg <literal>new Person();</literal>) and they will have the
|
||||
security interceptor applied.</para>
|
||||
</section>
|
||||
<para>That's it! Now you can create your beans from anywhere within your application, using
|
||||
whatever means you think fit (eg <literal>new Person();</literal>) and they will have
|
||||
the security interceptor applied.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="security-filter-chain"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>The Security Filter Chain</title>
|
||||
</info>
|
||||
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
|
||||
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so
|
||||
it has no strong links to any particular web technology. It deals in
|
||||
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s and
|
||||
doesn't care whether the requests come from a browser, a web service client, an
|
||||
<classname>HttpInvoker</classname> or an AJAX application. </para>
|
||||
<para> Spring Security maintains a filter chain internally where each of the filters has a
|
||||
particular responsibility and filters are added or removed from the configuration depending on
|
||||
which services are required. The ordering of the filters is important as there are dependencies
|
||||
between them. If you have been using <link xlink:href="#ns-config">namespace
|
||||
configuration</link>, then the filters are automatically configured for you and you don't have
|
||||
to define any Spring beans explicitly but here may be times when you want full control over the
|
||||
security filter chain, either because you are using features which aren't supported in the
|
||||
namespace, or you are using your own customized versions of classes.</para>
|
||||
<section xml:id="delegating-filter-proxy">
|
||||
<title><classname>DelegatingFilterProxy</classname></title>
|
||||
<para> When using servlet filters, you obviously need to declare them in your
|
||||
<filename>web.xml</filename>, or they will be ignored by the servlet container. In Spring
|
||||
Security, the filter classes are also Spring beans defined in the application context and thus
|
||||
able to take advantage of Spring's rich dependency-injection facilities and lifecycle
|
||||
interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides the link between
|
||||
<filename>web.xml</filename> and the application context. </para>
|
||||
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like this
|
||||
in the <filename>web.xml</filename> file: <programlisting><![CDATA[
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>The Security Filter Chain</title>
|
||||
</info>
|
||||
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
|
||||
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally,
|
||||
so it has no strong links to any particular web technology. It deals in
|
||||
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
|
||||
and doesn't care whether the requests come from a browser, a web service client, an
|
||||
<classname>HttpInvoker</classname> or an AJAX application. </para>
|
||||
<para> Spring Security maintains a filter chain internally where each of the filters has a
|
||||
particular responsibility and filters are added or removed from the configuration depending
|
||||
on which services are required. The ordering of the filters is important as there are
|
||||
dependencies between them. If you have been using <link xlink:href="#ns-config">namespace
|
||||
configuration</link>, then the filters are automatically configured for you and you don't
|
||||
have to define any Spring beans explicitly but here may be times when you want full control
|
||||
over the security filter chain, either because you are using features which aren't supported
|
||||
in the namespace, or you are using your own customized versions of classes.</para>
|
||||
<section xml:id="delegating-filter-proxy">
|
||||
<title><classname>DelegatingFilterProxy</classname></title>
|
||||
<para> When using servlet filters, you obviously need to declare them in your
|
||||
<filename>web.xml</filename>, or they will be ignored by the servlet container. In
|
||||
Spring Security, the filter classes are also Spring beans defined in the application
|
||||
context and thus able to take advantage of Spring's rich dependency-injection facilities
|
||||
and lifecycle interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides
|
||||
the link between <filename>web.xml</filename> and the application context. </para>
|
||||
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like
|
||||
this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
|
||||
<filter>
|
||||
<filter-name>myFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
|
@ -37,29 +37,29 @@
|
|||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>]]>
|
||||
</programlisting> Notice that the filter is actually a
|
||||
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement the
|
||||
logic of the filter. What <classname>DelegatingFilterProxy</classname> does is delegate the
|
||||
<interfacename>Filter</interfacename>'s methods through to a bean which is obtained from the
|
||||
Spring application context. This enables the bean to benefit from the Spring web application
|
||||
context lifecycle support and configuration flexibility. The bean must implement
|
||||
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that
|
||||
in the <literal>filter-name</literal> element. Read the Javadoc for
|
||||
<classname>DelegatingFilterProxy</classname> for more information</para>
|
||||
</section>
|
||||
<section xml:id="filter-chain-proxy">
|
||||
<title><classname>FilterChainProxy</classname></title>
|
||||
<para> It should now be clear that you can declare each Spring Security filter bean that you
|
||||
require in your application context file and add a corresponding
|
||||
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for each
|
||||
filter, making sure that they are ordered correctly. This is a cumbersome approach and
|
||||
clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We
|
||||
would prefer to just add a single entry to <filename>web.xml</filename> and deal entirely with
|
||||
the application context file for managing our web security beans. This is where Spring
|
||||
Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a
|
||||
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with the
|
||||
<literal>filter-name</literal> set to the bean name <quote>filterChainProxy</quote>. The
|
||||
filter chain is then declared in the application context with the same bean name. Here's an
|
||||
example: <programlisting language="xml"><![CDATA[
|
||||
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement
|
||||
the logic of the filter. What <classname>DelegatingFilterProxy</classname> does is
|
||||
delegate the <interfacename>Filter</interfacename>'s methods through to a bean which is
|
||||
obtained from the Spring application context. This enables the bean to benefit from the
|
||||
Spring web application context lifecycle support and configuration flexibility. The bean
|
||||
must implement <interfacename>javax.servlet.Filter</interfacename> and it must have the
|
||||
same name as that in the <literal>filter-name</literal> element. Read the Javadoc for
|
||||
<classname>DelegatingFilterProxy</classname> for more information</para>
|
||||
</section>
|
||||
<section xml:id="filter-chain-proxy">
|
||||
<title><classname>FilterChainProxy</classname></title>
|
||||
<para> It should now be clear that you can declare each Spring Security filter bean that you
|
||||
require in your application context file and add a corresponding
|
||||
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for
|
||||
each filter, making sure that they are ordered correctly. This is a cumbersome approach
|
||||
and clutters up the <filename>web.xml</filename> file quickly if we have a lot of
|
||||
filters. We would prefer to just add a single entry to <filename>web.xml</filename> and
|
||||
deal entirely with the application context file for managing our web security beans.
|
||||
This is where Spring Secuirity's <classname>FilterChainProxy</classname> comes in. It is
|
||||
wired using a <literal>DelegatingFilterProxy</literal>, just like in the example above,
|
||||
but with the <literal>filter-name</literal> set to the bean name
|
||||
<quote>filterChainProxy</quote>. The filter chain is then declared in the application
|
||||
context with the same bean name. Here's an example: <programlisting language="xml"><![CDATA[
|
||||
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/webServices/**" filters="
|
||||
|
@ -75,106 +75,116 @@
|
|||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
]]>
|
||||
</programlisting> The namespace element <literal>filter-chain-map</literal> is used
|
||||
to set up the security filter chain(s) which are required within the
|
||||
application<footnote><para>Note that you'll need to include the security namespace in your
|
||||
application context XML file in order to use this syntax.</para></footnote>. It maps a
|
||||
particular URL pattern to a chain of filters built up from the bean names specified in the
|
||||
<literal>filters</literal> element. Both regular expressions and Ant Paths are supported,
|
||||
and the most specific URIs appear first. At runtime the
|
||||
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches the
|
||||
current web request and the list of filter beans specified by the <literal>filters</literal>
|
||||
attribute will be applied to that request. The filters will be invoked in the order they are
|
||||
defined, so you have complete control over the filter chain which is applied to a particular
|
||||
URL.</para>
|
||||
<para>You may have noticed we have declared two
|
||||
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
|
||||
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property of
|
||||
<classname>SecurityContextPersistenceFilter</classname>). As web services will never present
|
||||
a <literal>jsessionid</literal> on future requests, creating <literal>HttpSession</literal>s
|
||||
for such user agents would be wasteful. If you had a high-volume application which required
|
||||
maximum scalability, we recommend you use the approach shown above. For smaller applications,
|
||||
using a single <classname>SecurityContextPersistenceFilter</classname> (with its default
|
||||
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
|
||||
sufficient.</para>
|
||||
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will always
|
||||
delegate <methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
|
||||
methods through to the underlaying <interfacename>Filter</interfacename>s if such methods are
|
||||
called against <classname>FilterChainProxy</classname> itself. In this case,
|
||||
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy each
|
||||
<literal>Filter</literal> bean once, no matter how many times it is declared in the filter
|
||||
chain(s). You control the overall choice as to whether these methods are called or not via the
|
||||
<literal>targetFilterLifecycle</literal> initialization parameter of
|
||||
<literal>DelegatingFilterProxy</literal>. By default this property is
|
||||
<literal>false</literal> and servlet container lifecycle invocations are not delegated
|
||||
through <literal>DelegatingFilterProxy</literal>.</para>
|
||||
<para> When we looked at how to set up web security using <link xlink:href="#ns-web-xml"
|
||||
>namespace configuration</link>, we used a <literal>DelegatingFilterProxy</literal> with the
|
||||
name <quote>springSecurityFilterChain</quote>. You should now be able to see that this is the
|
||||
name of the <classname>FilterChainProxy</classname> which is created by the namespace. </para>
|
||||
<section>
|
||||
<title>Bypassing the Filter Chain</title>
|
||||
<para> As with the namespace, you can use the attribute <literal>filters = "none"</literal> as
|
||||
an alternative to supplying a filter bean list. This will omit the request pattern from the
|
||||
security filter chain entirely. Note that anything matching this path will then have no
|
||||
authentication or authorization services applied and will be freely accessible. If you want
|
||||
to make use of the contents of the <classname>SecurityContext</classname> contents during a
|
||||
request, then it must have passed through the security filter chain. Otherwise the
|
||||
<classname>SecurityContextHolder</classname> will not have been populated and the contents
|
||||
will be null.</para>
|
||||
</programlisting> The namespace element <literal>filter-chain-map</literal> is used to set
|
||||
up the security filter chain(s) which are required within the application<footnote>
|
||||
<para>Note that you'll need to include the security namespace in your application
|
||||
context XML file in order to use this syntax.</para>
|
||||
</footnote>. It maps a particular URL pattern to a chain of filters built up from the
|
||||
bean names specified in the <literal>filters</literal> element. Both regular expressions
|
||||
and Ant Paths are supported, and the most specific URIs appear first. At runtime the
|
||||
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches
|
||||
the current web request and the list of filter beans specified by the
|
||||
<literal>filters</literal> attribute will be applied to that request. The filters will
|
||||
be invoked in the order they are defined, so you have complete control over the filter
|
||||
chain which is applied to a particular URL.</para>
|
||||
<para>You may have noticed we have declared two
|
||||
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
|
||||
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property
|
||||
of <classname>SecurityContextPersistenceFilter</classname>). As web services will never
|
||||
present a <literal>jsessionid</literal> on future requests, creating
|
||||
<literal>HttpSession</literal>s for such user agents would be wasteful. If you had a
|
||||
high-volume application which required maximum scalability, we recommend you use the
|
||||
approach shown above. For smaller applications, using a single
|
||||
<classname>SecurityContextPersistenceFilter</classname> (with its default
|
||||
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
|
||||
sufficient.</para>
|
||||
<para> When we looked at how to set up web security using <link xlink:href="#ns-web-xml"
|
||||
>namespace configuration</link>, we used a <literal>DelegatingFilterProxy</literal> with
|
||||
the name <quote>springSecurityFilterChain</quote>. You should now be able to see that
|
||||
this is the name of the <classname>FilterChainProxy</classname> which is created by the
|
||||
namespace. </para>
|
||||
<section>
|
||||
<title>Bypassing the Filter Chain</title>
|
||||
<para> As with the namespace, you can use the attribute <literal>filters =
|
||||
"none"</literal> as an alternative to supplying a filter bean list. This will omit
|
||||
the request pattern from the security filter chain entirely. Note that anything
|
||||
matching this path will then have no authentication or authorization services
|
||||
applied and will be freely accessible. If you want to make use of the contents of
|
||||
the <classname>SecurityContext</classname> contents during a request, then it must
|
||||
have passed through the security filter chain. Otherwise the
|
||||
<classname>SecurityContextHolder</classname> will not have been populated and the
|
||||
contents will be null.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Filter Ordering</title>
|
||||
<para>The order that filters are defined in the chain is very important. Irrespective of which
|
||||
filters you are actually using, the order should be as follows:
|
||||
<orderedlist><listitem><para><classname>ChannelProcessingFilter</classname>, because
|
||||
it might need to redirect to a different
|
||||
protocol</para></listitem><listitem><para><classname>ConcurrentSessionFilter</classname>,
|
||||
because it doesn't use any <classname>SecurityContextHolder</classname> functionality
|
||||
but needs to update the <interfacename>SessionRegistry</interfacename> to reflect
|
||||
ongoing requests from the
|
||||
principal</para></listitem><listitem><para><classname>SecurityContextPersistenceFilter</classname>,
|
||||
so a <interfacename>SecurityContext</interfacename> can be set up in the
|
||||
<classname>SecurityContextHolder</classname> at the beginning of a web request, and
|
||||
any changes to the <interfacename>SecurityContext</interfacename> can be copied to the
|
||||
<literal>HttpSession</literal> when the web request ends (ready for use with the next
|
||||
web request)</para></listitem><listitem><para>Authentication processing mechanisms -
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname>,
|
||||
<classname>CasAuthenticationFilter</classname>,
|
||||
<classname>BasicAuthenticationFilter</classname> etc - so that the
|
||||
<classname>SecurityContextHolder</classname> can be modified to contain a valid
|
||||
<interfacename>Authentication</interfacename> request
|
||||
token</para></listitem><listitem><para>The
|
||||
<literal>SecurityContextHolderAwareRequestFilter</literal>, if you are using it to
|
||||
install a Spring Security aware <literal>HttpServletRequestWrapper</literal> into your
|
||||
servlet
|
||||
container</para></listitem><listitem><para><classname>RememberMeAuthenticationFilter</classname>,
|
||||
so that if no earlier authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, and the request presents a cookie that
|
||||
enables remember-me services to take place, a suitable remembered
|
||||
<interfacename>Authentication</interfacename> object will be put
|
||||
there</para></listitem><listitem><para><classname>AnonymousAuthenticationFilter</classname>,
|
||||
so that if no earlier authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, an anonymous
|
||||
<interfacename>Authentication</interfacename> object will be put
|
||||
there</para></listitem><listitem><para><classname>ExceptionTranslationFilter</classname>,
|
||||
to catch any Spring Security exceptions so that either an HTTP error response can be
|
||||
returned or an appropriate <interfacename>AuthenticationEntryPoint</interfacename> can
|
||||
be
|
||||
launched</para></listitem><listitem><para><classname>FilterSecurityInterceptor</classname>,
|
||||
to protect web URIs and raise exceptions when access is
|
||||
denied</para></listitem></orderedlist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Use with other Filter-Based Frameworks</title>
|
||||
<para>If you're using some other framework that is also filter-based, then you need to make sure
|
||||
that the Spring Security filters come first. This enables the
|
||||
<classname>SecurityContextHolder</classname> to be populated in time for use by the other
|
||||
filters. Examples are the use of SiteMesh to decorate your web pages or a web framework like
|
||||
Wicket which uses a filter to handle its requests. </para>
|
||||
</section>
|
||||
<!--
|
||||
<section>
|
||||
<title>Filter Ordering</title>
|
||||
<para>The order that filters are defined in the chain is very important. Irrespective of
|
||||
which filters you are actually using, the order should be as follows: <orderedlist>
|
||||
<listitem>
|
||||
<para><classname>ChannelProcessingFilter</classname>, because it might need to
|
||||
redirect to a different protocol</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
|
||||
<classname>SecurityContextHolder</classname> functionality but needs to update
|
||||
the <interfacename>SessionRegistry</interfacename> to reflect ongoing requests
|
||||
from the principal</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>SecurityContextPersistenceFilter</classname>, so a
|
||||
<interfacename>SecurityContext</interfacename> can be set up in the
|
||||
<classname>SecurityContextHolder</classname> at the beginning of a web request,
|
||||
and any changes to the <interfacename>SecurityContext</interfacename> can be
|
||||
copied to the <literal>HttpSession</literal> when the web request ends (ready
|
||||
for use with the next web request)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Authentication processing mechanisms -
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname>,
|
||||
<classname>CasAuthenticationFilter</classname>,
|
||||
<classname>BasicAuthenticationFilter</classname> etc - so that the
|
||||
<classname>SecurityContextHolder</classname> can be modified to contain a valid
|
||||
<interfacename>Authentication</interfacename> request token</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <literal>SecurityContextHolderAwareRequestFilter</literal>, if you are
|
||||
using it to install a Spring Security aware
|
||||
<literal>HttpServletRequestWrapper</literal> into your servlet container</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>RememberMeAuthenticationFilter</classname>, so that if no earlier
|
||||
authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, and the request presents a cookie
|
||||
that enables remember-me services to take place, a suitable remembered
|
||||
<interfacename>Authentication</interfacename> object will be put there</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>AnonymousAuthenticationFilter</classname>, so that if no earlier
|
||||
authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, an anonymous
|
||||
<interfacename>Authentication</interfacename> object will be put there</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring
|
||||
Security exceptions so that either an HTTP error response can be returned or an
|
||||
appropriate <interfacename>AuthenticationEntryPoint</interfacename> can be
|
||||
launched</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and
|
||||
raise exceptions when access is denied</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Use with other Filter-Based Frameworks</title>
|
||||
<para>If you're using some other framework that is also filter-based, then you need to make
|
||||
sure that the Spring Security filters come first. This enables the
|
||||
<classname>SecurityContextHolder</classname> to be populated in time for use by the
|
||||
other filters. Examples are the use of SiteMesh to decorate your web pages or a web
|
||||
framework like Wicket which uses a filter to handle its requests. </para>
|
||||
</section>
|
||||
<!--
|
||||
<section xml:id="taglib">
|
||||
<info>
|
||||
<title>Tag Libraries</title>
|
||||
|
|
|
@ -1,43 +1,46 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="session-mgmt"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Session Management</title>
|
||||
</info>
|
||||
<para>HTTP session related functonality is handled by a combination of the
|
||||
<classname>SessionManagementFilter</classname> and the
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename> interface, which the filter
|
||||
delegates to. Typical usage includes session-fixation protection attack prevention, detection of
|
||||
session timeouts and restrictions on how many sessions an authenticated user may have open
|
||||
concurrently.</para>
|
||||
<section>
|
||||
<title>SessionManagementFilter</title>
|
||||
<para>The <classname>SessionManagementFilter</classname> checks the contents of the
|
||||
<interfacename>SecurityContextRepository</interfacename> against the current contents of the
|
||||
<classname>SecurityContextHolder</classname> to determine whether a user has been
|
||||
authenticated during the current request, typically by a non-interactive authentication
|
||||
mechanism, such as pre-authentication or remember-me <footnote><para>Authentication by
|
||||
mechanisms which perform a redirect after authenticating (such as form-login) will not be
|
||||
detected by <classname>SessionManagementFilter</classname>, as the filter will not be
|
||||
invoked during the authenticating request. Session-management functionality has to be
|
||||
handled separately in these cases. </para></footnote>. If the repository contains a
|
||||
security context, the filter does nothing. If it doesn't, and the thread-local
|
||||
<interfacename>SecurityContext</interfacename> contains a (non-anonymous)
|
||||
<interfacename>Authentication</interfacename> object, the filter assumes they have been
|
||||
authenticated by a previous filter in the stack. It will then invoke the configured
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename>.</para>
|
||||
<para>If the user is not currently authenticated, the filter will check whether an invalid
|
||||
session ID has been requested (because of a timeout, for example) and will redirect to the
|
||||
configured <literal>invalidSessionUrl</literal> if set. The easiest way to configure this is
|
||||
through the namespace, <link xlink:href="#ns-session-mgmt">as described earlier</link>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title><interfacename>SessionAuthenticationStrategy</interfacename></title>
|
||||
<para>
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename> is used by both
|
||||
<classname>SessionManagementFilter</classname> and
|
||||
<classname>AbstractAuthenticationProcessingFilter</classname>, so if you are using a
|
||||
customized form-login class, for example, you will need to inject it into both of these. In
|
||||
this case, a typical configuration, combining the namespace and custom beans might look like this:<programlisting><![CDATA[
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Session Management</title>
|
||||
</info>
|
||||
<para>HTTP session related functonality is handled by a combination of the
|
||||
<classname>SessionManagementFilter</classname> and the
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename> interface, which the filter
|
||||
delegates to. Typical usage includes session-fixation protection attack prevention,
|
||||
detection of session timeouts and restrictions on how many sessions an authenticated user
|
||||
may have open concurrently.</para>
|
||||
<section>
|
||||
<title>SessionManagementFilter</title>
|
||||
<para>The <classname>SessionManagementFilter</classname> checks the contents of the
|
||||
<interfacename>SecurityContextRepository</interfacename> against the current contents of
|
||||
the <classname>SecurityContextHolder</classname> to determine whether a user has been
|
||||
authenticated during the current request, typically by a non-interactive authentication
|
||||
mechanism, such as pre-authentication or remember-me <footnote>
|
||||
<para>Authentication by mechanisms which perform a redirect after authenticating (such
|
||||
as form-login) will not be detected by
|
||||
<classname>SessionManagementFilter</classname>, as the filter will not be invoked
|
||||
during the authenticating request. Session-management functionality has to be
|
||||
handled separately in these cases. </para>
|
||||
</footnote>. If the repository contains a security context, the filter does nothing. If
|
||||
it doesn't, and the thread-local <interfacename>SecurityContext</interfacename> contains
|
||||
a (non-anonymous) <interfacename>Authentication</interfacename> object, the filter
|
||||
assumes they have been authenticated by a previous filter in the stack. It will then
|
||||
invoke the configured
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename>.</para>
|
||||
<para>If the user is not currently authenticated, the filter will check whether an invalid
|
||||
session ID has been requested (because of a timeout, for example) and will redirect to
|
||||
the configured <literal>invalidSessionUrl</literal> if set. The easiest way to configure
|
||||
this is through the namespace, <link xlink:href="#ns-session-mgmt">as described
|
||||
earlier</link>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title><interfacename>SessionAuthenticationStrategy</interfacename></title>
|
||||
<para> <interfacename>SessionAuthenticationStrategy</interfacename> is used by both
|
||||
<classname>SessionManagementFilter</classname> and
|
||||
<classname>AbstractAuthenticationProcessingFilter</classname>, so if you are using a
|
||||
customized form-login class, for example, you will need to inject it into both of these.
|
||||
In this case, a typical configuration, combining the namespace and custom beans might
|
||||
look like this:<programlisting><![CDATA[
|
||||
<http>
|
||||
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
|
||||
<session-management session-authentication-strategy-ref="sas"/>
|
||||
|
@ -56,46 +59,51 @@
|
|||
</beans:bean>
|
||||
]]>
|
||||
</programlisting></para>
|
||||
</section>
|
||||
<section xml:id="concurrent-sessions">
|
||||
<title>Concurrency Control</title>
|
||||
<para>Spring Security is able to prevent a principal from concurrently authenticating to the
|
||||
same application more than a specified number of times. Many ISVs take advantage of this to
|
||||
enforce licensing, whilst network administrators like this feature because it helps prevent
|
||||
people from sharing login names. You can, for example, stop user <quote>Batman</quote> from
|
||||
logging onto the web application from two different sessions. You can either expire their
|
||||
previous login or you can report an error when they try to log in again, preventing the second
|
||||
login. Note that if you are using the second approach, a user who has not explicitly logged
|
||||
out (but who has just closed their browser, for example) will not be able to log in again
|
||||
until their original session expires.</para>
|
||||
<para>Concurrency control is supported by the namespace, so please check the earlier namespace
|
||||
chapter for the simplest configuration. Sometimes you need to customize things though. </para>
|
||||
<para>The implementation uses a specialized version of
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename>, called
|
||||
<classname>ConcurrentSessionControlStrategy</classname>. <note><para>Previously the
|
||||
concurrent authentication check was made by the <classname>ProviderManager</classname>,
|
||||
which could be injected with a <literal>ConcurrentSessionController</literal>. The latter
|
||||
would check if the user was attempting to exceed the number of permitted sessions.
|
||||
However, this approach required that an HTTP session be created in advance, which is
|
||||
undesirable. In Spring Security 3, the user is first authenticated by the
|
||||
<interfacename>AuthenticationManager</interfacename> and once they are successfully
|
||||
authenticated, a session is created and the check is made whether they are allowed to have
|
||||
another session open.</para></note></para>
|
||||
<para>To use concurrent session support, you'll need to add the following to
|
||||
<literal>web.xml</literal>: <programlisting><![CDATA[
|
||||
</section>
|
||||
<section xml:id="concurrent-sessions">
|
||||
<title>Concurrency Control</title>
|
||||
<para>Spring Security is able to prevent a principal from concurrently authenticating to the
|
||||
same application more than a specified number of times. Many ISVs take advantage of this
|
||||
to enforce licensing, whilst network administrators like this feature because it helps
|
||||
prevent people from sharing login names. You can, for example, stop user
|
||||
<quote>Batman</quote> from logging onto the web application from two different sessions.
|
||||
You can either expire their previous login or you can report an error when they try to
|
||||
log in again, preventing the second login. Note that if you are using the second
|
||||
approach, a user who has not explicitly logged out (but who has just closed their
|
||||
browser, for example) will not be able to log in again until their original session
|
||||
expires.</para>
|
||||
<para>Concurrency control is supported by the namespace, so please check the earlier
|
||||
namespace chapter for the simplest configuration. Sometimes you need to customize things
|
||||
though. </para>
|
||||
<para>The implementation uses a specialized version of
|
||||
<interfacename>SessionAuthenticationStrategy</interfacename>, called
|
||||
<classname>ConcurrentSessionControlStrategy</classname>. <note>
|
||||
<para>Previously the concurrent authentication check was made by the
|
||||
<classname>ProviderManager</classname>, which could be injected with a
|
||||
<literal>ConcurrentSessionController</literal>. The latter would check if the user
|
||||
was attempting to exceed the number of permitted sessions. However, this approach
|
||||
required that an HTTP session be created in advance, which is undesirable. In Spring
|
||||
Security 3, the user is first authenticated by the
|
||||
<interfacename>AuthenticationManager</interfacename> and once they are successfully
|
||||
authenticated, a session is created and the check is made whether they are allowed
|
||||
to have another session open.</para>
|
||||
</note></para>
|
||||
<para>To use concurrent session support, you'll need to add the following to
|
||||
<literal>web.xml</literal>: <programlisting><![CDATA[
|
||||
<listener>
|
||||
<listener-class>
|
||||
org.springframework.security.web.session.HttpSessionEventPublisher
|
||||
</listener-class>
|
||||
</listener> ]]>
|
||||
</programlisting></para>
|
||||
<para>In addition, you will need to add the <literal>ConcurrentSessionFilter</literal> to your
|
||||
<classname>FilterChainProxy</classname>. The <classname>ConcurrentSessionFilter</classname>
|
||||
requires two properties, <literal>sessionRegistry</literal>, which generally points to an
|
||||
instance of <classname>SessionRegistryImpl</classname>, and <literal>expiredUrl</literal>, which
|
||||
points to the page to display when a session has expired. A configuration using the namespace
|
||||
to create the <classname>FilterChainProxy</classname> and other default beans might look like
|
||||
this: <programlisting><![CDATA[
|
||||
<para>In addition, you will need to add the <literal>ConcurrentSessionFilter</literal> to
|
||||
your <classname>FilterChainProxy</classname>. The
|
||||
<classname>ConcurrentSessionFilter</classname> requires two properties,
|
||||
<literal>sessionRegistry</literal>, which generally points to an instance of
|
||||
<classname>SessionRegistryImpl</classname>, and <literal>expiredUrl</literal>, which
|
||||
points to the page to display when a session has expired. A configuration using the
|
||||
namespace to create the <classname>FilterChainProxy</classname> and other default beans
|
||||
might look like this: <programlisting><![CDATA[
|
||||
<http>
|
||||
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
|
||||
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
|
||||
|
@ -125,12 +133,12 @@
|
|||
class="org.springframework.security.core.session.SessionRegistryImpl" />
|
||||
]]>
|
||||
</programlisting></para>
|
||||
<para>Adding the listener to <filename>web.xml</filename> causes an
|
||||
<literal>ApplicationEvent</literal> to be published to the Spring
|
||||
<literal>ApplicationContext</literal> every time a <literal>HttpSession</literal> commences
|
||||
or terminates. This is critical, as it allows the <classname>SessionRegistryImpl</classname>
|
||||
to be notified when a session ends. Without it, a user will never be able to log back in again
|
||||
once they have exceeded their session allowance, even if they log out of another session or it
|
||||
times out.</para>
|
||||
</section>
|
||||
<para>Adding the listener to <filename>web.xml</filename> causes an
|
||||
<literal>ApplicationEvent</literal> to be published to the Spring
|
||||
<literal>ApplicationContext</literal> every time a <literal>HttpSession</literal>
|
||||
commences or terminates. This is critical, as it allows the
|
||||
<classname>SessionRegistryImpl</classname> to be notified when a session ends. Without
|
||||
it, a user will never be able to log back in again once they have exceeded their session
|
||||
allowance, even if they log out of another session or it times out.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -1,126 +1,136 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<book version="5.0" xml:id="spring-security-reference-guide" xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<info><title>Spring Security</title><subtitle>Reference Documentation</subtitle><authorgroup>
|
||||
<author>
|
||||
<personname>Ben Alex</personname>
|
||||
</author>
|
||||
<author>
|
||||
<personname>Luke Taylor</personname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<productname>Spring Security</productname>
|
||||
<releaseinfo>3.0.2.RELEASE</releaseinfo>
|
||||
</info>
|
||||
<toc/>
|
||||
<preface xml:id="preface">
|
||||
<title>Preface</title>
|
||||
<para>Spring Security provides a comprehensive security solution for J2EE-based enterprise
|
||||
software applications. As you will discover as you venture through this reference guide, we
|
||||
have tried to provide you a useful and highly configurable security system.</para>
|
||||
<para>Security is an ever-moving target, and it's important to pursue a comprehensive,
|
||||
system-wide approach. In security circles we encourage you to adopt "layers of security", so
|
||||
that each layer tries to be as secure as possible in its own right, with successive layers
|
||||
providing additional security. The "tighter" the security of each layer, the more robust and
|
||||
safe your application will be. At the bottom level you'll need to deal with issues such as
|
||||
transport security and system identification, in order to mitigate man-in-the-middle attacks.
|
||||
Next you'll generally utilise firewalls, perhaps with VPNs or IP security to ensure only
|
||||
authorised systems can attempt to connect. In corporate environments you may deploy a DMZ to
|
||||
separate public-facing servers from backend database and application servers. Your operating
|
||||
system will also play a critical part, addressing issues such as running processes as
|
||||
non-privileged users and maximising file system security. An operating system will usually
|
||||
also be configured with its own firewall. Hopefully somewhere along the way you'll be trying
|
||||
to prevent denial of service and brute force attacks against the system. An intrusion
|
||||
detection system will also be especially useful for monitoring and responding to attacks, with
|
||||
such systems able to take protective action such as blocking offending TCP/IP addresses in
|
||||
real-time. Moving to the higher layers, your Java Virtual Machine will hopefully be configured
|
||||
to minimize the permissions granted to different Java types, and then your application will
|
||||
add its own problem domain-specific security configuration. Spring Security makes this latter
|
||||
area - application security - much easier. </para>
|
||||
<para>Of course, you will need to properly address all security layers mentioned above, together
|
||||
with managerial factors that encompass every layer. A non-exhaustive list of such managerial
|
||||
factors would include security bulletin monitoring, patching, personnel vetting, audits,
|
||||
change control, engineering management systems, data backup, disaster recovery, performance
|
||||
benchmarking, load monitoring, centralised logging, incident response procedures etc.</para>
|
||||
<para>With Spring Security being focused on helping you with the enterprise application security
|
||||
layer, you will find that there are as many different requirements as there are business
|
||||
problem domains. A banking application has different needs from an ecommerce application. An
|
||||
ecommerce application has different needs from a corporate sales force automation tool. These
|
||||
custom requirements make application security interesting, challenging and rewarding. </para>
|
||||
<para>Please read <xref linkend="getting-started"/>, in its entirety to begin with. This will
|
||||
introduce you to the framework and the namespace-based configuration system with which you can
|
||||
get up and running quite quickly. To get more of an understanding of how Spring Security
|
||||
works, and some of the classes you might need to use, you should then read <xref
|
||||
linkend="overall-architecture"/>. The remaining parts of this guide are structured in a more
|
||||
traditional reference style, designed to be read on an as-required basis. We'd also recommend
|
||||
that you read up as much as possible on application security issues in general. Spring
|
||||
Security is not a panacea which will solve all security issues. It is important that the
|
||||
application is designed with security in mind from the start. Attempting to retrofit it is not
|
||||
a good idea. In particular, if you are building a web application, you should be aware of the
|
||||
many potential vulnerabilities such as cross-site scripting, request-forgery and
|
||||
session-hijacking which you should be taking into account from the start. The OWASP web site
|
||||
(http://www.owasp.org/) maintains a top ten list of web application vulnerabilities as well as
|
||||
a lot of useful reference information. </para>
|
||||
<para>We hope that you find this reference guide useful, and we welcome your feedback and <link
|
||||
xlink:href="#jira">suggestions</link>. </para>
|
||||
<para>Finally, welcome to the Spring Security <link xlink:href="#community">community</link>.
|
||||
</para>
|
||||
</preface>
|
||||
<part xml:id="getting-started">
|
||||
<title>Getting Started</title>
|
||||
<partintro>
|
||||
<para>The later parts of this guide provide an in-depth discussion of the framework
|
||||
architecture and implementation classes, which you need to understand if you want to do any
|
||||
serious customization. In this part, we'll introduce Spring Security 3.0, give a brief
|
||||
overview of the project's history and take a slightly gentler look at how to get started
|
||||
using the framework. In particular, we'll look at namespace configuration which provides a
|
||||
much simpler way of securing your application compared to the traditional Spring bean
|
||||
approach where you have to wire up all the implementation classes individually. </para>
|
||||
<para> We'll also take a look at the sample applications that are available. It's worth trying
|
||||
to run these and experimenting with them a bit even before you read the later sections - you
|
||||
can dip back into them as your understanding of the framework increases. Please also check
|
||||
out the <link xlink:href="http://static.springsource.org/spring-security/site/index.html"
|
||||
>project website</link> as it has useful information on building the project, plus links
|
||||
to articles, videos and tutorials. </para>
|
||||
</partintro>
|
||||
<xi:include href="introduction.xml"/>
|
||||
<xi:include href="namespace-config.xml"/>
|
||||
<xi:include href="samples.xml"/>
|
||||
<xi:include href="community.xml"/>
|
||||
</part>
|
||||
<part xml:id="overall-architecture">
|
||||
<title>Architecture and Implementation</title>
|
||||
<partintro>
|
||||
<para>Once you are familiar with setting up and running some namespace-configuration based
|
||||
applications, you may wish to develop more of an understanding of how the framework actually
|
||||
works behind the namespace facade. Like most software, Spring Security has certain central
|
||||
interfaces, classes and conceptual abstractions that are commonly used throughout the
|
||||
framework. In this part of the reference guide we will look at some of these and see how
|
||||
they work together to support authentication and access-control within Spring
|
||||
Security.</para>
|
||||
</partintro>
|
||||
<xi:include href="technical-overview.xml"/>
|
||||
<xi:include href="core-services.xml"/>
|
||||
</part>
|
||||
<part xml:id="web-app-security">
|
||||
<title>Web Application Security</title>
|
||||
<partintro>
|
||||
<para> Most Spring Security users will be using the framework in applications which make user
|
||||
of HTTP and the Servlet API. In this part, we'll take a look at how Spring Security provides
|
||||
authentication and access-control features for the web layer of an application. We'll look
|
||||
behind the facade of the namespace and see which classes and interfaces are actually
|
||||
assembled to provide web-layer security. In some situations it is necessary to use
|
||||
traditional bean configuration to provide full control over the configuration, so we'll also
|
||||
see how to configure these classes directly without the namespace.</para>
|
||||
</partintro>
|
||||
<xi:include href="security-filter-chain.xml"/>
|
||||
<xi:include href="core-filters.xml"/>
|
||||
<xi:include href="basic-and-digest-auth.xml"/>
|
||||
<xi:include href="remember-me-authentication.xml"/>
|
||||
<xi:include href="session-mgmt.xml"/>
|
||||
<xi:include href="anon-auth-provider.xml"/>
|
||||
</part>
|
||||
<!--
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<info>
|
||||
<title>Spring Security</title>
|
||||
<subtitle>Reference Documentation</subtitle>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<personname>Ben Alex</personname>
|
||||
</author>
|
||||
<author>
|
||||
<personname>Luke Taylor</personname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<productname>Spring Security</productname>
|
||||
<releaseinfo>3.0.2.RELEASE</releaseinfo>
|
||||
</info>
|
||||
<toc/>
|
||||
<preface xml:id="preface">
|
||||
<title>Preface</title>
|
||||
<para>Spring Security provides a comprehensive security solution for J2EE-based enterprise
|
||||
software applications. As you will discover as you venture through this reference guide,
|
||||
we have tried to provide you a useful and highly configurable security system.</para>
|
||||
<para>Security is an ever-moving target, and it's important to pursue a comprehensive,
|
||||
system-wide approach. In security circles we encourage you to adopt "layers of
|
||||
security", so that each layer tries to be as secure as possible in its own right, with
|
||||
successive layers providing additional security. The "tighter" the security of each
|
||||
layer, the more robust and safe your application will be. At the bottom level you'll
|
||||
need to deal with issues such as transport security and system identification, in order
|
||||
to mitigate man-in-the-middle attacks. Next you'll generally utilise firewalls, perhaps
|
||||
with VPNs or IP security to ensure only authorised systems can attempt to connect. In
|
||||
corporate environments you may deploy a DMZ to separate public-facing servers from
|
||||
backend database and application servers. Your operating system will also play a
|
||||
critical part, addressing issues such as running processes as non-privileged users and
|
||||
maximising file system security. An operating system will usually also be configured
|
||||
with its own firewall. Hopefully somewhere along the way you'll be trying to prevent
|
||||
denial of service and brute force attacks against the system. An intrusion detection
|
||||
system will also be especially useful for monitoring and responding to attacks, with
|
||||
such systems able to take protective action such as blocking offending TCP/IP addresses
|
||||
in real-time. Moving to the higher layers, your Java Virtual Machine will hopefully be
|
||||
configured to minimize the permissions granted to different Java types, and then your
|
||||
application will add its own problem domain-specific security configuration. Spring
|
||||
Security makes this latter area - application security - much easier. </para>
|
||||
<para>Of course, you will need to properly address all security layers mentioned above,
|
||||
together with managerial factors that encompass every layer. A non-exhaustive list of
|
||||
such managerial factors would include security bulletin monitoring, patching, personnel
|
||||
vetting, audits, change control, engineering management systems, data backup, disaster
|
||||
recovery, performance benchmarking, load monitoring, centralised logging, incident
|
||||
response procedures etc.</para>
|
||||
<para>With Spring Security being focused on helping you with the enterprise application
|
||||
security layer, you will find that there are as many different requirements as there are
|
||||
business problem domains. A banking application has different needs from an ecommerce
|
||||
application. An ecommerce application has different needs from a corporate sales force
|
||||
automation tool. These custom requirements make application security interesting,
|
||||
challenging and rewarding. </para>
|
||||
<para>Please read <xref linkend="getting-started"/>, in its entirety to begin with. This
|
||||
will introduce you to the framework and the namespace-based configuration system with
|
||||
which you can get up and running quite quickly. To get more of an understanding of how
|
||||
Spring Security works, and some of the classes you might need to use, you should then
|
||||
read <xref linkend="overall-architecture"/>. The remaining parts of this guide are
|
||||
structured in a more traditional reference style, designed to be read on an as-required
|
||||
basis. We'd also recommend that you read up as much as possible on application security
|
||||
issues in general. Spring Security is not a panacea which will solve all security
|
||||
issues. It is important that the application is designed with security in mind from the
|
||||
start. Attempting to retrofit it is not a good idea. In particular, if you are building
|
||||
a web application, you should be aware of the many potential vulnerabilities such as
|
||||
cross-site scripting, request-forgery and session-hijacking which you should be taking
|
||||
into account from the start. The OWASP web site (http://www.owasp.org/) maintains a top
|
||||
ten list of web application vulnerabilities as well as a lot of useful reference
|
||||
information. </para>
|
||||
<para>We hope that you find this reference guide useful, and we welcome your feedback and
|
||||
<link xlink:href="#jira">suggestions</link>. </para>
|
||||
<para>Finally, welcome to the Spring Security <link xlink:href="#community"
|
||||
>community</link>. </para>
|
||||
</preface>
|
||||
<part xml:id="getting-started">
|
||||
<title>Getting Started</title>
|
||||
<partintro>
|
||||
<para>The later parts of this guide provide an in-depth discussion of the framework
|
||||
architecture and implementation classes, which you need to understand if you want to
|
||||
do any serious customization. In this part, we'll introduce Spring Security 3.0,
|
||||
give a brief overview of the project's history and take a slightly gentler look at
|
||||
how to get started using the framework. In particular, we'll look at namespace
|
||||
configuration which provides a much simpler way of securing your application
|
||||
compared to the traditional Spring bean approach where you have to wire up all the
|
||||
implementation classes individually. </para>
|
||||
<para> We'll also take a look at the sample applications that are available. It's worth
|
||||
trying to run these and experimenting with them a bit even before you read the later
|
||||
sections - you can dip back into them as your understanding of the framework
|
||||
increases. Please also check out the <link
|
||||
xlink:href="http://static.springsource.org/spring-security/site/index.html"
|
||||
>project website</link> as it has useful information on building the project,
|
||||
plus links to articles, videos and tutorials. </para>
|
||||
</partintro>
|
||||
<xi:include href="introduction.xml"/>
|
||||
<xi:include href="namespace-config.xml"/>
|
||||
<xi:include href="samples.xml"/>
|
||||
<xi:include href="community.xml"/>
|
||||
</part>
|
||||
<part xml:id="overall-architecture">
|
||||
<title>Architecture and Implementation</title>
|
||||
<partintro>
|
||||
<para>Once you are familiar with setting up and running some namespace-configuration
|
||||
based applications, you may wish to develop more of an understanding of how the
|
||||
framework actually works behind the namespace facade. Like most software, Spring
|
||||
Security has certain central interfaces, classes and conceptual abstractions that
|
||||
are commonly used throughout the framework. In this part of the reference guide we
|
||||
will look at some of these and see how they work together to support authentication
|
||||
and access-control within Spring Security.</para>
|
||||
</partintro>
|
||||
<xi:include href="technical-overview.xml"/>
|
||||
<xi:include href="core-services.xml"/>
|
||||
</part>
|
||||
<part xml:id="web-app-security">
|
||||
<title>Web Application Security</title>
|
||||
<partintro>
|
||||
<para> Most Spring Security users will be using the framework in applications which make
|
||||
user of HTTP and the Servlet API. In this part, we'll take a look at how Spring
|
||||
Security provides authentication and access-control features for the web layer of an
|
||||
application. We'll look behind the facade of the namespace and see which classes and
|
||||
interfaces are actually assembled to provide web-layer security. In some situations
|
||||
it is necessary to use traditional bean configuration to provide full control over
|
||||
the configuration, so we'll also see how to configure these classes directly without
|
||||
the namespace.</para>
|
||||
</partintro>
|
||||
<xi:include href="security-filter-chain.xml"/>
|
||||
<xi:include href="core-filters.xml"/>
|
||||
<xi:include href="basic-and-digest-auth.xml"/>
|
||||
<xi:include href="remember-me-authentication.xml"/>
|
||||
<xi:include href="session-mgmt.xml"/>
|
||||
<xi:include href="anon-auth-provider.xml"/>
|
||||
</part>
|
||||
<!--
|
||||
<part xml:id="authentication">
|
||||
<title>Authentication</title>
|
||||
<partintro>
|
||||
|
@ -145,42 +155,43 @@
|
|||
<xi:include href="dao-auth-provider.xml"/>
|
||||
</part>
|
||||
-->
|
||||
<part xml:id="authorization">
|
||||
<title>Authorization</title>
|
||||
<partintro>
|
||||
<para>The advanced authorization capabilities within Spring Security represent one of the most
|
||||
compelling reasons for its popularity. Irrespective of how you choose to authenticate -
|
||||
whether using a Spring Security-provided mechanism and provider, or integrating with a
|
||||
container or other non-Spring Security authentication authority - you will find the
|
||||
authorization services can be used within your application in a consistent and simple
|
||||
way.</para>
|
||||
<para>In this part we'll explore the different
|
||||
<classname>AbstractSecurityInterceptor</classname> implementations, which were introduced
|
||||
in Part I. We then move on to explore how to fine-tune authorization through use of domain
|
||||
access control lists.</para>
|
||||
</partintro>
|
||||
<xi:include href="authorization-common.xml"/>
|
||||
<xi:include href="secured-objects.xml"/>
|
||||
<xi:include href="el-access.xml"/>
|
||||
</part>
|
||||
<part xml:id="advanced-topics">
|
||||
<title>Additional Topics</title>
|
||||
<!--
|
||||
<part xml:id="authorization">
|
||||
<title>Authorization</title>
|
||||
<partintro>
|
||||
<para>The advanced authorization capabilities within Spring Security represent one of
|
||||
the most compelling reasons for its popularity. Irrespective of how you choose to
|
||||
authenticate - whether using a Spring Security-provided mechanism and provider, or
|
||||
integrating with a container or other non-Spring Security authentication authority -
|
||||
you will find the authorization services can be used within your application in a
|
||||
consistent and simple way.</para>
|
||||
<para>In this part we'll explore the different
|
||||
<classname>AbstractSecurityInterceptor</classname> implementations, which were
|
||||
introduced in Part I. We then move on to explore how to fine-tune authorization
|
||||
through use of domain access control lists.</para>
|
||||
</partintro>
|
||||
<xi:include href="authorization-common.xml"/>
|
||||
<xi:include href="secured-objects.xml"/>
|
||||
<xi:include href="el-access.xml"/>
|
||||
</part>
|
||||
<part xml:id="advanced-topics">
|
||||
<title>Additional Topics</title>
|
||||
<!--
|
||||
Essentially standalone features which do not have to follow on directly from earlier chapters
|
||||
-->
|
||||
<partintro>
|
||||
<para> In this part we cover features which require a knowledge of previous chapters as well
|
||||
as some of the more advanced and less-commonly used features of the framework.</para>
|
||||
</partintro>
|
||||
<xi:include href="domain-acls.xml"/>
|
||||
<xi:include href="preauth.xml"/>
|
||||
<xi:include href="ldap-auth-provider.xml"/>
|
||||
<xi:include href="taglibs.xml"/>
|
||||
<xi:include href="jaas-auth-provider.xml"/>
|
||||
<xi:include href="cas-auth-provider.xml"/>
|
||||
<xi:include href="x509-auth-provider.xml"/>
|
||||
<xi:include href="runas-auth-provider.xml"/>
|
||||
</part>
|
||||
<xi:include href="appendix-db-schema.xml"/>
|
||||
<xi:include href="appendix-namespace.xml"/>
|
||||
<partintro>
|
||||
<para> In this part we cover features which require a knowledge of previous chapters as
|
||||
well as some of the more advanced and less-commonly used features of the
|
||||
framework.</para>
|
||||
</partintro>
|
||||
<xi:include href="domain-acls.xml"/>
|
||||
<xi:include href="preauth.xml"/>
|
||||
<xi:include href="ldap-auth-provider.xml"/>
|
||||
<xi:include href="taglibs.xml"/>
|
||||
<xi:include href="jaas-auth-provider.xml"/>
|
||||
<xi:include href="cas-auth-provider.xml"/>
|
||||
<xi:include href="x509-auth-provider.xml"/>
|
||||
<xi:include href="runas-auth-provider.xml"/>
|
||||
</part>
|
||||
<xi:include href="appendix-db-schema.xml"/>
|
||||
<xi:include href="appendix-namespace.xml"/>
|
||||
</book>
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
<title>The <literal>authorize</literal> Tag</title>
|
||||
<para> This tag is used to determine whether its contents should be evaluated or not. In
|
||||
Spring Security 3.0, it can be used in two ways <footnote>
|
||||
<para>The legacy options from Spring Security 2.0 are also supported, but
|
||||
discouraged.</para>
|
||||
<para>The legacy options from Spring Security 2.0 are also supported, but
|
||||
discouraged.</para>
|
||||
</footnote>. The first approach uses a <link xlink:href="el-access-we">web-security
|
||||
expression</link>, specified in the <literal>access</literal> attribute of the tag.
|
||||
The expression evaluation will be delegated to the
|
||||
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the
|
||||
application context (you should have web expressions enabled in your
|
||||
<literal><http></literal> namespace configuration to make sure this service is
|
||||
available). So, for example, you might
|
||||
expression</link>, specified in the <literal>access</literal> attribute of the tag. The
|
||||
expression evaluation will be delegated to the
|
||||
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the application
|
||||
context (you should have web expressions enabled in your <literal><http></literal>
|
||||
namespace configuration to make sure this service is available). So, for example, you
|
||||
might
|
||||
have<programlisting><sec:authorize access="hasRole('supervisor')">
|
||||
|
||||
This content will only be visible to users who have
|
||||
|
@ -40,7 +40,7 @@ This content will only be visible to users who are authorized to send requests t
|
|||
|
||||
</sec:authorize></programlisting>To
|
||||
use this tag there must also be an instance of
|
||||
<interfacename>WebInvocationPrivilegeEvaluator</interfacename> in your application
|
||||
<interfacename>WebInvocationPrivilegeEvaluator</interfacename> in your application
|
||||
context. If you are using the namespace, one will automatically be registered. This is
|
||||
an instance of <classname>DefaultWebInvocationPrivilegeEvaluator</classname>, which
|
||||
creates a dummy web request for the supplied URL and invokes the security interceptor to
|
||||
|
@ -56,15 +56,15 @@ This content will only be visible to users who are authorized to send requests t
|
|||
<para>This tag allows access to the current <interfacename>Authentication</interfacename>
|
||||
object stored in the security context. It renders a property of the object directly in
|
||||
the JSP. So, for example, if the <literal>principal</literal> property of the
|
||||
<interfacename>Authentication</interfacename> is an instance of Spring Security's
|
||||
<interfacename>UserDetails</interfacename> object, then using
|
||||
<literal><sec:authentication property="principal.username" /></literal> will
|
||||
render the name of the current user.</para>
|
||||
<interfacename>Authentication</interfacename> is an instance of Spring Security's
|
||||
<interfacename>UserDetails</interfacename> object, then using
|
||||
<literal><sec:authentication property="principal.username" /></literal> will render
|
||||
the name of the current user.</para>
|
||||
<para>Of course, it isn't necessary to use JSP tags for this kind of thing and some people
|
||||
prefer to keep as little logic as possible in the view. You can access the
|
||||
<interfacename>Authentication</interfacename> object in your MVC controller (by
|
||||
calling <code>SecurityContextHolder.getContext().getAuthentication()</code>) and add the
|
||||
data directly to your model for rendering by the view.</para>
|
||||
<interfacename>Authentication</interfacename> object in your MVC controller (by calling
|
||||
<code>SecurityContextHolder.getContext().getAuthentication()</code>) and add the data
|
||||
directly to your model for rendering by the view.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>The <literal>accesscontrollist</literal> Tag</title>
|
||||
|
@ -80,14 +80,14 @@ represented by the values "1" or "2" on the given object.
|
|||
</sec:accesscontrollist></programlisting></para>
|
||||
<para>The permissions are passed to the <interfacename>PermissionFactory</interfacename>
|
||||
defined in the application context, converting them to ACL
|
||||
<interfacename>Permission</interfacename> instances, so they may be any format which
|
||||
is supported by the factory - they don't have to be integers, they could be strings like
|
||||
<literal>READ</literal> or <literal>WRITE</literal>. If no
|
||||
<interfacename>PermissionFactory</interfacename> is found, an instance of
|
||||
<classname>DefaultPermissionFactory</classname> will be used. The
|
||||
<interfacename>AclService</interfacename>from the application context will be used
|
||||
to load the <interfacename>Acl</interfacename> instance for the supplied object. The
|
||||
<interfacename>Acl</interfacename> will be invoked with the required permissions to
|
||||
<interfacename>Permission</interfacename> instances, so they may be any format which is
|
||||
supported by the factory - they don't have to be integers, they could be strings like
|
||||
<literal>READ</literal> or <literal>WRITE</literal>. If no
|
||||
<interfacename>PermissionFactory</interfacename> is found, an instance of
|
||||
<classname>DefaultPermissionFactory</classname> will be used. The
|
||||
<interfacename>AclService</interfacename>from the application context will be used to
|
||||
load the <interfacename>Acl</interfacename> instance for the supplied object. The
|
||||
<interfacename>Acl</interfacename> will be invoked with the required permissions to
|
||||
check if any of them are granted.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,35 +1,38 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Web Application Infrastructure</title>
|
||||
</info>
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<info>
|
||||
<title>Web Application Infrastructure</title>
|
||||
</info>
|
||||
|
||||
<section xml:id="filters">
|
||||
<title>The Security Filter Chain</title>
|
||||
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
|
||||
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so
|
||||
it has no strong links to any particular web technology. It deals in
|
||||
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
|
||||
and doesn't care whether the requests come from a browser, a web service client, an
|
||||
<classname>HttpInvoker</classname> or an AJAX application. </para>
|
||||
<para> Spring Security maintains a filter chain internally where each of the filters has a
|
||||
particular responsibility and filters are added or removed from the configuration depending on
|
||||
which services are required. The ordering of the filters is important as there are
|
||||
dependencies between them. If you have been using <link xlink:href="#ns-config">namespace
|
||||
configuration</link>, then the filters are automatically configured for you and you don't
|
||||
have to define any Spring beans explicitly but here may be times when you want full control
|
||||
over the security filter chain, either because you are using features which aren't supported
|
||||
in the namespace, or you are using your own customized versions of classes.</para>
|
||||
<section xml:id="delegating-filter-proxy">
|
||||
<title><classname>DelegatingFilterProxy</classname></title>
|
||||
<para> When using servlet filters, you obviously need to declare them in your
|
||||
<filename>web.xml</filename>, or they will be ignored by the servlet container. In Spring
|
||||
Security, the filter classes are also Spring beans defined in the application context and
|
||||
thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle
|
||||
interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides the link between
|
||||
<filename>web.xml</filename> and the application context. </para>
|
||||
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like
|
||||
this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
|
||||
<section xml:id="filters">
|
||||
<title>The Security Filter Chain</title>
|
||||
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
|
||||
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC)
|
||||
internally, so it has no strong links to any particular web technology. It deals in
|
||||
<classname>HttpServletRequest</classname>s and
|
||||
<classname>HttpServletResponse</classname>s and doesn't care whether the requests come
|
||||
from a browser, a web service client, an <classname>HttpInvoker</classname> or an AJAX
|
||||
application. </para>
|
||||
<para> Spring Security maintains a filter chain internally where each of the filters has a
|
||||
particular responsibility and filters are added or removed from the configuration
|
||||
depending on which services are required. The ordering of the filters is important as
|
||||
there are dependencies between them. If you have been using <link
|
||||
xlink:href="#ns-config">namespace configuration</link>, then the filters are
|
||||
automatically configured for you and you don't have to define any Spring beans
|
||||
explicitly but here may be times when you want full control over the security filter
|
||||
chain, either because you are using features which aren't supported in the namespace, or
|
||||
you are using your own customized versions of classes.</para>
|
||||
<section xml:id="delegating-filter-proxy">
|
||||
<title><classname>DelegatingFilterProxy</classname></title>
|
||||
<para> When using servlet filters, you obviously need to declare them in your
|
||||
<filename>web.xml</filename>, or they will be ignored by the servlet container. In
|
||||
Spring Security, the filter classes are also Spring beans defined in the application
|
||||
context and thus able to take advantage of Spring's rich dependency-injection
|
||||
facilities and lifecycle interfaces. Spring's
|
||||
<classname>DelegatingFilterProxy</classname> provides the link between
|
||||
<filename>web.xml</filename> and the application context. </para>
|
||||
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something
|
||||
like this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
|
||||
<filter>
|
||||
<filter-name>myFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
|
@ -40,29 +43,31 @@
|
|||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>]]>
|
||||
</programlisting> Notice that the filter is actually a
|
||||
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement
|
||||
the logic of the filter. What <classname>DelegatingFilterProxy</classname> does is delegate
|
||||
the <interfacename>Filter</interfacename>'s methods through to a bean which is obtained from
|
||||
the Spring application context. This enables the bean to benefit from the Spring web
|
||||
application context lifecycle support and configuration flexibility. The bean must implement
|
||||
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that
|
||||
in the <literal>filter-name</literal> element. Read the Javadoc for
|
||||
<classname>DelegatingFilterProxy</classname> for more information</para>
|
||||
</section>
|
||||
<section xml:id="filter-chain-proxy">
|
||||
<title><classname>FilterChainProxy</classname></title>
|
||||
<para> It should now be clear that you can declare each Spring Security filter bean that you
|
||||
require in your application context file and add a corresponding
|
||||
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for
|
||||
each filter, making sure that they are ordered correctly. This is a cumbersome approach and
|
||||
clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We
|
||||
would prefer to just add a single entry to <filename>web.xml</filename> and deal entirely
|
||||
with the application context file for managing our web security beans. This is where Spring
|
||||
Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a
|
||||
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with the
|
||||
<literal>filter-name</literal> set to the bean name <quote>filterChainProxy</quote>. The
|
||||
filter chain is then declared in the application context with the same bean name. Here's an
|
||||
example: <programlisting language="xml"><![CDATA[
|
||||
<literal>DelegatingFilterProxy</literal>, and not the class that will actually
|
||||
implement the logic of the filter. What <classname>DelegatingFilterProxy</classname>
|
||||
does is delegate the <interfacename>Filter</interfacename>'s methods through to a
|
||||
bean which is obtained from the Spring application context. This enables the bean to
|
||||
benefit from the Spring web application context lifecycle support and configuration
|
||||
flexibility. The bean must implement
|
||||
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name
|
||||
as that in the <literal>filter-name</literal> element. Read the Javadoc for
|
||||
<classname>DelegatingFilterProxy</classname> for more information</para>
|
||||
</section>
|
||||
<section xml:id="filter-chain-proxy">
|
||||
<title><classname>FilterChainProxy</classname></title>
|
||||
<para> It should now be clear that you can declare each Spring Security filter bean that
|
||||
you require in your application context file and add a corresponding
|
||||
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename>
|
||||
for each filter, making sure that they are ordered correctly. This is a cumbersome
|
||||
approach and clutters up the <filename>web.xml</filename> file quickly if we have a
|
||||
lot of filters. We would prefer to just add a single entry to
|
||||
<filename>web.xml</filename> and deal entirely with the application context file for
|
||||
managing our web security beans. This is where Spring Secuiryt's
|
||||
<classname>FilterChainProxy</classname> comes in. It is wired using a
|
||||
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with
|
||||
the <literal>filter-name</literal> set to the bean name
|
||||
<quote>filterChainProxy</quote>. The filter chain is then declared in the
|
||||
application context with the same bean name. Here's an example: <programlisting language="xml"><![CDATA[
|
||||
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/webServices/**" filters="
|
||||
|
@ -78,127 +83,134 @@
|
|||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
]]>
|
||||
</programlisting> The namespace element <literal>filter-chain-map</literal> is
|
||||
used to set up the security filter chain(s) which are required within the application<footnote>
|
||||
<para>Note that you'll need to include the security namespace in your application context
|
||||
XML file in order to use this syntax.</para>
|
||||
</footnote>. It maps a particular URL pattern to a chain of filters built up from the bean
|
||||
names specified in the <literal>filters</literal> element. Both regular expressions and Ant
|
||||
Paths are supported, and the most specific URIs appear first. At runtime the
|
||||
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches the
|
||||
current web request and the list of filter beans specified by the <literal>filters</literal>
|
||||
attribute will be applied to that request. The filters will be invoked in the order they are
|
||||
defined, so you have complete control over the filter chain which is applied to a particular
|
||||
URL.</para>
|
||||
<para>You may have noticed we have declared two
|
||||
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
|
||||
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property
|
||||
of <classname>SecurityContextPersistenceFilter</classname>). As web services will never
|
||||
present a <literal>jsessionid</literal> on future requests, creating
|
||||
<literal>HttpSession</literal>s for such user agents would be wasteful. If you had a
|
||||
high-volume application which required maximum scalability, we recommend you use the
|
||||
approach shown above. For smaller applications, using a single
|
||||
<classname>SecurityContextPersistenceFilter</classname> (with its default
|
||||
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
|
||||
sufficient.</para>
|
||||
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will always
|
||||
delegate <methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
|
||||
methods through to the underlaying <interfacename>Filter</interfacename>s if such methods
|
||||
are called against <classname>FilterChainProxy</classname> itself. In this case,
|
||||
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy each
|
||||
<literal>Filter</literal> bean once, no matter how many times it is declared in the filter
|
||||
chain(s). You control the overall choice as to whether these methods are called or not via
|
||||
the <literal>targetFilterLifecycle</literal> initialization parameter of
|
||||
<literal>DelegatingFilterProxy</literal>. By default this property is
|
||||
<literal>false</literal> and servlet container lifecycle invocations are not delegated
|
||||
through <literal>DelegatingFilterProxy</literal>.</para>
|
||||
<para> When we looked at how to set up web security using <link
|
||||
xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
|
||||
<literal>DelegatingFilterProxy</literal> with the name
|
||||
<quote>springSecurityFilterChain</quote>. You should now be able to see that this is the
|
||||
name of the <classname>FilterChainProxy</classname> which is created by the namespace. </para>
|
||||
<section>
|
||||
<title>Bypassing the Filter Chain</title>
|
||||
<para> As with the namespace, you can use the attribute <literal>filters = "none"</literal>
|
||||
as an alternative to supplying a filter bean list. This will omit the request pattern from
|
||||
the security filter chain entirely. Note that anything matching this path will then have
|
||||
no authentication or authorization services applied and will be freely accessible. If you
|
||||
want to make use of the contents of the <classname>SecurityContext</classname> contents
|
||||
during a request, then it must have passed through the security filter chain. Otherwise
|
||||
the <classname>SecurityContextHolder</classname> will not have been populated and the
|
||||
contents will be null.</para>
|
||||
</section>
|
||||
</programlisting> The namespace element <literal>filter-chain-map</literal> is used to set
|
||||
up the security filter chain(s) which are required within the application<footnote>
|
||||
<para>Note that you'll need to include the security namespace in your application
|
||||
context XML file in order to use this syntax.</para>
|
||||
</footnote>. It maps a particular URL pattern to a chain of filters built up from
|
||||
the bean names specified in the <literal>filters</literal> element. Both regular
|
||||
expressions and Ant Paths are supported, and the most specific URIs appear first. At
|
||||
runtime the <classname>FilterChainProxy</classname> will locate the first URI
|
||||
pattern that matches the current web request and the list of filter beans specified
|
||||
by the <literal>filters</literal> attribute will be applied to that request. The
|
||||
filters will be invoked in the order they are defined, so you have complete control
|
||||
over the filter chain which is applied to a particular URL.</para>
|
||||
<para>You may have noticed we have declared two
|
||||
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
|
||||
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a
|
||||
property of <classname>SecurityContextPersistenceFilter</classname>). As web
|
||||
services will never present a <literal>jsessionid</literal> on future requests,
|
||||
creating <literal>HttpSession</literal>s for such user agents would be wasteful. If
|
||||
you had a high-volume application which required maximum scalability, we recommend
|
||||
you use the approach shown above. For smaller applications, using a single
|
||||
<classname>SecurityContextPersistenceFilter</classname> (with its default
|
||||
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
|
||||
sufficient.</para>
|
||||
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will
|
||||
always delegate <methodname>init(FilterConfig)</methodname> and
|
||||
<methodname>destroy()</methodname> methods through to the underlaying
|
||||
<interfacename>Filter</interfacename>s if such methods are called against
|
||||
<classname>FilterChainProxy</classname> itself. In this case,
|
||||
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy
|
||||
each <literal>Filter</literal> bean once, no matter how many times it is declared in
|
||||
the filter chain(s). You control the overall choice as to whether these methods are
|
||||
called or not via the <literal>targetFilterLifecycle</literal> initialization
|
||||
parameter of <literal>DelegatingFilterProxy</literal>. By default this property is
|
||||
<literal>false</literal> and servlet container lifecycle invocations are not
|
||||
delegated through <literal>DelegatingFilterProxy</literal>.</para>
|
||||
<para> When we looked at how to set up web security using <link
|
||||
xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
|
||||
<literal>DelegatingFilterProxy</literal> with the name
|
||||
<quote>springSecurityFilterChain</quote>. You should now be able to see that this is
|
||||
the name of the <classname>FilterChainProxy</classname> which is created by the
|
||||
namespace. </para>
|
||||
<section>
|
||||
<title>Bypassing the Filter Chain</title>
|
||||
<para> As with the namespace, you can use the attribute <literal>filters =
|
||||
"none"</literal> as an alternative to supplying a filter bean list. This will
|
||||
omit the request pattern from the security filter chain entirely. Note that
|
||||
anything matching this path will then have no authentication or authorization
|
||||
services applied and will be freely accessible. If you want to make use of the
|
||||
contents of the <classname>SecurityContext</classname> contents during a
|
||||
request, then it must have passed through the security filter chain. Otherwise
|
||||
the <classname>SecurityContextHolder</classname> will not have been populated
|
||||
and the contents will be null.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Filter Ordering</title>
|
||||
<para>The order that filters are defined in the chain is very important. Irrespective of
|
||||
which filters you are actually using, the order should be as follows: <orderedlist>
|
||||
<listitem>
|
||||
<para><classname>ChannelProcessingFilter</classname>, because it might need to
|
||||
redirect to a different protocol</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
|
||||
<classname>SecurityContextHolder</classname> functionality but needs to
|
||||
update the <interfacename>SessionRegistry</interfacename> to reflect ongoing
|
||||
requests from the principal</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>SecurityContextPersistenceFilter</classname>, so a
|
||||
<interfacename>SecurityContext</interfacename> can be set up in the
|
||||
<classname>SecurityContextHolder</classname> at the beginning of a web
|
||||
request, and any changes to the
|
||||
<interfacename>SecurityContext</interfacename> can be copied to the
|
||||
<literal>HttpSession</literal> when the web request ends (ready for use with
|
||||
the next web request)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Authentication processing mechanisms -
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname>,
|
||||
<classname>CasProcessingFilter</classname>,
|
||||
<classname>BasicProcessingFilter</classname> etc - so that the
|
||||
<classname>SecurityContextHolder</classname> can be modified to contain a
|
||||
valid <interfacename>Authentication</interfacename> request token</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <literal>SecurityContextHolderAwareRequestFilter</literal>, if you are
|
||||
using it to install a Spring Security aware
|
||||
<literal>HttpServletRequestWrapper</literal> into your servlet
|
||||
container</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>RememberMeProcessingFilter</classname>, so that if no earlier
|
||||
authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, and the request presents a
|
||||
cookie that enables remember-me services to take place, a suitable
|
||||
remembered <interfacename>Authentication</interfacename> object will be put
|
||||
there</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>AnonymousProcessingFilter</classname>, so that if no earlier
|
||||
authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, an anonymous
|
||||
<interfacename>Authentication</interfacename> object will be put
|
||||
there</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring
|
||||
Security exceptions so that either an HTTP error response can be returned or
|
||||
an appropriate <interfacename>AuthenticationEntryPoint</interfacename> can
|
||||
be launched</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and
|
||||
raise exceptions when access is denied</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Use with other Filter-Based Frameworks</title>
|
||||
<para>If you're using some other framework that is also filter-based, then you need to
|
||||
make sure that the Spring Security filters come first. This enables the
|
||||
<classname>SecurityContextHolder</classname> to be populated in time for use by the
|
||||
other filters. Examples are the use of SiteMesh to decorate your web pages or a web
|
||||
framework like Wicket which uses a filter to handle its requests. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Filter Ordering</title>
|
||||
<para>The order that filters are defined in the chain is very important. Irrespective of which
|
||||
filters you are actually using, the order should be as follows:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para><classname>ChannelProcessingFilter</classname>, because it might need to redirect
|
||||
to a different protocol</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
|
||||
<classname>SecurityContextHolder</classname> functionality but needs to update the
|
||||
<interfacename>SessionRegistry</interfacename> to reflect ongoing requests from the
|
||||
principal</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>SecurityContextPersistenceFilter</classname>, so a
|
||||
<interfacename>SecurityContext</interfacename> can be set up in the
|
||||
<classname>SecurityContextHolder</classname> at the beginning of a web request, and
|
||||
any changes to the <interfacename>SecurityContext</interfacename> can be copied to the
|
||||
<literal>HttpSession</literal> when the web request ends (ready for use with the
|
||||
next web request)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Authentication processing mechanisms -
|
||||
<classname>UsernamePasswordAuthenticationFilter</classname>,
|
||||
<classname>CasProcessingFilter</classname>,
|
||||
<classname>BasicProcessingFilter</classname> etc - so that the
|
||||
<classname>SecurityContextHolder</classname> can be modified to contain a valid
|
||||
<interfacename>Authentication</interfacename> request token</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <literal>SecurityContextHolderAwareRequestFilter</literal>, if you are using
|
||||
it to install a Spring Security aware <literal>HttpServletRequestWrapper</literal>
|
||||
into your servlet container</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>RememberMeProcessingFilter</classname>, so that if no earlier
|
||||
authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, and the request presents a cookie that
|
||||
enables remember-me services to take place, a suitable remembered
|
||||
<interfacename>Authentication</interfacename> object will be put there</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>AnonymousProcessingFilter</classname>, so that if no earlier
|
||||
authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, an anonymous
|
||||
<interfacename>Authentication</interfacename> object will be put there</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring Security
|
||||
exceptions so that either an HTTP error response can be returned or an appropriate
|
||||
<interfacename>AuthenticationEntryPoint</interfacename> can be launched</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and raise
|
||||
exceptions when access is denied</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Use with other Filter-Based Frameworks</title>
|
||||
<para>If you're using some other framework that is also filter-based, then you need to make
|
||||
sure that the Spring Security filters come first. This enables the
|
||||
<classname>SecurityContextHolder</classname> to be populated in time for use by the other
|
||||
filters. Examples are the use of SiteMesh to decorate your web pages or a web framework like
|
||||
Wicket which uses a filter to handle its requests. </para>
|
||||
</section>
|
||||
</section>
|
||||
<!--
|
||||
<!--
|
||||
<section xml:id="taglib">
|
||||
<info>
|
||||
<title>Tag Libraries</title>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="x509">
|
||||
<info><title>X.509 Authentication</title></info>
|
||||
<info>
|
||||
<title>X.509 Authentication</title>
|
||||
</info>
|
||||
|
||||
<section xml:id="x509-overview"><info><title>Overview</title></info>
|
||||
<section xml:id="x509-overview">
|
||||
<info>
|
||||
<title>Overview</title>
|
||||
</info>
|
||||
|
||||
<para>The most common use of X.509 certificate authentication is in verifying the identity
|
||||
of a server when using SSL, most commonly when using HTTPS from a browser. The browser
|
||||
|
@ -10,38 +15,47 @@
|
|||
maintains.</para>
|
||||
<para>You can also use SSL with <quote>mutual authentication</quote>; the server will then
|
||||
request a valid certificate from the client as part of the SSL handshake. The server
|
||||
will authenticate the client by checking that its certificate is signed by an
|
||||
acceptable authority. If a valid certificate has been provided, it can be obtained
|
||||
through the servlet API in an application. Spring Security X.509 module extracts the
|
||||
certificate using a filter. It maps the certificate to an application user and loads that
|
||||
user's set of granted authorities for use with the standard Spring Security infrastructure.</para>
|
||||
will authenticate the client by checking that its certificate is signed by an acceptable
|
||||
authority. If a valid certificate has been provided, it can be obtained through the
|
||||
servlet API in an application. Spring Security X.509 module extracts the certificate
|
||||
using a filter. It maps the certificate to an application user and loads that user's set
|
||||
of granted authorities for use with the standard Spring Security infrastructure.</para>
|
||||
<para>You should be familiar with using certificates and setting up client authentication
|
||||
for your servlet container before attempting to use it with Spring Security. Most of the
|
||||
work is in creating and installing suitable certificates and keys. For example, if
|
||||
you're using Tomcat then read the instructions here <uri xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html">http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html</uri>. It's important that
|
||||
you get this working before trying it out with Spring Security</para>
|
||||
you're using Tomcat then read the instructions here <uri
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html"
|
||||
>http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html</uri>. It's important that you
|
||||
get this working before trying it out with Spring Security</para>
|
||||
</section>
|
||||
<section><info><title>Adding X.509 Authentication to Your Web Application</title></info>
|
||||
<section>
|
||||
<info>
|
||||
<title>Adding X.509 Authentication to Your Web Application</title>
|
||||
</info>
|
||||
|
||||
<para> Enabling X.509 client authentication is very straightforward. Just add the <literal><x509/></literal> element to your http security namespace configuration. <programlisting>
|
||||
<para> Enabling X.509 client authentication is very straightforward. Just add the
|
||||
<literal><x509/></literal> element to your http security namespace configuration.
|
||||
<programlisting>
|
||||
<http>
|
||||
...
|
||||
<x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/>
|
||||
...
|
||||
</http>
|
||||
</programlisting> The element has two optional attributes: <itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>subject-principal-regex</literal>. The regular expression used to
|
||||
extract a username from the certificate's subject name. The default value is
|
||||
shown above. This is the username which will be passed to the <interfacename>UserDetailsService</interfacename> to load the authorities for the
|
||||
user.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>user-service-ref</literal>. This is the bean Id of the
|
||||
<interfacename>UserDetailsService</interfacename> to be used with X.509.
|
||||
It isn't needed if there is only one defined in your application
|
||||
context.</para>
|
||||
</listitem>
|
||||
</programlisting>
|
||||
The element has two optional attributes: <itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>subject-principal-regex</literal>. The regular expression used to
|
||||
extract a username from the certificate's subject name. The default value is
|
||||
shown above. This is the username which will be passed to the
|
||||
<interfacename>UserDetailsService</interfacename> to load the authorities for
|
||||
the user.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>user-service-ref</literal>. This is the bean Id of the
|
||||
<interfacename>UserDetailsService</interfacename> to be used with X.509. It
|
||||
isn't needed if there is only one defined in your application context.</para>
|
||||
</listitem>
|
||||
</itemizedlist> The <literal>subject-principal-regex</literal> should contain a single
|
||||
group. For example the default expression "CN=(.*?)," matches the common name field. So
|
||||
if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this will give a
|
||||
|
@ -54,21 +68,21 @@
|
|||
authentication with other options such as a form-based login. </para>
|
||||
</section>
|
||||
<section xml:id="x509-ssl-config">
|
||||
<info><title>Setting up SSL in Tomcat</title></info>
|
||||
<info>
|
||||
<title>Setting up SSL in Tomcat</title>
|
||||
</info>
|
||||
|
||||
<para>There are some pre-generated certificates in the
|
||||
<filename>samples/certificate</filename> directory in the Spring Security project.
|
||||
You can use these to enable SSL for testing if you don't want to generate your own. The file
|
||||
<filename>server.jks</filename> contains the server certificate, private key and the
|
||||
<filename>samples/certificate</filename> directory in the Spring Security project. You
|
||||
can use these to enable SSL for testing if you don't want to generate your own. The file
|
||||
<filename>server.jks</filename> contains the server certificate, private key and the
|
||||
issuing certificate authority certificate. There are also some client certificate files
|
||||
for the users from the sample applications. You can install these in your browser to enable
|
||||
SSL client authentication.
|
||||
</para>
|
||||
<para>
|
||||
To run tomcat with SSL support, drop the <filename>server.jks</filename> file into the
|
||||
tomcat <filename>conf</filename> directory and add the following connector to the
|
||||
for the users from the sample applications. You can install these in your browser to
|
||||
enable SSL client authentication. </para>
|
||||
<para> To run tomcat with SSL support, drop the <filename>server.jks</filename> file into
|
||||
the tomcat <filename>conf</filename> directory and add the following connector to the
|
||||
<filename>server.xml</filename> file
|
||||
<programlisting>
|
||||
<programlisting>
|
||||
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
|
||||
clientAuth="true" sslProtocol="TLS"
|
||||
keystoreFile="${catalina.home}/conf/server.jks"
|
||||
|
@ -77,10 +91,10 @@
|
|||
truststoreType="JKS" truststorePass="password"
|
||||
/>
|
||||
</programlisting>
|
||||
<parameter>clientAuth</parameter> can also be set to <parameter>want</parameter> if you still
|
||||
want SSL connections to succeed even if the client doesn't provide a certificate.
|
||||
<parameter>clientAuth</parameter> can also be set to <parameter>want</parameter> if you
|
||||
still want SSL connections to succeed even if the client doesn't provide a certificate.
|
||||
Clients which don't present a certificate won't be able to access any objects secured by
|
||||
Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication.
|
||||
</para>
|
||||
Spring Security unless you use a non-X.509 authentication mechanism, such as form
|
||||
authentication. </para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
Loading…
Reference in New Issue