1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Restructured docs, faq and removed use of docbkx plugin

This commit is contained in:
Luke Taylor
2009-05-26 11:25:13 +00:00
parent 45c54c558c
commit 3bc7404854
51 changed files with 281 additions and 172 deletions
+90
View File
@@ -0,0 +1,90 @@
#! /usr/bin/perl
use strict;
# Get list of links to class src packages
system("curl http://static.springframework.org/spring-security/site/xref/allclasses-frame.html > allclasses-frame.html");
my @all_classes = `cat allclasses-frame.html`;
$#all_classes > 0 || die "No lines in xref";
#<a href="org/springframework/security/vote/AbstractAccessDecisionManager.html" target="classFrame">AbstractAccessDecisionManager</a>
my %classnames_to_src;
while ($_ = pop @all_classes) {
next unless $_ =~ /<a href="(.*)" target="classFrame">(([a-zA-Z0-9_]+?))<\/a>/;
$classnames_to_src{$2} = $1;
}
#my @docbook = glob("*.xml");
my @docbook;
# Read the includes rather than using globbing to get the ordering right for the index.
open MAINDOC, "<springsecurity.xml";
while(<MAINDOC>) {
if (/href="(.*\.xml)"/) {
push @docbook, $1;
}
}
# Hash of xml:id (i.e. anchor) to filename.html#anchor
my %id_to_html;
my %class_index;
# Build map of html pages links
while (my $file = pop @docbook) {
open FILE, $file or die "$!";
print "\nProcessing: $file\n\n";
my $file_id;
while(<FILE>) {
if (/.* xml:id="([a-z0-9-]+?)"/) {
$file_id = $1;
last;
}
}
$id_to_html{$file_id} = "$file_id.html#$file_id";
while (<FILE>) {
next unless /.* xml:id="([a-z0-9-]+?)"/;
print "$1\n";
$id_to_html{$1} = "$file_id.html#$1";
}
close FILE;
}
# Get the list of class/interface names and their section ids/titles
my @class_references = split /;/,`xsltproc --xinclude index-classes.xsl springsecurity.xml`;
# Get unique values
my %seen = ();
@class_references = grep { !$seen{$_}++} @class_references;
print "\nThere are $#class_references references to classes and interfaces.\n";
my %id_to_title;
my %classnames_to_ids = ();
foreach my $class_id_title (@class_references) {
(my $class, my $id, my $title) = split /:/, $class_id_title;
$title =~ s/</&lt;/;
$title =~ s/>/&gt;/;
$id_to_title{$id} = $title;
push( @{$classnames_to_ids{$class}}, $id );
}
open INDEX, ">classindex.xml" || die "Couldn't open output file\n";
print INDEX "<index>\n";
foreach my $class (sort keys %classnames_to_ids) {
print INDEX "<class name='$class'";
if (exists $classnames_to_src{$class}) {
print INDEX " src-xref='$classnames_to_src{$class}'";
}
print INDEX ">\n";
foreach my $id (@{$classnames_to_ids{$class}}) {
print INDEX " <link href='$id_to_html{$id}' title='$id_to_title{$id}'/>\n";
}
print INDEX "</class>\n"
}
print INDEX "</index>\n";
close INDEX;
@@ -0,0 +1,105 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="anonymous">
<info><title>Anonymous Authentication</title></info>
<section xml:id="anonymous-overview">
<info><title>Overview</title></info>
<para>Particularly in the case of web request URI security, sometimes
it is more convenient to assign configuration attributes against every
possible secure object invocation. 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. There are also other
situations where anonymous authentication would be desired, such as
when an auditing interceptor queries the
<classname>SecurityContextHolder</classname> to identify which principal
was responsible for a given operation. Such classes can be authored
with more robustness if they know the
<classname>SecurityContextHolder</classname> always contains an
<interfacename>Authentication</interfacename> object, and never
<literal>null</literal>.</para>
</section>
<section xml:id="anonymous-config">
<info><title>Configuration</title></info>
<para>Spring Security provides three classes that together provide an
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>AnonymousAuthenticationTokens</literal> are accepted.
Finally, there is an AnonymousProcessingFilter, which is chained after
the normal authentication mechanisms and automatically add an
<literal>AnonymousAuthenticationToken</literal> to the
<classname>SecurityContextHolder</classname> if there is no existing
<interfacename>Authentication</interfacename> held there. The definition of the
filter and authentication provider appears as follows:</para>
<para><programlisting>
<![CDATA[
<bean id="anonymousProcessingFilter"
class="org.springframework.security.web.authentication.AnonymousProcessingFilter">
<property name="key" value="foobar"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
<bean id="anonymousAuthenticationProvider"
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>]]>
</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. The <literal>userAttribute</literal> is
expressed in the form of
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
This is the same syntax as used after the equals sign for
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal>
property.</para>
<para>As explained earlier, the benefit of anonymous authentication is
that all URI patterns can have security applied to them. For
example:</para>
<para><programlisting>
<![CDATA[
<bean id="filterInvocationInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
<property name="objectDefinitionSource">
<security:filter-invocation-definition-source>
<security:intercept-url pattern='/index.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/hello.htm' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/logoff.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/login.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/**' access='ROLE_USER'/>
</security:filter-invocation-definition-source>" +
</property>
</bean>]]>
</programlisting>Rounding out the anonymous authentication discussion
is the <literal>AuthenticationTrustResolver</literal> interface, with
its corresponding <literal>AuthenticationTrustResolverImpl</literal>
implementation. This interface provides an
<literal>isAnonymous(Authentication)</literal> method, which allows
interested classes to take into account this special type of
authentication status. The
<classname>ExceptionTranslationFilter</classname> uses this interface in
processing <literal>AccessDeniedException</literal>s. If an
<literal>AccessDeniedException</literal> is thrown, and the
authentication is of an anonymous type, instead of throwing a 403
(forbidden) response, the filter will instead commence the
<interfacename>AuthenticationEntryPoint</interfacename> so the principal can
authenticate properly. This is a necessary distinction, otherwise
principals would always be deemed "authenticated" and never be given
an opportunity to login via form, basic, digest or some other normal
authentication mechanism</para>
</section>
</chapter>
@@ -0,0 +1,184 @@
<?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>
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,
enabled boolean not null);
create table authorities (
username varchar_ignorecase(50) not null,
authority varchar_ignorecase(50) not null,
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
<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);
create table group_authorities (
group_id bigint not null,
authority varchar(50) not null,
constraint fk_group_authorities_group foreign key(group_id) references groups(id));
create table group_members (
id bigint generated by default as identity(start with 0) primary key,
username varchar(50) not null,
group_id bigint not null,
constraint fk_group_members_group foreign key(group_id) references groups(id));
</programlisting></para>
</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">
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">
create table acl_sid (
id bigint generated by default as identity(start with 100) not null primary key,
principal boolean not null,
sid varchar_ignorecase(100) not null,
constraint unique_uk_1 unique(sid,principal) );
create table acl_class (
id bigint generated by default as identity(start with 100) not null primary key,
class varchar_ignorecase(100) not null,
constraint unique_uk_2 unique(class) );
create table acl_object_identity (
id bigint generated by default as identity(start with 100) not null primary key,
object_id_class bigint not null,
object_id_identity bigint not null,
parent_object bigint,
owner_sid bigint not null,
entries_inheriting boolean not null,
constraint unique_uk_3 unique(object_id_class,object_id_identity),
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );
create table acl_entry (
id bigint generated by default as identity(start with 100) not null primary key,
acl_object_identity bigint not null,ace_order int not null,sid bigint not null,
mask integer not null,granting boolean not null,audit_success boolean not null,
audit_failure boolean not null,constraint unique_uk_4 unique(acl_object_identity,ace_order),
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>
<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,
constraint unique_uk_1 unique(sid,principal));
create table acl_class(
id bigserial not null primary key,
class varchar(100) not null,
constraint unique_uk_2 unique(class));
create table acl_object_identity(
id bigserial primary key,
object_id_class bigint not null,
object_id_identity bigint not null,
parent_object bigint,
owner_sid bigint,
entries_inheriting boolean not null,
constraint unique_uk_3 unique(object_id_class,object_id_identity),
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id));
create table acl_entry(
id bigserial primary key,
acl_object_identity bigint not null,
ace_order int not null,
sid bigint not null,
mask integer not null,
granting boolean not null,
audit_success boolean not null,
audit_failure boolean not null,
constraint unique_uk_4 unique(acl_object_identity,ace_order),
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>
</section>
</section>
</appendix>
@@ -0,0 +1,650 @@
<?xml version="1.0" encoding="UTF-8"?>
<appendix version="5.0" xml:id="appendix-namespace" xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>The Security Namespace</title>
</info>
<para>
This appendix provides a reference to the elements available in the security namespace and information on
the underlying beans they create (a knowledge of the individual classes and how they work together is assumed -
you can find more information in the project Javadoc and elsewhere in this document).
If you haven't used the namespace before, please read the
<link xlink:href="#ns-config">introductory chapter</link> on namespace configuration,
as this is intended as a supplement to the information there. Using a good quality XML editor while editing a
configuration based on the schema is recommended as this will provide contextual information on which elements
and attributes are available as well as comments explaining their purpose.
</para>
<section xml:id="nsa-http">
<title>Web Application Security - the <literal>&lt;http&gt;</literal> Element</title>
<para>
The <literal>&lt;http&gt;</literal> element encapsulates the security configuration for the web layer of your application.
It creates a <classname>FilterChainProxy</classname> bean named "springSecurityFilterChain" which maintains the stack of
security filters which make up the web security configuration <footnote><para>See the
<link xlink:href="#ns-web-xml"> introductory chapter</link> for how to set up the mapping from
your <literal>web.xml</literal></para></footnote>. Some core filters are always created and others will
be added to the stack depending on the attributes child elements which are present. The positions of the standard
filters are fixed (see <link xlink:href="#filter-stack">the filter order table</link> in the namespace introduction),
removing a common source of errors with previous versions of the framework when users had to configure the
filter chain explicitly in the<classname>FilterChainProxy</classname> bean. You can, of course, still do this
if you need full control of the configuration.
</para>
<para>
All filters which require a reference to the <interfacename>AuthenticationManager</interfacename> will be automatically
injected with the internal instance created by the namespace configuration (see the
<link xlink:href="#ns-auth-manager"> introductory chapter</link> for more on the <interfacename>AuthenticationManager</interfacename>).
</para>
<para>
The <literal>&lt;http&gt;</literal> namespace block always creates an <classname>HttpSessionContextIntegrationFilter</classname>,
an <classname>ExceptionTranslationFilter</classname> and a <classname>FilterSecurityInterceptor</classname>. These are fixed
and cannot be replaced with alternatives.
</para>
<section xml:id="nsa-http-attributes">
<title><literal>&lt;http&gt;</literal> Attributes</title>
<para>
The attributes on the <literal>&lt;http&gt;</literal> element control some of the properties on the
core filters.
</para>
<section xml:id="nsa-servlet-api-provision">
<title><literal>servlet-api-provision</literal></title>
<para>
Provides versions of <literal>HttpServletRequest</literal> security methods such as
<literal>isUserInRole()</literal> and <literal>getPrincipal()</literal> which are implemented by
adding a <classname>SecurityContextHolderAwareRequestFilter</classname> bean to the stack. Defaults to "true".
</para>
</section>
<section xml:id="nsa-path-type">
<title><literal>path-type</literal></title>
<para>
Controls whether URL patterns are interpreted as ant paths (the default) or regular expressions. In practice
this sets a particular <interfacename>UrlMatcher</interfacename> instance on the <classname>FilterChainProxy</classname>.
</para>
</section>
<section xml:id="nsa-lowercase-comparisons">
<title><literal>lowercase-comparisons</literal></title>
<para>
Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified,
defaults to "true"
</para>
</section>
<section xml:id="session-fixation-protection">
<title><literal>session-fixation-protection</literal></title>
<para>
Indicates whether an existing session should be invalidated when a user authenticates and a new session started.
If set to "none" no change will be made. "newSession" will create a new empty session.
"migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession".
</para>
<para>
If enabled this will add a <classname>SessionFixationProtectionFilter</classname> to the stack. The session fixation protection
options on namespace-created instances of <classname>AbstractAuthenticationProcessingFilter</classname> will also be set appropriately.
</para>
</section>
<section xml:id="nsa-realm">
<title><literal>realm</literal></title>
<para>
Sets the realm name used for basic authentication (if enabled). Corresponds to the <literal>realmName</literal> proerty on
<classname>BasicProcessingFilterEntryPoint</classname>.
</para>
</section>
<section xml:id="nsa-entry-point-ref">
<title><literal>entry-point-ref</literal></title>
<para>
Normally the <interfacename>AuthenticationEntryPoint</interfacename> used will be set depending on which
authentication mechanisms have been configured. This attribute allows this behaviour to be overridden
by defining a customized <interfacename>AuthenticationEntryPoint</interfacename> bean which will start the authentication
process.
</para>
</section>
<section xml:id="nsa-access-decision-manager-ref">
<title><literal>access-decision-manager-ref</literal></title>
<para>
Optional attribute specifying the ID of the <interfacename>AccessDecisionManager</interfacename> implementation which should be
used for authorizing HTTP requests. By default an <classname>AffirmativeBased</classname> implementation is used for with
a <classname>RoleVoter</classname> and an <classname>AuthenticatedVoter</classname>.
</para>
</section>
<section xml:id="nsa-access-denied-page">
<title><literal>access-denied-page</literal></title>
<para>
Allows the access denied page to be set (the user will be redirected here if an
<exceptionname>AccessDeniedException</exceptionname> is raised). Corresponds to the
<literal>errorPage</literal> property set on the <classname>AccessDeniedHandlerImpl</classname> which is
used by the <classname>ExceptionTranslationFilter</classname>.
</para>
</section>
<section xml:id="nsa-once-per-request">
<title><literal>once-per-request</literal></title>
<para>
Corresponds to the <literal>observeOncePerRequest</literal> property of
<classname>FilterSecurityInterceptor</classname>. Defaults to "true".
</para>
</section>
<section xml:id="create-session">
<title><literal>create-session</literal></title>
<para>
Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Other options are "always" and "never".
The setting of this attribute affect the <literal>allowSessionCreation</literal> and <literal>forceEagerSessionCreation</literal>
properties of <classname>HttpSessionContextIntegrationFilter</classname>. <literal>allowSessionCreation</literal> will always be true unless
this attribute is set to "never". <literal>forceEagerSessionCreation</literal> is "false" unless it is set to "always".
So the default configuration allows session creation but does not force it. The exception is if concurrent session control is enabled,
when <literal>forceEagerSessionCreation</literal> will be set to true, regardless of what the setting is here. Using "never" would
then cause an exception during the initialization of <classname>HttpSessionContextIntegrationFilter</classname>.
</para>
</section>
</section>
<section>
<title>The <literal>&lt;intercept-url&gt;</literal> Element</title>
<para>
This element is used to define the set of URL patterns that the application is interested in
and to configure how they should be handled. It is used to construct the
<interfacename>FilterInvocationDefinitionSource</interfacename> used by the <classname>FilterSecurityInterceptor</classname> and
to exclude particular patterns from the filter chain entirely (by setting the attribute <literal>filters="none"</literal>).
It is also responsible for configuring a <classname>ChannelProcessingFilter</classname> if particular URLs need to be accessed
by HTTPS, for example.
</para>
<section xml:id="nsa-pattern">
<title><literal>pattern</literal></title>
<para>
The pattern which defines the URL path. The content will depend on the <literal>path-type</literal> attribute from the
containing http element, so will default to ant path syntax.
</para>
</section>
<section xml:id="nsa-method">
<title><literal>method</literal></title>
<para>
The HTTP Method which will be used in combination with the pattern to match an incoming request. If omitted, any method will match.
</para>
</section>
<section xml:id="nsa-access">
<title><literal>access</literal></title>
<para>
Lists the access attributes which will be stored in the <interfacename>FilterInvocationDefinitionSource</interfacename> for the defined
URL pattern/method combination. This should be a comma-separated list of the attributes (such as role names).
</para>
</section>
<section xml:id="nsa-requires-channel">
<title><literal>requires-channel</literal></title>
<para>
Can be "http" or "https" depending on whether a particular URL pattern should be accessed over HTTP or HTTPS respectively. Alternatively
the value "any" can be used when there is no preference. If this attribute is present on any <literal>&lt;intercept-url&gt;</literal>
element, then a <classname>ChannelProcessingFilter</classname> will be added to the filter stack and its additional dependencies added
to the application context. See the chapter on <link xlink:href="#channel-security-config">channel security</link> for an
example configuration using traditional beans.
</para>
<para>
If a <literal>&lt;port-mappings&gt;</literal> configuration is added, this will be used to by the <classname>SecureChannelProcessor</classname>
and <classname>InsecureChannelProcessor</classname> beans to determine the ports used for redirecting to HTTP/HTTPS.
</para>
</section>
</section>
<section>
<title>The <literal>&lt;port-mappings&gt;</literal> Element</title>
<para>
By default, an instance of <classname>PortMapperImpl</classname> will be added to the configuration for use in redirecting
to secure and insecure URLs. This element can optionally be used to override the default mappings which that class defines. Each
child <literal>&lt;port-mapping&gt;</literal> element defines a pair of HTTP:HTTPS ports. The default mappings are 80:443
and 8080:8443. An example of overriding these can be found in the <link xlink:href="#ns-requires-channel">namespace introduction</link>.
</para>
</section>
<section xml:id="nsa-form-login">
<title>The <literal>&lt;form-login&gt;</literal> Element</title>
<para>
Used to add an <classname>UsernamePasswordAuthenticationProcessingFilter</classname> to the filter stack and an
<classname>LoginUrlAuthenticationEntryPoint</classname> to the application context to provide authentication
on demand. This will always take precedence over other namespace-created entry points.
If no attributes are supplied, a login page will be generated automatically at the URL "/spring-security-login"
<footnote><para>This feature is really just provided for convenience and is not intended for production (where a
view technology will have been chosen and can be used to render a customized login page). The class
<classname>DefaultLoginPageGeneratingFilter</classname> is responsible for rendering the login
page and will provide login forms for both normal form login and/or OpenID if required.</para></footnote>
The behaviour can be customized using the following attributes.
</para>
<section>
<title><literal>login-page</literal></title>
<para>
The URL that should be used to render the login page. Maps to the <literal>loginFormUrl</literal>
property of the <classname>LoginUrlAuthenticationEntryPoint</classname>. Defaults to
"/spring-security-login".
</para>
</section>
<section>
<title><literal>login-processing-url</literal></title>
<para>
Maps to the <literal>filterProcessesUrl</literal> property of <classname>UsernamePasswordAuthenticationProcessingFilter</classname>.
The default value is "/j_spring_security_check".
</para>
</section>
<section>
<title><literal>default-target-url</literal></title>
<para>Maps to the <literal>defaultTargetUrl</literal> property of <classname>UsernamePasswordAuthenticationProcessingFilter</classname>. If
not set, the default value is "/" (the application root). A user will be taken to this URL after logging in, provided they
were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL.
</para>
</section>
<section>
<title><literal>always-use-default-target</literal></title>
<para>
If set to "true", the user will always start at the value given by <literal>default-target-url</literal>, regardless of how
they arrived at the login page. Maps to the <literal>alwaysUseDefaultTargetUrl</literal> property of
<classname>UsernamePasswordAuthenticationProcessingFilter</classname>. Default value is "false".
</para>
</section>
<section>
<title><literal>authentication-failure-url</literal></title>
<para>
Maps to the <literal>authenticationFailureUrl</literal> property of <classname>UsernamePasswordAuthenticationProcessingFilter</classname>.
Defines the URL the browser will be redirected to on login failure. Defaults to "/spring_security_login?login_error", which will
be automatically handled by the automatic login page generator, re-rendering the login page with an error message.
</para>
</section>
</section>
<section xml:id="nsa-http-basic">
<title>The <literal>&lt;http-basic&gt;</literal> Element</title>
<para>
Adds a <classname>BasicProcessingFilter</classname> and <classname>BasicProcessingFilterEntryPoint</classname> to the
configuration. The latter will only be used as the configuration entry point if form-based login is not enabled.
</para>
</section>
<section xml:id="nsa-remember-me">
<title>The <literal>&lt;remember-me&gt;</literal> Element</title>
<para>
Adds the <classname>RememberMeProcessingFilter</classname> to the stack. This in turn will
be configured with either a <classname>TokenBasedRememberMeServices</classname>, a <classname>PersistentTokenBasedRememberMeServices</classname>
or a user-specified bean implementing <interfacename>RememberMeServices</interfacename> depending on the attribute settings.
</para>
<section>
<title><literal>data-source-ref</literal></title>
<para>
If this is set, <classname>PersistentTokenBasedRememberMeServices</classname> will be used and configured with
a <classname>JdbcTokenRepositoryImpl</classname> instance.
</para>
</section>
<section>
<title><literal>token-repository-ref</literal></title>
<para>
Configures a <classname>PersistentTokenBasedRememberMeServices</classname> but allows the use of a custom
<interfacename>PersistentTokenRepository</interfacename> bean.
</para>
</section>
<section>
<title><literal>services-ref</literal></title>
<para>
Allows complete control of the <interfacename>RememberMeServices</interfacename> implementation that will be used
by the filter. The value should be the Id of a bean in the application context which implements this interface.
</para>
</section>
<section>
<title><literal>token-repository-ref</literal></title>
<para>
Configures a <classname>PersistentTokenBasedRememberMeServices</classname> but allows the use of a custom
<interfacename>PersistentTokenRepository</interfacename> bean.
</para>
</section>
<section>
<title>The <literal>key</literal> Attribute</title>
<para>Maps to the "key" property of <classname>AbstractRememberMeServices</classname>. Should be set to a unique
value to ensure that remember-me cookies are only valid within the one application <footnote><para>This doesn't affect
the use of <classname>PersistentTokenBasedRememberMeServices</classname>, where the tokens are stored on the server side.</para></footnote>.
</para>
</section>
<section>
<title><literal>token-validity-seconds</literal></title>
<para>
Maps to the <literal>tokenValiditySeconds</literal> property of <classname>AbstractRememberMeServices</classname>. Specifies the period
in seconds for which the remember-me cookie should be valid. By default it will be valid for 14 days.
</para>
</section>
<section>
<title><literal>user-service-ref</literal></title>
<para>
The remember-me services implementations require access to a <interfacename>UserDetailsService</interfacename>, so there has to be
one defined in the application context. If there is only one, it will be selected and used automatically by the namespace configuration.
If there are multiple instances, you can specify a bean Id explicitly using this attribute.
</para>
</section>
</section>
<section xml:id="nsa-concurrent-session-control">
<title>The <literal>&lt;concurrent-session-control&gt;</literal> Element</title>
<para>
Adds support for concurrent session control, allowing limits to be placed on the number of active sessions a user can have.
A <classname>ConcurrentSessionFilter</classname> will be created, along with a <classname>ConcurrentSessionControllerImpl</classname>
and an instance of <interfacename>SessionRegistry</interfacename> (a <classname>SessionRegistryImpl</classname> instance unless the user
wishes to use a custom bean). The controller is registered with the namespace's <interfacename>AuthenticationManager</interfacename>
(<classname>ProviderManager</classname>). Other namespace-created beans which require a reference to the <interfacename>SessionRegistry</interfacename>
will automatically have it injected.
</para>
<para>
Note that the <literal>forceEagerSessionCreation</literal> of <classname>HttpSessionContextIntegrationFilter</classname> will
be set to <literal>true</literal> if concurrent session control is in use.
</para>
<section>
<title>The <literal>max-sessions</literal> attribute</title>
<para>Maps to the <literal>maximumSessions</literal> property of <classname>ConcurrentSessionControllerImpl</classname>.</para>
</section>
<section>
<title>The <literal>expired-url</literal> attribute</title>
<para>
The URL a user will be redirected to if they attempt to use a session which has been "expired" by
the concurrent session controller because the user has exceeded the number of allowed sessions and has logged
in again elsewhere. Should be set unless <literal>exception-if-maximum-exceeded</literal> is set.
If no value is supplied, an expiry message will just be written directly back to the response.
</para>
</section>
<section>
<title>The <literal>exception-if-maximum-exceeded</literal> attribute</title>
<para>If set to "true" a <exceptionname>ConcurrentLoginException</exceptionname> should be raised when a user
attempts to exceed the maximum allowed number of sessions. The default behaviour is to expire the original session.
</para>
</section>
<section>
<title>The <literal>session-registry-alias</literal> and <literal>session-registry-ref</literal> attributes</title>
<para>
The user can supply their own <interfacename>SessionRegistry</interfacename> implementation using the
<literal>session-registry-ref</literal> attribute. The other concurrent session control beans will be wired
up to use it.
</para>
<para>
It can also be useful to have a reference to the internal session registry for use in your own
beans or an admin interface. You can expose the interal bean using the <literal>session-registry-alias</literal>
attribute, giving it a name that you can use elsewhere in your configuration.
</para>
</section>
</section>
<section xml:id="nsa-anonymous">
<title>The <literal>&lt;anonymous&gt;</literal> Element</title>
<para>
Adds an <classname>AnonymousProcessingFilter</classname> to the stack and an <classname>AnonymousAuthenticationProvider</classname>.
Required if you are using the <literal>IS_AUTHENTICATED_ANONYMOUSLY</literal> attribute.
</para>
</section>
<section xml:id="nsa-x509">
<title>The <literal>&lt;x509&gt;</literal> Element</title>
<para>
Adds support for X.509 authentication. An <classname>X509PreAuthenticatedProcessingFilter</classname> will be
added to the stack and a <classname>PreAuthenticatedProcessingFilterEntryPoint</classname> bean will be created. The
latter will only be used if no other authentication mechanisms are in use (it's only functionality is to return an HTTP
403 error code). A <classname>PreAuthenticatedAuthenticationProvider</classname> will also be created which delegates the
loading of user authorities to a <interfacename>UserDetailsService</interfacename>.
</para>
<section>
<title>The <literal>subject-principal-regex</literal> attribute</title>
<para>
Defines a regular expression which will be used to extract the username from the certificate (for use with the
<interfacename>UserDetailsService</interfacename>).
</para>
</section>
<section>
<title>The <literal>user-service-ref</literal> attribute</title>
<para>
Allows a specific <interfacename>UserDetailsService</interfacename> to be used with X.509 in the case where
multiple instances are configured. If not set, an attempt will be made to locate a suitable instance automatically and
use that.
</para>
</section>
</section>
<section xml:id="nsa-openid-login">
<title>The <literal>&lt;openid-login&gt;</literal> Element</title>
<para>
Similar to <literal>&lt;form-login&gt;</literal> and has the same attributes. The default value for <literal>login-processing-url</literal>
is "/j_spring_openid_security_check". An <classname>OpenIDUsernamePasswordAuthenticationProcessingFilter</classname> and <classname>OpenIDAuthenticationProvider</classname>
will be registered. The latter requires a reference to a <interfacename>UserDetailsService</interfacename>. Again, this can be
specified by Id, using the <literal>user-service-ref</literal> attribute, or will be located automatically in the application context.
</para>
</section>
<section xml:id="nsa-logout">
<title>The <literal>&lt;logout&gt;</literal> Element</title>
<para>
Adds a <classname>LogoutFilter</classname> to the filter stack. This is configured
with a <classname>SecurityContextLogoutHandler</classname>.
</para>
<section>
<title>The <literal>logout-url</literal> attribute</title>
<para>
The URL which will cause a logout (i.e. which will be processed by the filter). Defaults to "/j_spring_security_logout".
</para>
</section>
<section>
<title>The <literal>logout-success-url</literal> attribute</title>
<para>
The destination URL which the user will be taken to after logging out. Defaults to "/".
</para>
</section>
<section>
<title>The <literal>invalidate-session</literal> attribute</title>
<para>
Maps to the <literal>invalidateHttpSession</literal> of the <classname>SecurityContextLogoutHandler</classname>.
Defaults to "true", so the session will be invalidated on logout.
</para>
</section>
</section>
</section>
<section>
<title>Authentication Services</title>
<para>
If you are using the namespace, an <interfacename>AuthenticationManager</interfacename> is
automatically registered and will be used by all the namespace-created beans which need to reference it.
The bean is an instance of Spring Security's <classname>ProviderManager</classname> class, which needs to be
configured with a list of one or more <interfacename>AuthenticationProvider</interfacename> instances.
These can either be created using syntax elements provided by the namespace, or they can be
standard bean definitions, marked for addition to the list using the
<literal>custom-authentication-provider</literal> element.
</para>
<section>
<title>The &lt;authentication-provider&gt; Element</title>
<para>
This element is basically a shorthand syntax for configuring a <link xlink:href="#dao-provider"><classname>DaoAuthenticationProvider</classname></link>.
<classname>DaoAuthenticationProvider</classname> loads user information from a <interfacename>UserDetailsService</interfacename> and
compares the username/password combination with the values supplied at login. The <interfacename>UserDetailsService</interfacename> instance
can be defined either by using an available namespace element (<literal>jdbc-user-service</literal> or by using the <literal>user-service-ref</literal>
attribute to point to a bean defined elsewhere in the application context). You can find examples of these variations in the
<link xlink:href="#ns-auth-providers">namespace introduction</link>.
</para>
</section>
<section>
<title>Using <literal>&lt;custom-authentication-provider&gt;</literal> to register an AuthenticationProvider</title>
<para>
If you have written your own <interfacename>AuthenticationProvider</interfacename> implementation (or want
to configure one of Spring Security's own implementations as a traditional bean for some reason, then
you can use the following syntax to add it to the internal <classname>ProviderManager</classname>'s list:
<programlisting><![CDATA[
<bean id="myAuthenticationProvider" class="com.something.MyAuthenticationProvider">
<security:custom-authentication-provider />
</bean>
]]></programlisting>
</para>
</section>
<section>
<title>The <literal>&lt;authentication-manager&gt;</literal> Element</title>
<para>
Since the <interfacename>AuthenticationManager</interfacename> will be automatically registered in the application
context, this element is entirely optional. It allows you to define an alias name for the internal instance for use
in your own configuration and also to supply a link to a <interfacename>ConcurrentSessionController</interfacename>
if you are configuring concurrent session control yourself rather than through the namespace (a rare requirement).
Its use is described in the <link xlink:href="#ns-auth-manager">namespace introduction</link>.
</para>
</section>
</section>
<section>
<title>Method Security</title>
<section>
<title>The <literal>&lt;global-method-security&gt;</literal> Element</title>
<para>
This element is the primary means of adding support for securing methods on Spring Security beans. Methods can
be secured by the use of annotations (defined at the interface or class level) or by defining a set of
pointcuts as child elements, using AspectJ syntax.
</para>
<para>
Method security uses the same <interfacename>AccessDecisionManager</interfacename> configuration as web security,
but this can be overridden as explained above <xref xlink:href="#nsa-access-decision-manager-ref"/>, using the same
attribute.
</para>
<section>
<title>The <literal>&lt;secured-annotations&gt;</literal> and <literal>&lt;jsr250-annotations&gt;</literal> Attributes</title>
<para>
Setting these to "true" will enable support for Spring Security's own <literal>@Secured</literal> annotations and
JSR-250 annotations, respectively. They are both disabled by default. Use of JSR-250 annotations also adds a
<classname>Jsr250Voter</classname> to the <interfacename>AccessDecisionManager</interfacename>, so you need to
make sure you do this if you are using a custom implementation and want to use these annotations.
</para>
</section>
<section>
<title>Securing Methods using <literal>&lt;protect-pointcut&gt;</literal></title>
<para>
Rather than defining security attributes on an individual method or class basis using the
<literal>@Secured</literal> annotation, you can define cross-cutting security constraints across whole
sets of methods and interfaces in your service layer using the <literal>&lt;protect-pointcut&gt;</literal>
element. This has two attributes:
<itemizedlist>
<listitem><para><literal>expression</literal> - the pointcut expression</para></listitem>
<listitem><para><literal>access</literal> - the security attributes which apply</para></listitem>
</itemizedlist>
You can find an example in the <link xlink:href="#ns-protect-pointcut">namespace introduction</link>.
</para>
</section>
<section xml:id="nsa-custom-after-invocation">
<title>The <literal>&lt;custom-after-invocation-provider&gt;</literal> Element</title>
<para>
This element can be used to decorate an <interfacename>AfterInvocationProvider</interfacename>
for use by the security interceptor maintained by the <literal>&lt;global-method-security&gt;</literal>
namespace.
</para>
<para>
The syntax is the same as for <literal>&lt;custom-authentication-provider&gt;</literal>.
</para>
</section>
</section>
<section>
<title>LDAP Namespace Options</title>
<para>
LDAP is covered in some details in <link xlink:href="#ldap">its own chapter</link>. We will expand on that
here with some explanation of how the namespace options map to Spring beans. The LDAP implementation uses
Spring LDAP extensively, so some familiarity with that project's API may be useful.
</para>
<section>
<title>Defining the LDAP Server using the <literal>&lt;ldap-server&gt;</literal> Element</title>
<para>
This element sets up a Spring LDAP <interfacename>ContextSource</interfacename> for use by the
other LDAP beans, defining the location of the LDAP server and other information (such as a username
and password, if it doesn't allow anonymous access) for connecting to it. It can also be used to
create an embedded server for testing.
Details of the syntax for both options are covered in the <link xlink:href="#ldap-server">LDAP chapter</link>.
The actual <interfacename>ContextSource</interfacename> implementation is
<classname>DefaultSpringSecurityContextSource</classname> which extends Spring LDAP's
<classname>LdapContextSource</classname> class. The <literal>manager-dn</literal> and <literal>manager-password</literal>
attributes map to the latter's <literal>userDn</literal> and <literal>password</literal> properties respectively.
</para>
<para>
If you only have one server defined in your application context, the other LDAP namespace-defined beans
will use it automatically. Otherwise, you can give the element an "id" attribute and refer to it from other
namespace beans using the <literal>server-ref</literal> attribute. This is actually the bean Id of the
<literal>ContextSource</literal> instance, if you want to use it in other traditional Spring beans.
</para>
</section>
<section>
<title>The <literal>&lt;ldap-provider&gt;</literal> Element</title>
<para>
This element is shorthand for the creation of an <classname>LdapAuthenticationProvider</classname> instance.
By default this will be configured with a <classname>BindAuthenticator</classname> instance and a
<classname>DefaultAuthoritiesPopulator</classname>.
</para>
<section>
<title>The <literal>user-dn-pattern</literal> Attribute</title>
<para>
If your users are at a fixed location in the directory (i.e. you can work out the DN
directly from the username without doing a directory search), you can use this attribute
to map directly to the DN. It maps directly to the <literal>userDnPatterns</literal>
property of <classname>AbstractLdapAuthenticator</classname>.
</para>
</section>
<section>
<title>The <literal>user-search-base</literal> and <literal>user-search-filter</literal> Attributes</title>
<para>
If you need to perform a search to locate the user in the directory, then you
can set these attributes to control the search. The <classname>BindAuthenticator</classname> will be configured
with a <classname>FilterBasedLdapUserSearch</classname> and the attribute values map directly to the first two
arguments of that bean's constructor. If these attributes aren't set and no <literal>user-dn-pattern</literal>
has been supplied as an alternative, then the default search values of <literal>user-search-filter="(uid={0})"</literal>
and <literal>user-search-base=""</literal> will be used.
</para>
</section>
<section>
<title><literal>group-search-filter</literal>, <literal>group-search-base</literal>, <literal>group-role-attribute</literal> and <literal>role-prefix</literal> Attributes</title>
<para>
The value of <literal>group-search-base</literal> is mapped to the <literal>groupSearchBase</literal> constructor argument
of <classname>DefaultAuthoritiesPopulator</classname> and defaults to "ou=groups". The default filter value is
"(uniqueMember={0})", which assumes that the entry is of type "groupOfUniqueNames". <literal>group-role-attribute</literal>
maps to the <literal>groupRoleAttribute</literal> attribute and defaults to "cn". Similarly <literal>role-prefix</literal>
maps to <literal>rolePrefix</literal> and defaults to "ROLE_".
</para>
</section>
<section>
<title>The <literal>&lt;password-compare&gt;</literal> Element</title>
<para>
This is used as child element to <literal>&lt;ldap-provider&gt;</literal> and switches
the authentication strategy from <classname>BindAuthenticator</classname> to
<classname>PasswordComparisonAuthenticator</classname>. This can optionally be supplied with a
<literal>hash</literal> attribute or with a child <literal>&lt;password-encoder&gt;</literal>
element to hash the password before submitting it to the directory for comparison.
</para>
</section>
</section>
<section>
<title>The <literal>&lt;ldap-user-service&gt;</literal> Element</title>
<para>
This element configures an LDAP <interfacename>UserDetailsService</interfacename>. The class used
is <classname>LdapUserDetailsService</classname> which is a combination of a <classname>FilterBasedLdapUserSearch</classname>
and a <classname>DefaultAuthoritiesPopulator</classname>. The attributes it supports have the same usage as in
<literal>&lt;ldap-provider&gt;</literal>.
</para>
</section>
</section>
</section>
</appendix>
@@ -0,0 +1,436 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authorization-common" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Common Authorization Concepts</title></info>
<section xml:id="authorities">
<info><title>Authorities</title></info>
<para>As briefly mentioned in the Authentication section, all
<interfacename>Authentication</interfacename> implementations are required to
store an array 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 "read" 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 "complex" and
<literal>getAuthority()</literal> must return
<literal>null</literal>.</para>
<para>An example of a "complex" <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 complex, 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="pre-invocation">
<info>
<title>Pre-Invocation Handling</title>
</info>
<para>
As we'll see 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>
<title>The AccessDecisionManager</title>
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the
<classname>AbstractSecurityInterceptor</classname> and is responsible for
making final access control decisions. The
<interfacename>AccessDecisionManager</interfacename> interface contains three
methods:
<programlisting>
void decide(Authentication authentication, Object secureObject, List&lt;ConfigAttribute&gt; config) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
</programlisting>
As can be seen from the first method, the
<interfacename>AccessDecisionManager</interfacename> is passed via method
parameters all information that is likely to be of value in assessing
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>
<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 role="fo">
<imagedata align="center" fileref="resources/images/AccessDecisionVoting.gif" format="GIF"/>
</imageobject>
<imageobject role="html">
<imagedata align="center" fileref="images/AccessDecisionVoting.gif" format="GIF"/>
</imageobject>
</mediaobject>
</figure>
<para>Using this approach, a series of
<interfacename>AccessDecisionVoter</interfacename> implementations are polled on
an authorization decision. The
<interfacename>AccessDecisionManager</interfacename> then decides whether or not
to throw an <literal>AccessDeniedException</literal> based on its
assessment of the votes.</para>
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three
methods:
<programlisting>
int vote(Authentication authentication, Object object, List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
</programlisting>
Concrete implementations return an <literal>int</literal>, with
possible values being reflected in the
<interfacename>AccessDecisionVoter</interfacename> static fields
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal>
and <literal>ACCESS_GRANTED</literal>. A voting implementation will
return <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an
authorization decision. If it does have an opinion, it must return
either <literal>ACCESS_DENIED</literal> or
<literal>ACCESS_GRANTED</literal>.</para>
<para>There are three concrete
<interfacename>AccessDecisionManager</interfacename>s provided with Spring
Security that tally the votes. The <literal>ConsensusBased</literal>
implementation will grant or deny access based on the consensus of
non-abstain votes. Properties are provided to control behavior in the
event of an equality of votes or if all votes are abstain. The
<literal>AffirmativeBased</literal> implementation will grant access
if one or more <literal>ACCESS_GRANTED</literal> votes were received
(i.e. a deny vote will be ignored, provided there was at least one grant
vote). Like the <literal>ConsensusBased</literal> implementation,
there is a parameter that controls the behavior if all voters abstain.
The <literal>UnanimousBased</literal> provider expects unanimous
<literal>ACCESS_GRANTED</literal> votes in order to grant access,
ignoring abstains. It will deny access if there is any
<literal>ACCESS_DENIED</literal> vote. Like the other implementations,
there is a parameter that controls the behaviour if all voters
abstain.</para>
<para>It is possible to implement a custom
<interfacename>AccessDecisionManager</interfacename> that tallies votes
differently. For example, votes from a particular
<interfacename>AccessDecisionVoter</interfacename> might receive additional
weighting, whilst a deny vote from a particular voter may have a veto
effect.</para>
<section>
<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 ConfigAttribute 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
<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.
<literal>RoleVoter</literal> is case sensitive on comparisons as well
as the <literal>ROLE_</literal> prefix.</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="after-invocation">
<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 role="fo">
<imagedata align="center" fileref="resources/images/AfterInvocation.gif" format="GIF"/>
</imageobject>
<imageobject role="html">
<imagedata align="center" fileref="images/AfterInvocation.gif" format="GIF"/>
</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. Let's now consider our ACL-aware
implementations of <literal>AfterInvocationProvider</literal>.</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>
<section xml:id="after-invocation-acl-aware"><info><title>ACL-Aware AfterInvocationProviders</title></info>
<!-- TODO: Move to ACL section and add reference here -->
<para>A common services layer method we've all written at one stage
or another looks like this:</para>
<para><programlisting>public Contact getById(Integer id);</programlisting></para>
<para>Quite often, only principals with permission to read the
<literal>Contact</literal> should be allowed to obtain it. In this
situation the <interfacename>AccessDecisionManager</interfacename> approach
provided by the <classname>AbstractSecurityInterceptor</classname> will
not suffice. This is because the identity of the
<literal>Contact</literal> is all that is available before the
secure object is invoked. The
<classname>AclEntryAfterInvocationProvider</classname> delivers a solution,
and is configured as follows:
<programlisting><![CDATA[
<bean id="afterAclRead"
class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationProvider">
<constructor-arg ref="aclService"/>
<constructor-arg>
<list>
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
]]></programlisting>
In the above example, the <literal>Contact</literal> will be
retrieved and passed to the
<classname>AclEntryAfterInvocationProvider</classname>. The provider
will thrown an <classname>AccessDeniedException</classname> if one of
the listed <literal>requirePermission</literal>s is not held by the
<interfacename>Authentication</interfacename>. The
<classname>AclEntryAfterInvocationProvider</classname> queries the
acl service to determine the ACL that applies for
this domain object to this <interfacename>Authentication</interfacename>.</para>
<para>Similar to the
<classname>AclEntryAfterInvocationProvider</classname> is
<classname>AclEntryAfterInvocationCollectionFilteringProvider</classname>.
It is designed to remove <literal>Collection</literal> or array
elements for which a principal does not have access. It never thrown
an <classname>AccessDeniedException</classname> - simply silently
removes the offending elements. The provider is configured as
follows:
<programlisting><![CDATA[
<bean id="afterAclCollectionRead"
class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
<constructor-arg ref="aclService"/>
<constructor-arg>
<list>
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
]]> </programlisting>
As you can imagine, the returned <literal>Object</literal>
must be a <literal>Collection</literal> or array for this provider
to operate. It will remove any element if the
<literal>AclManager</literal> indicates the
<interfacename>Authentication</interfacename> does not hold one of the listed
<literal>requirePermission</literal>s.</para>
<para>The Contacts sample application demonstrates these two
<literal>AfterInvocationProvider</literal>s.</para>
</section>
</section>
<section xml:id="authorization-taglibs">
<info><title>Authorization Tag Libraries</title></info>
<para><literal>AuthorizeTag</literal> is used to include content if
the current principal holds certain
<interfacename>GrantedAuthority</interfacename>s.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AuthorizeTag</literal>:</para>
<para><programlisting>
<![CDATA[
<security:authorize ifAllGranted="ROLE_SUPERVISOR">
<td>
<a href="del.htm?id=<c:out value="${contact.id}"/>">Del</a>
</td>
</security:authorize>
]]></programlisting></para>
<para>This tag would cause the tag's body to be output if the
principal has been granted ROLE_SUPERVISOR.</para>
<para>The <literal>security:authorize</literal> tag declares the
following attributes:</para>
<para><itemizedlist spacing="compact">
<listitem>
<para><literal>ifAllGranted</literal>: All the listed roles must
be granted for the tag to output its body.</para>
</listitem>
<listitem>
<para><literal>ifAnyGranted</literal>: Any of the listed roles
must be granted for the tag to output its body.</para>
</listitem>
<listitem>
<para><literal>ifNotGranted</literal>: None of the listed roles
must be granted for the tag to output its body.</para>
</listitem>
</itemizedlist></para>
<para>You'll note that in each attribute you can list multiple roles.
Simply separate the roles using a comma. The
<literal>authorize</literal> tag ignores whitespace in
attributes.</para>
<para>The tag library logically ANDs all of it's parameters together.
This means that if you combine two or more attributes, all attributes
must be true for the tag to output it's body. Don't add an
<literal>ifAllGranted="ROLE_SUPERVISOR"</literal>, followed by an
<literal>ifNotGranted="ROLE_SUPERVISOR"</literal>, or you'll be
surprised to never see the tag's body.</para>
<para>By requiring all attributes to return true, the authorize tag
allows you to create more complex authorization scenarios. For
example, you could declare an
<literal>ifAllGranted="ROLE_SUPERVISOR"</literal> and an
<literal>ifNotGranted="ROLE_NEWBIE_SUPERVISOR"</literal> in the same
tag, in order to prevent new supervisors from seeing the tag body.
However it would no doubt be simpler to use
<literal>ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR"</literal> rather
than inserting NOT conditions into your design.</para>
<para>One last item: the tag verifies the authorizations in a specific
order: first <literal>ifNotGranted</literal>, then
<literal>ifAllGranted</literal>, and finally, <literal>if
AnyGranted</literal>.</para>
<para><literal>AccessControlListTag</literal> is used to include
content if the current principal has an ACL to the indicated domain
object.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AccessControlListTag</literal>:
<programlisting><![CDATA[
<security:accesscontrollist domainObject="${contact}" hasPermission="8,16">
<td><a href="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</a></td>
</security:accesscontrollist>
]]></programlisting>
This tag would cause the tag's body to be output if the
principal holds either permission 16 or permission 1 for the "contact"
domain object. The numbers are actually integers that are used with
<literal>BasePermission</literal> bit masking. Please refer to the ACL
section of this reference guide to understand more about the ACL
capabilities of Spring Security.</para>
<para><literal>AclTag</literal> is part of the old ACL module and
should be considered deprecated. For the sake of historical reference,
works exactly the samae as
<literal>AccessControlListTag</literal>.</para>
</section>
</chapter>
@@ -0,0 +1,60 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="basic"><info><title>BASIC Authentication Mechanism</title></info>
<section xml:id="basic-overview"><info><title>Overview</title></info>
<para>Spring Security provides a
<literal>BasicProcessingFilter</literal> which is capable of
processing basic authentication credentials presented in HTTP headers.
This can be used for authenticating calls made by Spring remoting
protocols (such as Hessian and Burlap), as well as normal user agents
(such as Internet Explorer and Navigator). The standard governing HTTP
Basic Authentication is defined by RFC 1945, Section 11, and the
<literal>BasicProcessingFilter</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>
</section>
<section xml:id="basic-config"><info><title>Configuration</title></info>
<para>To implement HTTP Basic Authentication, it is necessary to
define <literal>BasicProcessingFilter</literal> in the filter chain.
The application context will need to define the
<literal>BasicProcessingFilter</literal> and its required
collaborator:</para>
<para><programlisting language="xml">
&lt;bean id="basicProcessingFilter" class="org.springframework.security.web.authentication.www.BasicProcessingFilter"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="authenticationEntryPoint"&gt;&lt;ref bean="authenticationEntryPoint"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint"&gt;
&lt;property name="realmName"&gt;&lt;value&gt;Name Of Your Realm&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</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
<literal>BasicProcessingFilterEntryPoint</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>.</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,
as discussed in the previous paragraph</para>
</section>
</chapter>
@@ -0,0 +1,461 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CAS Authentication</title>
<section xml:id="cas-overview">
<title>Overview</title>
<para>JA-SIG produces an enterprise-wide single sign on system known
as CAS. Unlike other initiatives, JA-SIG's Central Authentication
Service is open source, widely used, simple to understand, platform
independent, and supports proxy capabilities. Spring Security fully
supports CAS, and provides an easy migration path from
single-application deployments of Spring Security through to
multiple-application deployments secured by an enterprise-wide CAS
server.</para>
<para>You can learn more about CAS at
<literal>http://www.ja-sig.org/products/cas/</literal>. You will also need
to visit this site to download the CAS Server files.</para>
</section>
<section xml:id="cas-how-it-works">
<info><title>How CAS Works</title></info>
<para>Whilst the CAS web site contains documents that detail
the architecture of CAS, we present the general overview again here
within the context of Spring Security. Spring Security 2.0 supports
CAS 3. At the time of writing, the CAS server was at version 3.2.</para>
<para>Somewhere in your enterprise you will need to setup a CAS
server. The CAS server is simply a standard WAR file, so there isn't
anything difficult about setting up your server. Inside the WAR file
you will customise the login and other single sign on pages displayed
to users.</para>
<para>When deploying a CAS 3.2 server, you will also need to specify an
<literal>AuthenticationHandler</literal> in the
<filename>deployerConfigContext.xml</filename> included with CAS. The
<literal>AuthenticationHandler</literal> has a simple method that
returns a boolean as to whether a given set of Credentials is valid.
Your <literal>AuthenticationHandler</literal> implementation will need
to link into some type of backend authentication repository, such as
an LDAP server or database. CAS itself includes numerous
<literal>AuthenticationHandler</literal>s out of the box to assist
with this. When you download and deploy the server war file, it is set up
to successfully authenticate users who enter a password matching their
username, which is useful for testing.</para>
<para>Apart from the CAS server itself, the other key players are of
course the secure web applications deployed throughout your
enterprise. These web applications are known as "services". There are
two types of services: standard services and proxy services. A proxy
service is able to request resources from other services on behalf of
the user. This will be explained more fully later.</para>
<!--
<section xml:id="cas-sequence">
<title>Spring Security and CAS Interaction Sequence</title>
TODO: Needs reviewed
<para>The basic interaction between a web browser, CAS server and a
Spring Security-secured service is as follows:</para>
<orderedlist inheritnum="ignore" continuation="restarts">
<listitem>
<para>The web user is browsing the service's public pages. CAS or
Spring Security is not involved.</para>
</listitem>
<listitem>
<para>The user eventually requests a page that is either secure or
one of the beans it uses is secure. Spring Security's
<classname>ExceptionTranslationFilter</classname> will detect the
<literal>AuthenticationException</literal>.</para>
</listitem>
<listitem>
<para>Because the user's <interfacename>Authentication</interfacename> object
(or lack thereof) caused an
<literal>AuthenticationException</literal>, the
<classname>ExceptionTranslationFilter</classname> will call the
configured <interfacename>AuthenticationEntryPoint</interfacename>. If using
CAS, this will be the
<literal>CasProcessingFilterEntryPoint</literal> class.</para>
</listitem>
<listitem>
<para>The <literal>CasProcessingFilterEntry</literal> point will
redirect the user's browser to the CAS server. It will also
indicate a <literal>service</literal> parameter, which is the
callback URL for Spring Security service. For example, the URL to
which the browser is redirected might be
<literal>https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_spring_cas_security_check</literal>.</para>
</listitem>
<listitem>
<para>After the user's browser redirects to CAS, they will be
prompted for their username and password. If the user presents a
session cookie which indicates they've previously logged on, they
will not be prompted to login again (there is an exception to this
procedure, which we'll cover later). CAS will use the
<literal>PasswordHandler</literal> (or
<literal>AuthenticationHandler</literal> if using CAS 3.0)
discussed above to decide whether the username and password is
valid.</para>
</listitem>
<listitem>
<para>Upon successful login, CAS will redirect the user's browser
back to the original service. It will also include a
<literal>ticket</literal> parameter, which is an opaque string
representing the "service ticket". Continuing our earlier example,
the URL the browser is redirected to might be
<literal>https://server3.company.com/webapp/j_spring_cas_security_check?ticket=ST-0-ER94xMJmn6pha35CQRoZ</literal>.</para>
</listitem>
<listitem>
<para>Back in the service web application, the
<literal>CasProcessingFilter</literal> is always listening for
requests to <literal>/j_spring_cas_security_check</literal> (this
is configurable, but we'll use the defaults in this introduction).
The processing filter will construct a
<literal>UsernamePasswordAuthenticationToken</literal>
representing the service ticket. The principal will be equal to
<literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>,
whilst the credentials will be the service ticket opaque value.
This authentication request will then be handed to the configured
<interfacename>AuthenticationManager</interfacename>.</para>
</listitem>
<listitem>
<para>The <interfacename>AuthenticationManager</interfacename> implementation
will be the <literal>ProviderManager</literal>, which is in turn
configured with the <literal>CasAuthenticationProvider</literal>.
The <literal>CasAuthenticationProvider</literal> only responds to
<literal>UsernamePasswordAuthenticationToken</literal>s containing
the CAS-specific principal (such as
<literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>)
and <literal>CasAuthenticationToken</literal>s (discussed
later).</para>
</listitem>
<listitem>
<para><literal>CasAuthenticationProvider</literal> will validate
the service ticket using a <literal>TicketValidator</literal>
implementation. Spring Security includes one implementation, the
<literal>CasProxyTicketValidator</literal>. This implementation a
ticket validation class included in the CAS client library. The
<literal>CasProxyTicketValidator</literal> makes an HTTPS request
to the CAS server in order to validate the service ticket. The
<literal>CasProxyTicketValidator</literal> may also include a
proxy callback URL, which is included in this example:
<literal>https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_spring_cas_security_check&amp;ticket=ST-0-ER94xMJmn6pha35CQRoZ&amp;pgtUrl=https://server3.company.com/webapp/casProxy/receptor</literal>.</para>
</listitem>
<listitem>
<para>Back on the CAS server, the proxy validation request will be
received. If the presented service ticket matches the service URL
the ticket was issued to, CAS will provide an affirmative response
in XML indicating the username. If any proxy was involved in the
authentication (discussed below), the list of proxies is also
included in the XML response.</para>
</listitem>
<listitem>
<para>[OPTIONAL] If the request to the CAS validation service
included the proxy callback URL (in the <literal>pgtUrl</literal>
parameter), CAS will include a <literal>pgtIou</literal> string in
the XML response. This <literal>pgtIou</literal> represents a
proxy-granting ticket IOU. The CAS server will then create its own
HTTPS connection back to the <literal>pgtUrl</literal>. This is to
mutually authenticate the CAS server and the claimed service URL.
The HTTPS connection will be used to send a proxy granting ticket
to the original web application. For example,
<literal>https://server3.company.com/webapp/casProxy/receptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&amp;pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH</literal>.
We suggest you use CAS' <literal>ProxyTicketReceptor</literal>
servlet to receive these proxy-granting tickets, if they are
required.</para>
</listitem>
<listitem>
<para>The <literal>CasProxyTicketValidator</literal> will parse
the XML received from the CAS server. It will return to the
<literal>CasAuthenticationProvider</literal> a
<literal>TicketResponse</literal>, which includes the username
(mandatory), proxy list (if any were involved), and proxy-granting
ticket IOU (if the proxy callback was requested).</para>
</listitem>
<listitem>
<para>Next <literal>CasAuthenticationProvider</literal> will call
a configured <literal>CasProxyDecider</literal>. The
<literal>CasProxyDecider</literal> indicates whether the proxy
list in the <literal>TicketResponse</literal> is acceptable to the
service. Several implementations are provided with Spring
Security: <literal>RejectProxyTickets</literal>,
<literal>AcceptAnyCasProxy</literal> and
<literal>NamedCasProxyDecider</literal>. These names are largely
self-explanatory, except <literal>NamedCasProxyDecider</literal>
which allows a <literal>List</literal> of trusted proxies to be
provided.</para>
</listitem>
<listitem>
<para><literal>CasAuthenticationProvider</literal> will next
request a <literal>CasAuthoritiesPopulator</literal> to advise the
<interfacename>GrantedAuthority</interfacename> objects that apply to the user
contained in the <literal>TicketResponse</literal>. Spring
Security includes a <literal>DaoCasAuthoritiesPopulator</literal>
which simply uses the <interfacename>UserDetailsService</interfacename>
infrastructure to find the <interfacename>UserDetails</interfacename> and
their associated <interfacename>GrantedAuthority</interfacename>s. Note that
the password and enabled/disabled status of
<interfacename>UserDetails</interfacename> returned by the
<interfacename>UserDetailsService</interfacename> are ignored, as the CAS
server is responsible for authentication decisions.
<literal>DaoCasAuthoritiesPopulator</literal> is only concerned
with retrieving the <interfacename>GrantedAuthority</interfacename>s.</para>
</listitem>
<listitem>
<para>If there were no problems,
<literal>CasAuthenticationProvider</literal> constructs a
<literal>CasAuthenticationToken</literal> including the details
contained in the <literal>TicketResponse</literal> and the
<interfacename>GrantedAuthority</interfacename>s. The
<literal>CasAuthenticationToken</literal> contains the hash of a
key, so that the <literal>CasAuthenticationProvider</literal>
knows it created it.</para>
</listitem>
<listitem>
<para>Control then returns to
<literal>CasProcessingFilter</literal>, which places the created
<literal>CasAuthenticationToken</literal> into the
<literal>HttpSession</literal> attribute named
<literal>HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY</literal>.</para>
</listitem>
<listitem>
<para>The user's browser is redirected to the original page that
caused the <literal>AuthenticationException</literal>.</para>
</listitem>
<listitem>
<para>As the <interfacename>Authentication</interfacename> object is now in
the well-known location, it is handled like any other
authentication approach. Usually the
<classname>HttpSessionContextIntegrationFilter</classname> will be
used to associate the <interfacename>Authentication</interfacename> object
with the <classname>SecurityContextHolder</classname> for the duration
of each request.</para>
</listitem>
</orderedlist>
<para>It's good that you're still here! It might sound involved, but
you can relax as Spring Security classes hide much of the complexity.
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 <literal>ServiceProperties</literal> bean
to your application context. This represents your service:</para>
<para><programlisting><![CDATA[
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>]]>
</programlisting></para>
<para>The <literal>service</literal> must equal a URL that will be
monitored by the <literal>CasProcessingFilter</literal>. The
<literal>sendRenew</literal> defaults to false, but should be set to
true if your application is particularly sensitive. What this
parameter does is tell the CAS login service that a single sign on
login is unacceptable. Instead, the user will need to re-enter their
username and password in order to gain access to the service.</para>
<para>The following beans should be configured to commence the CAS
authentication process:</para>
<para><programlisting><![CDATA[
<security:authentication-manager alias="authenticationManager"/>
<bean id="casProcessingFilter" class="org.springframework.security.cas.web.CasProcessingFilter">
<security:custom-filter after="CAS_PROCESSING_FILTER"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/casfailed.jsp"/>
<property name="defaultTargetUrl" value="/"/>
</bean>
<bean id="casProcessingFilterEntryPoint"
class="org.springframework.security.cas.web.CasProcessingFilterEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>
]]>
</programlisting></para>
<para>
The <classname>CasProcessingFilterEntryPoint</classname> should be selected to
drive authentication using <link xlink:href="ns-entry-point-ref"><literal>entry-point-ref</literal></link>.
</para>
<para>The <literal>CasProcessingFilter</literal> has very similar
properties to the <literal>UsernamePasswordAuthenticationProcessingFilter</literal>
(used for form-based logins). Each property is
self-explanatory. Note that we've also used the namespace syntax
for setting up an alias to the authentication mnager, since the
<literal>CasProcessingFilter</literal> needs a reference to it.</para>
<para>For CAS to operate, the
<classname>ExceptionTranslationFilter</classname> must have its
<literal>authenticationEntryPoint</literal> property set to the
<literal>CasProcessingFilterEntryPoint</literal> bean.</para>
<para>The <literal>CasProcessingFilterEntryPoint</literal> must refer
to the <literal>ServiceProperties</literal> bean (discussed above),
which provides the URL to the enterprise's CAS login server. This is
where the user's browser will be redirected.</para>
<para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its
collaborators:
<programlisting><![CDATA[
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<security:custom-authentication-provider />
<property name="userDetailsService" ref="userService"/>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:9443/cas" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>
<security:user-service id="userService">
<security:user name="joe" password="joe" authorities="ROLE_USER" />
...
</security:user-service>]]>
</programlisting>
The <classname>CasAuthenticationProvider</classname> uses a <interfacename>UserDetailsService</interfacename>
instance to load the authorities for a user, once they have been authentiated by CAS. We've shown a simple
in-memory setup here.
</para>
<para>The beans are all reasonable self-explanatory if you refer back
to the "How CAS Works" section.</para>
</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
the <literal>proxyCallbackUrl</literal> is set so the service can
receive a proxy-granting ticket. As mentioned above, this is optional
and unnecessary if you do not require proxy-granting tickets. If you
do use this feature, you will need to configure a suitable servlet to
receive the proxy-granting tickets. We suggest you use CAS'
<literal>ProxyTicketReceptor</literal> by adding the following to your
web application's <literal>web.xml</literal>:</para>
<para><programlisting>
&lt;servlet&gt;
&lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
&lt;servlet-class&gt;edu.yale.its.tp.cas.proxy.ProxyTicketReceptor&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
&lt;url-pattern&gt;/casProxy/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
</programlisting></para>
<para>This completes the configuration of CAS. If you haven't made any
mistakes, your web application should happily work within the
framework of CAS single sign on. No other parts of Spring Security
need to be concerned about the fact CAS handled authentication.</para>
<para>There is also a <literal>contacts-cas.war</literal> file in the
sample applications directory. This sample application uses the above
settings and can be deployed to see CAS in operation</para>
</section>
<section xml:id="cas-advanced">
<info><title>Advanced Issues</title></info>
<para>The <literal>CasAuthenticationProvider</literal> distinguishes
between stateful and stateless clients. A stateful client is
considered any that originates via the
<literal>CasProcessingFilter</literal>. A stateless client is any that
presents an authentication request via the
<literal>UsernamePasswordAuthenticationToken</literal> with a
principal equal to
<literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>.</para>
<para>Stateless clients are likely to be via remoting protocols such
as Hessian and Burlap. The <literal>BasicProcessingFilter</literal> is
still used in this case, but the remoting protocol client is expected
to present a username equal to the static string above, and a password
equal to a CAS service ticket. Clients should acquire a CAS service
ticket directly from the CAS server.</para>
<para>Because remoting protocols have no way of presenting themselves
within the context of an <literal>HttpSession</literal>, it isn't
possible to rely on the <literal>HttpSession</literal>'s
<literal>HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY</literal>
attribute to locate the <literal>CasAuthenticationToken</literal>.
Furthermore, because the CAS server invalidates a service ticket after
it has been validated by the <literal>TicketValidator</literal>,
presenting the same service ticket on subsequent requests will not
work. It is similarly very difficult to obtain a proxy-granting ticket
for a remoting protocol client, as they are often deployed on client
machines which rarely have HTTPS URLs that would be accessible to the
CAS server.</para>
<para>One obvious option is to not use CAS at all for remoting
protocol clients. However, this would eliminate many of the desirable
features of CAS.</para>
<para>As a middle-ground, the
<literal>CasAuthenticationProvider</literal> uses a
<literal>StatelessTicketCache</literal>. This is used solely for
requests with a principal equal to
<literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>. What
happens is the <literal>CasAuthenticationProvider</literal> will store
the resulting <literal>CasAuthenticationToken</literal> in the
<literal>StatelessTicketCache</literal>, keyed on the service ticket.
Accordingly, remoting protocol clients can present the same service
ticket and the <literal>CasAuthenticationProvider</literal> will not
need to contact the CAS server for validation (aside from the first
request).</para>
<para>The other aspect of advanced CAS usage involves creating proxy
tickets from the proxy-granting ticket. As indicated above, we
recommend you use CAS' <literal>ProxyTicketReceptor</literal> to
receive these tickets. The <literal>ProxyTicketReceptor</literal>
provides a static method that enables you to obtain a proxy ticket by
presenting the proxy-granting IOU ticket. You can obtain the
proxy-granting IOU ticket by calling
<literal>CasAuthenticationToken.getProxyGrantingTicketIou()</literal>.</para>
<para>It is hoped you find CAS integration easy and useful with Spring
Security classes. Welcome to enterprise-wide single sign on!</para>
</section>
-->
</chapter>
@@ -0,0 +1,160 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="channel-security" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Channel Security</title></info>
<section xml:id="channel-security-overview">
<info><title>Overview</title></info>
<para>In addition to coordinating the authentication and authorization
requirements of your application, Spring Security is also able to
ensure unauthenticated web requests have certain properties. These
properties may include being of a particular transport type, having a
particular <literal>HttpSession</literal> attribute set and so on. The
most common requirement is for your web requests to be received using
a particular transport 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 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 maintain
the same session identifier for a given user, even after they switch
from HTTP to HTTPS pages.</para>
<para>If session hijacking is considered too significant a risk for
your particular application, the only option is to use HTTPS for every
request. This means the <literal>jsessionid</literal> is never sent
across an insecure channel. You will need to ensure your
<literal>web.xml</literal>-defined
<literal>&lt;welcome-file&gt;</literal> points to an HTTPS location,
and the application never directs the user to an HTTP location. Spring
Security provides a solution to assist with the latter.</para>
</section>
<section xml:id="channel-security-config">
<info><title>Configuration</title></info>
<para>Channel security is supported by the <link xlink:href="#ns-requires-channel">security namespace</link>
by means of the <literal>requires-channel</literal> attribute on the <literal>&lt;intercept-url&gt;</literal>
element and this is the simplest (and recommended approach)</para>
<para>To confiure channel security explicitly, you would define the following the filter in your application
context:
<programlisting><![CDATA[
<bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter">
<property name="channelDecisionManager" ref="channelDecisionManager"/>
<property name="filterInvocationDefinitionSource">
<security:filter-invocation-definition-source path-type="regex">
<security:intercept-url pattern="\A/secure/.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
<security:intercept-url pattern="\A/acegilogin.jsp.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
<security:intercept-url pattern="\A/j_spring_security_check.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
<security:intercept-url pattern="\A/.*\Z" access="ANY_CHANNEL"/>
</security:filter-invocation-definition-source>
</property>
</bean>
<bean id="channelDecisionManager" class="org.springframework.security.access.channel.ChannelDecisionManagerImpl">
<property name="channelProcessors">
<list>
<ref bean="secureChannelProcessor"/>
<ref bean="insecureChannelProcessor"/>
</list>
</property>
</bean>
<bean id="secureChannelProcessor" class="org.springframework.security.access.channel.SecureChannelProcessor"/>
<bean id="insecureChannelProcessor" class="org.springframework.security.access.channel.InsecureChannelProcessor"/>]]>
</programlisting>
Like <classname>FilterSecurityInterceptor</classname>, Apache Ant
style paths are also 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>
<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 HTTPS, whilst
<literal>InsecureChannelProcessor</literal> ensures requests with a
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 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>
<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>
<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>
</section>
<section xml:id="channel-security-conclusion">
<info><title>Conclusion</title></info>
<para>Once configured, using the channel security filter is very easy.
Simply request pages without regard to the protocol (ie HTTP or HTTPS)
or port (eg 80, 8080, 443, 8443 etc). Obviously you'll still need a
way of making the initial request (probably via the
<literal>web.xml</literal> <literal>&lt;welcome-file&gt;</literal> or
a well-known home page URL), but once this is done the filter will
perform redirects as defined by your application context.</para>
<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
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>
<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>
</section>
</chapter>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="src-xref-base">http://static.springframework.org/spring-security/site/xref/</xsl:variable>
<xsl:variable name="ref-man-base">http://static.springframework.org/spring-security/site/reference/html/</xsl:variable>
<xsl:template match="index">
<html>
<body>
<h1>Class and Interface Index</h1>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="class">
<h3><xsl:value-of select="@name"/></h3>
<xsl:if test="@src-xref">
<p><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="concat($src-xref-base, @src-xref)"/></xsl:attribute>Source</xsl:element></p>
</xsl:if>
<xsl:for-each select="link">
<p><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="concat($ref-man-base, @href)"/></xsl:attribute><xsl:value-of select="@title"/></xsl:element></p>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
@@ -0,0 +1,463 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authentication-common-auth-services" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Common Authentication Services</title></info>
<section xml:id="mechanisms-providers-entry-points">
<info>
<title>Mechanisms, Providers and Entry Points</title>
</info>
<para>To use Spring Security's authentication services,
you'll usually need to configure a web filter, together
with an <classname>AuthenticationProvider</classname> and
<interfacename>AuthenticationEntryPoint</interfacename>. In this section we are
going to explore an example application that needs to support both
form-based authentication (so a nice HTML page is presented to a
user for them to login) and BASIC authentication (so a web service
or similar can access protected resources).</para>
<para>In the web.xml, this application will need a single Spring
Security filter in order to use the FilterChainProxy. Nearly every
Spring Security application will have such an entry, and it looks like
this:</para>
<para><programlisting><![CDATA[
<filter>
<filter-name>filterChainProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>filterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting></para>
<para>The above declarations will cause every web request to be passed
through to the bean called <literal>filterChainProxy</literal>
which will usually be an instance of Spring Security's
<classname>FilterChainProxy</classname>.
As explained in the filters section of this reference guide, the
<classname>FilterChainProxy</classname> is a generally-useful class
that enables web requests to be passed to different filters based on
URL patterns. Those delegated filters are managed inside the
application context, so they can benefit from dependency injection.
Let's have a look at what the FilterChainProxy bean definition would
look like inside your application context:</para>
<para><programlisting><![CDATA[
<bean id="filterChainProxy"
class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<security:filter-chain pattern="/**" filters="httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor,switchUserProcessingFilter"/>
</security:filter-chain-map>
</bean>]]></programlisting></para>
<para>The <literal>filter-chain-map</literal> syntax from the security namespace
allows you to define the mapping from URLs to filter chains, using a sequence of
<literal>filter-chain</literal> child elements. Each of these defines a set of URLs using
the <literal>pattern</literal> attribute and a chain of filters using the <literal>filters</literal>
attribute.What's important to note at this stage is that a series of filters will be
run - in the order specified by the declaration - and each of those
filters are actually the <literal>id</literal> of another
bean in the application context. So, in our case some extra beans
will also appear in the application context, and they'll be named
<literal>httpSessionContextIntegrationFilter</literal>,
<literal>logoutFilter</literal> and so on. The order that the filters
should appear is discussed in the filters section of the reference
guide - although they are correct in the above example.</para>
<para>In our example we have the
<literal>UsernamePasswordAuthenticationProcessingFilter</literal> and
<literal>BasicProcessingFilter</literal> being used. These are the
"authentication mechanisms" that respond to form-based authentication
and BASIC HTTP header-based authentication respectively (we discussed
the role of authentication mechanisms earlier in this reference
guide). If you weren't using form or BASIC authentication, neither of
these beans would be defined. You'd instead define filters applicable
to your desired authentication environment, such as
<literal>DigestProcessingFilter</literal> or
<literal>CasProcessingFilter</literal>. Refer to the individual
chapters of this part of the reference guide to learn how to configure
each of these authentication mechanisms.</para>
<para>Recall that
<classname>HttpSessionContextIntegrationFilter</classname> keeps the
contents of the <interfacename>SecurityContext</interfacename> between invocations
inside an HTTP session. This means the authentication mechanisms are
only used once, being when the principal initially tries to
authenticate. The rest of the time the authentication mechanisms sit
there and silently pass the request through to the next filter in the
chain. That is a practical requirement due to the fact that few
authentication approaches present credentials on each and every call
(BASIC authentication being a notable exception), but what happens if
a principal's account gets cancelled or disabled or otherwise changed
(eg an increase or decrease in <literal>GrantedAuthority[]</literal>s)
after the initial authentication step? Let's look at how that is
handled now.</para>
<para>The major authorization provider for secure objects has
previously been introduced as
<classname>AbstractSecurityInterceptor</classname>. This class needs to
have access to an <interfacename>AuthenticationManager</interfacename>. It also
has configurable settings to indicate whether an
<interfacename>Authentication</interfacename> object should be re-authenticated on
each secure object invocation. By default it just accepts any
<interfacename>Authentication</interfacename> inside the
<classname>SecurityContextHolder</classname> is authenticated if
<literal>Authentication.isAuthenticated()</literal> returns true. This
is great for performance, but not ideal if you want to ensure
up-to-the-moment authentication validity. For such cases you'll
probably want to set the
<literal>AbstractSecurityInterceptor.alwaysReauthenticate</literal>
property to true.</para>
<para>You might be asking yourself, "what's this
<interfacename>AuthenticationManager</interfacename>?". We haven't explored it
before, but we have discussed the concept of an
<classname>AuthenticationProvider</classname>. Quite simply, an
<interfacename>AuthenticationManager</interfacename> is responsible
for passing requests through a chain of AuthenticationProviders. It's
a little like the filter chain we discussed earlier, although there
are some differences. There is only one
<interfacename>AuthenticationManager</interfacename> implementation
shipped with Spring Security, so let's look at how it's configured for
the example we're using in this chapter:</para>
<para><programlisting>&lt;bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager"&gt;
&lt;property name="providers"&gt;
&lt;list&gt;
&lt;ref local="daoAuthenticationProvider"/&gt;
&lt;ref local="anonymousAuthenticationProvider"/&gt;
&lt;ref local="rememberMeAuthenticationProvider"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>It's probably worth mentioning at this point that your
authentication mechanisms (which are usually filters) are also
injected with a reference to the
<interfacename>AuthenticationManager</interfacename>. So both
<classname>AbstractSecurityInterceptor</classname> as well as the
authentication mechanisms will use the above
<literal>ProviderManager</literal> to poll a list of
<classname>AuthenticationProvider</classname>s.</para>
<para>In our example we have three providers. They are tried in the
order shown (which is implied by the use of a <literal>List</literal>
instead of a <literal>Set</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 suitable exception. If
you're interested in learning more about chaining providers, please
refer to the <literal>ProviderManager</literal> JavaDocs.</para>
<para>The providers to use will sometimes be interchangeable with the
authentication mechanisms, whilst at other times they will depend on a
specific authentication mechanism. For example, the
<literal>DaoAuthenticationProvider</literal> just needs a string-based
username and password. Various authentication mechanisms result in the
collection of a string-based username and password, including (but not
limited to) BASIC and form authentication. Equally, some
authentication mechanisms create an authentication request object
which can only be interpreted by a single type of
<classname>AuthenticationProvider</classname>. An example of this
one-to-one mapping would be JA-SIG CAS, which uses the notion of a
service ticket which can therefore only be authenticated by
<literal>CasAuthenticationProvider</literal>. A further example of a
one-to-one mapping would be the LDAP authentication mechanism, which
can only be processed an the
<literal>LdapAuthenticationProvider</literal>. The specifics of such
relationships are detailed in the JavaDocs for each class, plus the
authentication approach-specific chapters of this reference guide. You
need not be terribly concerned about this implementation detail,
because if you forget to register a suitable provider, you'll simply
receive a <literal>ProviderNotFoundException</literal> when an attempt
to authenticate is made.</para>
<para>After configuring the correct authentication mechanisms in the
<classname>FilterChainProxy</classname>, and ensuring that a corresponding
<classname>AuthenticationProvider</classname> is registered in the
<literal>ProviderManager</literal>, your last step is to configure an
<interfacename>AuthenticationEntryPoint</interfacename>. Recall that earlier we
discussed the role of <classname>ExceptionTranslationFilter</classname>,
which is used when HTTP-based requests should receive back an HTTP
header or HTTP redirect in order to start authentication. Continuing
on with our earlier example:</para>
<para><programlisting><![CDATA[
<bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/>
<property name="accessDeniedHandler">
<bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.jsp"/>
</bean>
</property>
</bean>
<bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
<property name="forceHttps">< value="false"/>
</bean>]]></programlisting></para>
<para>Notice that the <classname>ExceptionTranslationFilter</classname>
requires two collaborators. The first,
<literal>AccessDeniedHandlerImpl</literal>, uses a
<literal>RequestDispatcher</literal> forward to display the specified
access denied error page. We use a forward so that the
<classname>SecurityContextHolder</classname> still contains details of the
principal, which may be useful for display 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). <literal>AccessDeniedHandlerImpl</literal> will also set
the HTTP header to 403, which is the official error code to indicate
access denied. In the case of the
<literal>AuthentionEntryPoint</literal>, here we're setting what
action we would like taken when an unauthenticated principal attempts
to perform a protected operation. Because in our example we're going
to be using form-based authentication, we specify
<literal>AuthenticationProcessinFilterEntryPoint</literal> and the URL
of the login page. Your application will usually only have one entry
point, and most authentication approaches define their own specific
<interfacename>AuthenticationEntryPoint</interfacename>. Details of which entry
point to use for each authentication approach is discussed in the
authentication approach-specific chapters of this reference
guide.</para>
</section>
<section xml:id="userdetails-and-associated-types">
<info><title>UserDetails and Associated Types</title></info>
<para>As mentioned in the first part of the reference guide, most
authentication providers take advantage of the
<interfacename>UserDetails</interfacename> and
<interfacename>UserDetailsService</interfacename> interfaces. The contract for
this latter interface consists of a single method:</para>
<para><programlisting>
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;
</programlisting></para>
<para>The returned <interfacename>UserDetails</interfacename> is an interface that
provides getters that guarantee non-null provision of basic
authentication information such as the username, password, granted
authorities and whether the user 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.
Generally such providers will be using the returned
<interfacename>UserDetails</interfacename> object just for its
<literal>GrantedAuthority[]</literal> information, because some other
system (like LDAP or X509 or CAS etc) has undertaken the
responsibility of actually validating the credentials.</para>
<para>A single concrete implementation of
<interfacename>UserDetails</interfacename> is provided with Spring Security, being
the <literal>User</literal> class. Spring Security users will need to
decide when writing their <interfacename>UserDetailsService</interfacename> what
concrete <interfacename>UserDetails</interfacename> class to return. In most cases
<literal>User</literal> will be used directly or subclassed, although
special circumstances (such as object relational mappers) may require
users to write their own <interfacename>UserDetails</interfacename> implementation
from scratch. This is not such an unusual situation, and users should
not hesitate to simply return their normal domain object that
represents a user of the system. This is especially common given that
<interfacename>UserDetails</interfacename> is often used to store additional
principal-related properties (such as their telephone number and email
address), so that they can be easily used by web views.</para>
<para>Given <interfacename>UserDetailsService</interfacename> is so simple to
implement, it should be easy for users to retrieve authentication
information using a persistence strategy of their choice. Having said
that, Spring Security does include a couple of useful base
implementations, which we'll look at below.</para>
<section xml:id="in-memory-service">
<info><title>In-Memory Authentication</title></info>
<para>Whilst it is easy to use create a custom
<interfacename>UserDetailsService</interfacename> implementation that extracts
information from a persistence engine of choice, many applications
do not require such complexity. This is particularly true if you're
undertaking a rapid prototype 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 from the security
<link xlink:href="#namespace-minimal" >namespace</link>:
<programlisting><![CDATA[
<user-service id="userDetailsService">
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
]]>
</programlisting>
This also suppots the use of an external properties file:
<programlisting><![CDATA[
<user-service id="userDetailsService" properties="users.properties"/>
]]>
</programlisting>
The properties file should contain entries in the form
<programlisting>
username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]
</programlisting>
For example
<programlisting>
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled
</programlisting>
</para>
</section>
<section xml:id="jdbc-service">
<info>
<title>JDBC Authentication</title>
</info>
<para>Spring Security also includes a
<interfacename>UserDetailsService</interfacename> that can obtain authentication
information from a JDBC data source. Internally 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>
<![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"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</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
per normal Spring options.
</para>
<section xml:id="jdbc-default-schema">
<title>Default User Database Schema</title>
<para>
Irrespective of the database you are using and how
a <literal>DataSource</literal> is obtained, a standard schema must
be in place. The DDL for an HSQL database instance would be:
<programlisting>
CREATE TABLE users (
username VARCHAR(50) NOT NULL PRIMARY KEY,
password VARCHAR(50) NOT NULL,
enabled BIT NOT NULL
);
CREATE TABLE authorities (
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL
);
ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users(username);
</programlisting>
</para>
<para>If the default schema is unsuitable for your needs,
<literal>JdbcDaoImpl</literal> provides properties that allow
customisation of the SQL statements. Please refer to the JavaDocs for
details, but note that the class is not intended for complex custom subclasses.
If you have a complex schema or would like a
custom <interfacename>UserDetails</interfacename> implementation returned,
you'd be better off writing your own
<interfacename>UserDetailsService</interfacename>. The base implementation
provided with Spring Security is intended for typical situations,
rather than catering for all possible requirements.</para>
</section>
</section>
</section>
<section xml:id="concurrent-sessions">
<info><title>Concurrent Session Handling</title></info>
<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
"Batman" from logging onto the web application from two different
sessions.</para>
<para>To use concurrent session support, you'll need to add the
following to <literal>web.xml</literal>:
<programlisting>
&lt;listener&gt;
&lt;listener-class&gt;org.springframework.security.web.session.HttpSessionEventPublisher&lt;/listener-class&gt;
&lt;/listener&gt;
</programlisting>
</para>
<para>In addition, you will need to add the
<literal>org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter</literal>
to your <classname>FilterChainProxy</classname>. The
<classname>ConcurrentSessionFilter</classname> requires two
properties, <literal>sessionRegistry</literal>, which generally points
to an instance of <literal>SessionRegistryImpl</literal>, and
<literal>expiredUrl</literal>, which points to the page to display
when a session has expired.</para>
<para>The <literal>web.xml</literal>
<literal>HttpSessionEventPublisher</literal> 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.</para>
<para>You will also need to wire up the
<classname>ConcurrentSessionControllerImpl</classname> and refer to it
from your <literal>ProviderManager</literal> bean:</para>
<para>
<programlisting><![CDATA[
<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<!-- your providers go here -->
</property>
<property name="sessionController" ref="concurrentSessionController"/>
</bean>
<bean id="concurrentSessionController"
class="org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl">
<property name="maximumSessions" value="1"/>
<property name="sessionRegistry">
<bean class="org.springframework.security.authentication.concurrent.SessionRegistryImpl"/>
<property>
</bean>
]]></programlisting></para>
</section>
<section xml:id="authentication-taglibs">
<info><title>Authentication Tag Libraries</title></info>
<para><literal>AuthenticationTag</literal> is used to simply output a
property of the current <interfacename>Authentication</interfacename> object to the web
page.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AuthenticationTag</literal>:</para>
<para><programlisting>&lt;security:authentication property="principal.username"/&gt;</programlisting></para>
<para>This tag would cause the principal's name to be output. Here we
are assuming the <literal>Authentication.getPrincipal()</literal> is a
<interfacename>UserDetails</interfacename> object, which is generally the case
when using one of Spring Security's stadard <classname>AuthenticationProvider</classname>
implementations.</para>
</section>
</chapter>
+59
View File
@@ -0,0 +1,59 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0"
xml:id="community"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<info>
<title>Spring Security Community</title></info>
<section xml:id="jira">
<info><title>Issue Tracking</title></info>
<para>Spring Security uses JIRA to manage bug reports and enhancement
requests. If you find a bug, please log a report using JIRA. Do not
log it on the support forum, mailing list or by emailing the project's
developers. Such approaches are ad-hoc and we prefer to manage bugs
using a more formal process.</para>
<para>If possible, in your issue report please provide a JUnit test
that demonstrates any incorrect behaviour. Or, better yet, provide a
patch that corrects the issue. Similarly, enhancements are welcome to
be logged in the issue tracker, although we only accept 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.springframework.org/browse/SEC">http://jira.springframework.org/browse/SEC</link>.
</para>
</section>
<section xml:id="becoming-involved">
<info><title>Becoming Involved</title></info>
<para>We welcome your involvement in Spring Security project.
There are many ways of contributing, including reading the forum
and responding to questions from other people, writing new code,
improving existing code, assisting with documentation, developing
samples or tutorials, or simply making suggestions.</para>
<!-- TODO: Not currently there on SSec 2.0
<para>Please read our project policies web page that is available on
Spring Security home page. This explains the path to become a
committer, and the administration approaches we use within the
project.</para>
-->
</section>
<section xml:id="further-info">
<info><title>Further Information</title></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.springframework.org">http://forum.springframework.org</uri>
to discuss Spring Security with other users of the framework.
Remember to use JIRA for bug reports, as explained above.
Everyone is also welcome to join the Acegisecurity-developer mailing
list and participate in design discussions. The
traffic volume is very light.</para>
</section>
</chapter>
@@ -0,0 +1,450 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="ca"><info><title>Container Adapter Authentication</title></info>
<section xml:id="ca-overview">
<info><title>Overview</title></info>
<para>Very early versions of Spring Security exclusively used
Container Adapters for interfacing authentication with end users.
Whilst this worked well, it required considerable time to support
multiple container versions and the configuration itself was
relatively time-consuming for developers. For this reason the HTTP
Form Authentication and HTTP Basic Authentication approaches were
developed, and are today recommended for almost all
applications.</para>
<para>Container Adapters enable Spring Security to integrate directly
with the containers used to host end user applications. This
integration means that applications can continue to leverage the
authentication and authorization capabilities built into containers
(such as <literal>isUserInRole()</literal> and form-based or basic
authentication), whilst benefiting from the enhanced security
interception capabilities provided by Spring Security (it should be
noted that Spring Security also offers
<literal>ContextHolderAwareRequestWrapper</literal> to deliver
<literal>isUserInRole()</literal> and similar Servlet Specification
compatibility methods).</para>
<para>The integration between a container and Spring Security is
achieved through an adapter. The adapter provides a
container-compatible user authentication provider, and needs to return
a container-compatible user object.</para>
<para>The adapter is instantiated by the container and is defined in a
container-specific configuration file. The adapter then loads a Spring
application context which defines the normal authentication manager
settings, such as the authentication providers that can be used to
authenticate the request. The application context is usually named
<literal>acegisecurity.xml</literal> and is placed in a
container-specific location.</para>
<para>Spring Security currently supports Jetty, Catalina (Tomcat),
JBoss and Resin. Additional container adapters can easily be
written</para>
</section>
<section xml:id="ca-adapter"><info><title>Adapter Authentication Provider</title></info>
<para>As is always the case, the container adapter generated
<interfacename>Authentication</interfacename> object still needs to be
authenticated by an <interfacename>AuthenticationManager</interfacename> when
requested to do so by the
<classname>AbstractSecurityInterceptor</classname>. The
<interfacename>AuthenticationManager</interfacename> needs to be certain the
adapter-provided <interfacename>Authentication</interfacename> object is valid and
was actually authenticated by a trusted adapter.</para>
<para>Adapters create <interfacename>Authentication</interfacename> objects which
are immutable and implement the <literal>AuthByAdapter</literal>
interface. These objects store the hash of a key that is defined by
the adapter. This allows the <interfacename>Authentication</interfacename> object
to be validated by the <literal>AuthByAdapterProvider</literal>. This
authentication provider is defined as follows:</para>
<para><programlisting>&lt;bean id="authByAdapterProvider"
class="org.springframework.security.adapters.AuthByAdapterProvider"&gt;
&lt;property name="key"&gt;&lt;value&gt;my_password&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>The key must match the key that is defined in the
container-specific configuration file that starts the adapter. The
<literal>AuthByAdapterProvider</literal> automatically accepts as
valid any <literal>AuthByAdapter</literal> implementation that returns
the expected hash of the key.</para>
<para>To reiterate, this means the adapter will perform the initial
authentication using providers such as
<literal>DaoAuthenticationProvider</literal>, returning an
<literal>AuthByAdapter</literal> instance that contains a hash code of
the key. Later, when an application calls a security interceptor
managed resource, the <literal>AuthByAdapter</literal> instance in the
<interfacename>SecurityContext</interfacename> in the
<classname>SecurityContextHolder</classname> will be tested by the
application's <literal>AuthByAdapterProvider</literal>. There is no
requirement for additional authentication providers such as
<literal>DaoAuthenticationProvider</literal> within the
application-specific application context, as the only type of
<interfacename>Authentication</interfacename> instance that will be presented by
the application is from the container adapter.</para>
<para>Classloader issues are frequent with containers and the use of
container adapters illustrates this further. Each container requires a
very specific configuration. The installation instructions are
provided below. Once installed, please take the time to try the sample
application to ensure your container adapter is properly
configured.</para>
<para>When using container adapters with the
<literal>DaoAuthenticationProvider</literal>, ensure you set its
<literal>forcePrincipalAsString</literal> property to
<literal>true</literal>.</para>
</section>
<section xml:id="ca-jetty"><info><title>Jetty</title></info>
<para>The following was tested with Jetty 4.2.18.</para>
<para><literal>$JETTY_HOME</literal> refers to the root of your Jetty
installation.</para>
<para>Edit your <literal>$JETTY_HOME/etc/jetty.xml</literal> file so
the <literal>&lt;Configure class&gt;</literal> section has a new
<literal>addRealm</literal> call:</para>
<para><programlisting>
&lt;Call name="addRealm"&gt;
&lt;Arg&gt;
&lt;New class="org.springframework.security.adapters.jetty.JettySpringSecurityUserRealm"&gt;
&lt;Arg&gt;Spring Powered Realm&lt;/Arg&gt;
&lt;Arg&gt;my_password&lt;/Arg&gt;
&lt;Arg&gt;etc/acegisecurity.xml&lt;/Arg&gt;
&lt;/New&gt;
&lt;/Arg&gt;
&lt;/Call&gt;
</programlisting></para>
<para>Copy <literal>acegisecurity.xml</literal> into
<literal>$JETTY_HOME/etc</literal>.</para>
<para>Copy the following files into
<literal>$JETTY_HOME/ext</literal>:<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-logging.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>acegi-security-jetty-XX.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist></para>
<para>None of the above JAR files (or
<literal>acegi-security-XX.jar</literal>) should be in your
application's <literal>WEB-INF/lib</literal>. The realm name indicated
in your <literal>web.xml</literal> does matter with Jetty. The
<literal>web.xml</literal> must express the same
<literal>&lt;realm-name&gt;</literal> as your
<literal>jetty.xml</literal> (in the example above, "Spring Powered
Realm").</para>
</section>
<section xml:id="ca-jboss"><info><title>JBoss</title></info>
<para>The following was tested with JBoss 3.2.6.</para>
<para><literal>$JBOSS_HOME</literal> refers to the root of your JBoss
installation.</para>
<para>There are two different ways of making spring context available
to the Jboss integration classes.</para>
<para>The first approach is by editing your
<literal>$JBOSS_HOME/server/your_config/conf/login-config.xml</literal>
file so that it contains a new entry under the
<literal>&lt;Policy&gt;</literal> section:</para>
<para><programlisting>
&lt;application-policy name = "SpringPoweredRealm"&gt;
&lt;authentication&gt;
&lt;login-module code = "org.springframework.security.adapters.jboss.JbossSpringSecurityLoginModule"
flag = "required"&gt;
&lt;module-option name = "appContextLocation"&gt;acegisecurity.xml&lt;/module-option&gt;
&lt;module-option name = "key"&gt;my_password&lt;/module-option&gt;
&lt;/login-module&gt;
&lt;/authentication&gt;
&lt;/application-policy&gt;
</programlisting></para>
<para>Copy <literal>acegisecurity.xml</literal> into
<literal>$JBOSS_HOME/server/your_config/conf</literal>.</para>
<para>In this configuration <literal>acegisecurity.xml</literal>
contains the spring context definition including all the
authentication manager beans. You have to bear in mind though, that
<interfacename>SecurityContext</interfacename> is created and destroyed on each
login request, so the login operation might become costly.
Alternatively, the second approach is to use Spring singleton
capabilities through
<literal>org.springframework.beans.factory.access.SingletonBeanFactoryLocator</literal>.
The required configuration for this approach is:</para>
<para><programlisting>
&lt;application-policy name = "SpringPoweredRealm"&gt;
&lt;authentication&gt;
&lt;login-module code = "org.springframework.security.adapters.jboss.JbossSpringSecurityLoginModule"
flag = "required"&gt;
&lt;module-option name = "singletonId"&gt;springRealm&lt;/module-option&gt;
&lt;module-option name = "key"&gt;my_password&lt;/module-option&gt;
&lt;module-option name = "authenticationManager"&gt;authenticationManager&lt;/module-option&gt;
&lt;/login-module&gt;
&lt;/authentication&gt;
&lt;/application-policy&gt;
</programlisting></para>
<para>In the above code fragment,
<literal>authenticationManager</literal> is a helper property that
defines the expected name of the
<interfacename>AuthenticationManager</interfacename> in case you have several
defined in the IoC container. The <literal>singletonId</literal>
property references a bean defined in a
<literal>beanRefFactory.xml</literal> file. This file needs to be
available from anywhere on the JBoss classpath, including
<literal>$JBOSS_HOME/server/your_config/conf</literal>. The
<literal>beanRefFactory.xml</literal> contains the following
declaration:</para>
<para><programlisting>
&lt;beans&gt;
&lt;bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"&gt;
&lt;constructor-arg&gt;
&lt;list&gt;
&lt;value&gt;acegisecurity.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/constructor-arg&gt;
&lt;/bean&gt;
&lt;/beans&gt;
</programlisting></para>
<para>Finally, irrespective of the configuration approach you need to
copy the following files into
<literal>$JBOSS_HOME/server/your_config/lib</literal>:<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>acegi-security-jboss-XX.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist></para>
<para>None of the above JAR files (or
<literal>acegi-security-XX.jar</literal>) should be in your
application's <literal>WEB-INF/lib</literal>. The realm name indicated
in your <literal>web.xml</literal> does not matter with JBoss.
However, your web application's
<literal>WEB-INF/jboss-web.xml</literal> must express the same
<literal>&lt;security-domain&gt;</literal> as your
<literal>login-config.xml</literal>. For example, to match the above
example, your <literal>jboss-web.xml</literal> would look like
this:</para>
<para><programlisting>
&lt;jboss-web&gt;
&lt;security-domain&gt;java:/jaas/SpringPoweredRealm&lt;/security-domain&gt;
&lt;/jboss-web&gt;</programlisting></para>
<para>JBoss is a widely-used container adapter (mostly due to the need
to support legacy EJBs), so please let us know if you have any
difficulties.</para>
</section>
<section xml:id="ca-resin"><info><title>Resin</title></info>
<para>The following was tested with Resin 3.0.6.</para>
<para><literal>$RESIN_HOME</literal> refers to the root of your Resin
installation.</para>
<para>Resin provides several ways to support the container adapter. In
the instructions below we have elected to maximise consistency with
other container adapter configurations. This will allow Resin users to
simply deploy the sample application and confirm correct
configuration. Developers comfortable with Resin are naturally able to
use its capabilities to package the JARs with the web application
itself, and/or support single sign-on.</para>
<para>Copy the following files into
<literal>$RESIN_HOME/lib</literal>:<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-logging.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>acegi-security-resin-XX.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist></para>
<para>Unlike the container-wide <literal>acegisecurity.xml</literal>
files used by other container adapters, each Resin web application
will contain its own
<literal>WEB-INF/resin-acegisecurity.xml</literal> file. Each web
application will also contain a <literal>resin-web.xml</literal> file
which Resin uses to start the container adapter:</para>
<para><programlisting>
&lt;web-app&gt;
&lt;authenticator&gt;
&lt;type&gt;org.springframework.security.adapters.resin.ResinAcegiAuthenticator&lt;/type&gt;
&lt;init&gt;
&lt;app-context-location&gt;WEB-INF/resin-acegisecurity.xml&lt;/app-context-location&gt;
&lt;key&gt;my_password&lt;/key&gt;
&lt;/init&gt;
&lt;/authenticator&gt;
&lt;/web-app&gt;
</programlisting></para>
<para>With the basic configuration provided above, none of the JAR
files listed (or <literal>acegi-security-XX.jar</literal>) should be
in your application's <literal>WEB-INF/lib</literal>. The realm name
indicated in your <literal>web.xml</literal> does not matter with
Resin, as the relevant authentication class is indicated by the
<literal>&lt;authenticator&gt;</literal> setting</para>
</section>
<section xml:id="ca-tomcat"><info><title>Tomcat</title></info>
<para>The following was tested with Jakarta Tomcat 4.1.30 and
5.0.19.</para>
<para><literal>$CATALINA_HOME</literal> refers to the root of your
Catalina (Tomcat) installation.</para>
<para>Edit your <literal>$CATALINA_HOME/conf/server.xml</literal> file
so the <literal>&lt;Engine&gt;</literal> section contains only one
active <literal>&lt;Realm&gt;</literal> entry. An example realm
entry:</para>
<para><programlisting> &lt;Realm
className="org.springframework.security.adapters.catalina.CatalinaSpringSecurityUserRealm"
appContextLocation="conf/acegisecurity.xml"
key="my_password" /&gt;</programlisting></para>
<para>Be sure to remove any other <literal>&lt;Realm&gt;</literal>
entry from your <literal>&lt;Engine&gt;</literal> section.</para>
<para>Copy <literal>acegisecurity.xml</literal> into
<literal>$CATALINA_HOME/conf</literal>.</para>
<para>Copy <literal>spring-security-catalina-XX.jar</literal> into
<literal>$CATALINA_HOME/server/lib</literal>.</para>
<para>Copy the following files into
<literal>$CATALINA_HOME/common/lib</literal>:</para>
<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist>
<para>None of the above JAR files (or
<literal>spring-security-XX.jar</literal>) should be in your
application's <literal>WEB-INF/lib</literal>. The realm name indicated
in your <literal>web.xml</literal> does not matter with
Catalina.</para>
<para>We have received reports of problems using this Container
Adapter with Mac OS X. A work-around is to use a script such as
follows:</para>
<para><programlisting>#!/bin/sh
export CATALINA_HOME="/Library/Tomcat"
export JAVA_HOME="/Library/Java/Home"
cd /
$CATALINA_HOME/bin/startup.sh</programlisting></para>
<para>Finally, restart Tomcat.</para>
</section>
</chapter>
@@ -0,0 +1,129 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="dao-provider">
<info><title>DAO Authentication Provider</title></info>
<section xml:id="dao-provider-overview">
<info><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 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 authentication providers that leverage UserDetailsService,
this authentication provider actually requires the password to be
presented, and the provider will actually evaluate the validity or
otherwise of the password presented in an authentication request
object.</para>
</section>
<section xml:id="dao-provider-config">
<info><title>Configuration</title></info>
<para>Aside from adding DaoAuthenticationProvider to your
ProviderManager list (as discussed 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>
<![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></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 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
inspects a given property of the returned
<interfacename>UserDetails</interfacename> object to obtain the salt. Please refer
to the JavaDocs for further details on these 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[
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="userCache" ref="userCache"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:/ehcache-failsafe.xml"/>
</bean>
<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheName" value="userCache"/>
</bean>
<bean id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
<property name="cache" ref="userCacheBackend"/>
</bean>]]>
</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>
<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 stored in the <literal>HttpSession</literal>.
</para></note>
<para>A design decision was made not to support account locking in the
<literal>DaoAuthenticationProvider</literal>, as doing so would have
increased the complexity of the <interfacename>UserDetailsService</interfacename>
interface. For instance, a method would be required to increase the
count of unsuccessful authentication attempts. Such functionality
could be easily provided by leveraging the application event
publishing features discussed below.</para>
<para><literal>DaoAuthenticationProvider</literal> returns an
<interfacename>Authentication</interfacename> object which in turn has its
<literal>principal</literal> property set. The principal will be
either a <literal>String</literal> (which is essentially the username)
or a <interfacename>UserDetails</interfacename> object (which was looked up from
the <interfacename>UserDetailsService</interfacename>). By default the
<interfacename>UserDetails</interfacename> is returned, as this enables
applications to add extra properties potentially of use in
applications, such as the user's full name, email address etc. If
using container adapters, or if your applications were written to
operate with <literal>String</literal>s (as was the case for releases
prior to Spring Security 0.6), you should set the
<literal>DaoAuthenticationProvider.forcePrincipalAsString</literal>
property to <literal>true</literal> in your application context</para>
</section>
</chapter>
@@ -0,0 +1,144 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="digest"><info><title>Digest Authentication</title></info>
<section xml:id="digest-overview"><info><title>Overview</title></info>
<para>Spring Security provides a
<literal>DigestProcessingFilter</literal> which is capable of
processing digest authentication credentials presented in HTTP
headers. Digest Authentication attempts to solve many of the
weaknesses of Basic authentication, specifically by ensuring
credentials are never sent in clear text across the wire. Many user
agents support Digest Authentication, including FireFox and Internet
Explorer. The standard governing HTTP Digest Authentication is defined
by RFC 2617, which updates an earlier version of the Digest
Authentication standard prescribed by RFC 2069. Most user agents
implement RFC 2617. Spring Security
<literal>DigestProcessingFilter</literal> is compatible with the
"<literal>auth</literal>" quality of protection
(<literal>qop</literal>) prescribed by RFC 2617, which also provides
backward compatibility with RFC 2069. Digest Authentication is a
highly attractive option if you need to use unencrypted HTTP (ie no
TLS/HTTPS) and wish to maximise security of the authentication
process. Indeed Digest Authentication is a mandatory requirement for
the WebDAV protocol, as noted by RFC 2518 Section 17.1, so we should
expect to see it increasingly deployed and replacing Basic
Authentication.</para>
<para>Digest Authentication is definitely the most secure choice
between Form Authentication, Basic Authentication and Digest
Authentication, although extra security also means more complex user
agent implementations. Central to Digest Authentication is a "nonce".
This is a value the server generates. Spring Security's nonce adopts
the following format:</para>
<para><programlisting>
base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
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>
<para>The <literal>DigestProcessingFilterEntryPoint</literal> has a
property specifying the <literal>key</literal> used for generating the
nonce tokens, along with a <literal>nonceValiditySeconds</literal>
property for determining the expiration time (default 300, which
equals five minutes). Whist ever the nonce is valid, the digest is
computed by concatenating various strings including the username,
password, nonce, URI being requested, a client-generated nonce (merely
a random value which the user agent generates each request), the realm
name etc, then performing an MD5 hash. Both the server and user agent
perform this digest computation, resulting in different hash codes if
they disagree on an included value (eg password). In Spring Security
implementation, if the server-generated nonce has merely expired (but
the digest was otherwise valid), the
<literal>DigestProcessingFilterEntryPoint</literal> will send a
<literal>"stale=true"</literal> header. This tells the user agent
there is no need to disturb the user (as the password and username etc
is correct), but simply to try again using a new nonce.</para>
<para>An appropriate value for
<literal>DigestProcessingFilterEntryPoint</literal>'s
<literal>nonceValiditySeconds</literal> parameter will depend on your
application. Extremely secure applications should note that an
intercepted authentication header can be used to impersonate the
principal until the <literal>expirationTime</literal> contained in the
nonce is reached. This is the key principle when selecting an
appropriate setting, but it would be unusual for immensely secure
applications to not be 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 Security
filters therefore encapsulate all state information into the
"<literal>nonce</literal>" token instead. In our testing, Spring
Security implementation works reliably with FireFox and Internet
Explorer, correctly handling nonce timeouts etc.</para>
</section>
<section xml:id="digest-config"><info><title>Configuration</title></info>
<para>Now that we've reviewed the theory, let's see how to use it. To
implement HTTP Digest Authentication, it is necessary to define
<literal>DigestProcessingFilter</literal> in the fitler chain. The
application context will need to define the
<literal>DigestProcessingFilter</literal> and its required
collaborators:</para>
<para><programlisting>
<![CDATA[
<bean id="digestProcessingFilter"
class="org.springframework.security.web.authentication.www.DigestProcessingFilter">
<property name="userDetailsService" ref="jdbcDaoImpl"/>
<property name="authenticationEntryPoint" ref="digestProcessingFilterEntryPoint"/>
<property name="userCache" ref="userCache"/>
</bean>
<bean id="digestProcessingFilterEntryPoint"
class="org.springframework.security.web.authentication.www.DigestProcessingFilterEntryPoint">
<property name="realmName" value="Contacts Realm via Digest Authentication"/>
<property name="key" value="acegi"/>
<property name="nonceValiditySeconds" value="10"/>
</bean>]]>
</programlisting></para>
<para>The configured <interfacename>UserDetailsService</interfacename> is needed
because <literal>DigestProcessingFilter</literal> must have direct
access to the clear text password of a user. Digest Authentication
will NOT work if you are using encoded passwords in your DAO. The DAO
collaborator, along with the <literal>UserCache</literal>, are
typically shared directly with a
<literal>DaoAuthenticationProvider</literal>. The
<literal>authenticationEntryPoint</literal> property must be
<literal>DigestProcessingFilterEntryPoint</literal>, so that
<literal>DigestProcessingFilter</literal> can obtain the correct
<literal>realmName</literal> and <literal>key</literal> for digest
calculations.</para>
<para>Like <literal>BasicAuthenticationFilter</literal>, if
authentication is successful an <interfacename>Authentication</interfacename>
request token will be placed into the
<classname>SecurityContextHolder</classname>. If the authentication event
was successful, or authentication was not attempted because the HTTP
header did not contain a Digest Authentication request, the filter
chain will continue as normal. The only time the filter chain will be
interrupted is if authentication fails and the
<interfacename>AuthenticationEntryPoint</interfacename> is called, as discussed in
the previous paragraph.</para>
<para>Digest Authentication's RFC offers a range of additional
features to further increase security. For example, the nonce can be
changed on every request. Despite this, Spring Security implementation
was designed to minimise the complexity of the implementation (and the
doubtless user agent incompatibilities that would emerge), and avoid
needing to store server-side state. You are invited to review RFC 2617
if you wish to explore these features in more detail. As far as we are
aware, Spring Security's implementation does comply with the minimum
standards of this RFC.</para>
</section>
</chapter>
+297
View File
@@ -0,0 +1,297 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="domain-acls">
<info>
<title>Domain Object Security (ACLs)</title>
</info>
<section xml:id="domain-acls-overview">
<info>
<title>Overview</title>
</info>
<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>
<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
customers will only be able to see their own customer records. To make it a little more
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>
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>
</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>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>
<para>Fortunately, there is another alternative, which we'll talk about below.</para>
</section>
<section xml:id="domain-acls-key-concepts">
<info>
<title>Key Concepts</title>
</info>
<para>Spring Security's ACL services are shipped in the
<literal>spring-security-acl-xxx.jar</literal>. You will need to add this JAR to your
classpath to use Spring Security's domain object instance security capabilities.</para>
<para>Spring Security's domain object instance security capabilities centre on the concept
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>
</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
repository capability is extremely important, because every domain object instance in
your system might have several access control entries, and each ACL might inherit from
other ACLs in a tree-like structure (this is supported out-of-the-box by Spring
Security, and is very commonly used). Spring Security's ACL capability has been
carefully designed to provide high performance retrieval of ACLs, together with
pluggable caching, deadlock-minimizing database updates, independence from ORM
frameworks (we use JDBC directly), proper encapsulation, and transparent database
updating.</para>
<para>Given databases are central to the operation of the ACL module, let's explore the four
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>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
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
have 32 bits available for permissions, you could have billions of domain object
instances (which will mean billions of rows in ACL_OBJECT_IDENTITY and quite probably
ACL_ENTRY). We make this point because we've found sometimes people mistakenly believe
they need a bit for each potential domain object, which is not the case.</para>
<para>Now that we've provided a basic overview of what the ACL system does, and what it
looks like at a table structure, let's explore the key interfaces. The key interfaces
are:</para>
<itemizedlist spacing="compact">
<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>
</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>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>
<listitem>
<para><literal>Permission</literal>: A permission represents a particular immutable
bit mask, and offers convenience functions for bit masking and outputting
information. The basic permissions presented above (bits 0 through 4) are
contained in the <literal>BasePermission</literal> class.</para>
</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
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
stored in the ACL_SID table.</para>
</listitem>
<listitem>
<para><literal>ObjectIdentity</literal>: Each domain object is represented
internally within the ACL module by an <literal>ObjectIdentity</literal>. The
default implementation is called <literal>ObjectIdentityImpl</literal>.</para>
</listitem>
<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>
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
and similar performance-centric, non-ANSI SQL capabilities.</para>
</listitem>
<listitem>
<para><literal>MutableAclService</literal>: Allows a modified <literal>Acl</literal>
to be presented for persistence. It is not essential to use this interface if
you do not wish.</para>
</listitem>
</itemizedlist>
<para>Please note that our out-of-the-box AclService and related database classes all use
ANSI SQL. This should therefore work with all major databases. At the time of writing,
the system had been successfully tested using Hypersonic SQL, PostgreSQL, Microsoft SQL
Server and Oracle.</para>
<para>Two samples ship with Spring Security that demonstrate the ACL module. The first is
the Contacts Sample, and the other is the Document Management System (DMS) Sample. We
suggest taking a look over these for examples.</para>
</section>
<section xml:id="domain-acls-getting-started">
<info>
<title>Getting Started</title>
</info>
<para>To get starting using Spring Security's ACL capability, you will need to store your
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>
<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
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
consideration to <literal>ObjectIdentity</literal> issues. Many parts of the ACL module
rely on long identifiers. If you're not using long (or an int, byte etc), there is a
very good chance you'll need to reimplement a number of classes. We do not intend to
support non-long identifiers in Spring Security's ACL module, as longs are already
compatible with all database sequences, the most common identifier data type, and are of
sufficient length to accommodate all common usage scenarios.</para>
<para>The following fragment of code shows how to create an <literal>Acl</literal>, or
modify an existing
<literal>Acl</literal>:<programlisting>// Prepare the information we'd like in our access control entry (ACE)
ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44));
Sid sid = new PrincipalSid("Samantha");
Permission p = BasePermission.ADMINISTRATION;
// Create or update the relevant ACL
MutableAcl acl = null;
try {
acl = (MutableAcl) aclService.readAclById(oi);
} catch (NotFoundException nfe) {
acl = aclService.createAcl(oi);
}
// Now grant some permissions via an access control entry (ACE)
acl.insertAce(acl.getEntries().length, p, sid, true);
aclService.updateAcl(acl);
</programlisting></para>
<para>In the example above, we're retrieving the ACL associated with the "Foo" domain object
with identifier number 44. We're then adding an ACE so that a principal named "Samantha"
can "administer" the object. The code fragment is relatively self-explanatory, except
the insertAce method. The first argument to the insertAce method is determining at what
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>
<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
considering using AOP on your services layer to automatically integrate the ACL
information with your services layer operations. We've found this quite an effective
approach in the past.</para>
<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.
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
runtime, freeing you from needing to write any code. Please refer to the sample
applications to learn how to use these classes.</para>
</section>
</chapter>
@@ -0,0 +1,58 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="form"><info><title>Form Authentication Mechanism</title></info>
<section xml:id="form-overview">
<info><title>Overview</title></info>
<para>HTTP Form Authentication involves using the
<literal>UsernamePasswordAuthenticationProcessingFilter</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
and JAAS authentication providers.</para>
</section>
<section xml:id="form-config">
<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>UsernamePasswordAuthenticationProcessingFilter</literal> to your application context:
<programlisting><![CDATA[
<bean id="authenticationProcessingFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/login.jsp?login_error=1"/>
<property name="defaultTargetUrl" value="/"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean> ]]>
</programlisting></para>
<para>The configured <interfacename>AuthenticationManager</interfacename>
processes each authentication request. If authentication fails, the
browser will be redirected to the
<literal>authenticationFailureUrl</literal>. The
<literal>AuthenticationException</literal> will be placed into the
<literal>HttpSession</literal> attribute indicated by
<literal>AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY</literal>,
enabling a reason to be provided to the user on the error page.</para>
<para>If authentication is successful, the resulting
<interfacename>Authentication</interfacename> object will be placed into the
<classname>SecurityContextHolder</classname>.</para>
<para>Once the <classname>SecurityContextHolder</classname> has been
updated, the browser will need to be redirected to the target URL which
is usually indicated by the <literal>HttpSession</literal> attribute stored under
<literal>AbstractAuthenticationProcessingFilter.SPRING_SECURITY_TARGET_URL_KEY</literal>.
This attribute is automatically set by the
<classname>ExceptionTranslationFilter</classname> when an
<literal>AuthenticationException</literal> occurs, so that after login
is completed the user can return to what they were originally trying to access.
If for some reason the <literal>HttpSession</literal> does not
indicate the target URL, the browser will be redirected to the
<literal>defaultTargetUrl</literal> property.</para>
</section>
</chapter>
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- ==================================================================== -->
<t:titlepage t:element="book" t:wrapper="div" class="titlepage">
<t:titlepage-content t:side="recto">
<title/>
<subtitle/>
<corpauthor/>
<authorgroup/>
<author/>
<mediaobject/>
<othercredit/>
<productname/>
<releaseinfo/>
<copyright/>
<pubdate/>
<revision/>
<revhistory/>
<abstract/>
</t:titlepage-content>
<t:titlepage-content t:side="verso">
<legalnotice/>
</t:titlepage-content>
<t:titlepage-separator>
<hr/>
</t:titlepage-separator>
<t:titlepage-before t:side="recto">
</t:titlepage-before>
<t:titlepage-before t:side="verso">
</t:titlepage-before>
</t:titlepage>
</t:templates>
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:db="http://docbook.org/ns/docbook">
<xsl:output method="text"/>
<xsl:template match="db:interfacename|db:classname">
<xsl:variable name="classname" select="."/>
<xsl:for-each select="ancestor::*[@xml:id][1]">
<xsl:variable name="title" select="db:info/db:title|db:title"/>
<xsl:value-of select="concat($classname, ':', @xml:id, ':', $title,';')"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()|@*|*">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
+308
View File
@@ -0,0 +1,308 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0" xml:id="introduction"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Introduction</title>
<sect1 xml:id="what-is-acegi-security">
<title>What is Spring Security?</title>
<para>Spring Security provides comprehensive security services for
J2EE-based enterprise software applications. There is a particular
emphasis on supporting projects built using The Spring Framework,
which is the leading J2EE solution for enterprise software
development. If you're not using Spring for developing enterprise
applications, we warmly encourage you to take a closer look at it.
Some familiarity with Spring - and in particular dependency injection
principles - will help you get up to speed with Spring Security more
easily.</para>
<para>People use Spring Security for many reasons, but most are drawn
to the project after finding the security features of J2EE's Servlet
Specification or EJB Specification lack the depth required for typical
enterprise application scenarios. Whilst mentioning these standards,
it's important to recognise that they are not portable at a WAR or EAR
level. Therefore, if you switch server environments, it is typically a
lot of work to reconfigure your application's security in the new
target environment. Using Spring Security overcomes these problems,
and also brings you dozens of other useful, entirely customisable
security features.</para>
<para>As you probably know, security comprises two major operations.
The first is known as "authentication", which is the process of
establishing a principal is who they claim to be. A "principal"
generally means a user, device or some other system which can perform
an action in your application. "Authorization" refers to the process
of deciding whether a principal is allowed to perform an action in
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>
<para>At an authentication level, Spring Security supports a wide
range of authentication models. Most of these authentication models
are either provided by third parties, or are developed by relevant
standards bodies such as the Internet Engineering Task Force. In
addition, Spring Security provides its own set of authentication
features. Specifically, Spring Security currently supports
authentication integration with all of these technologies:</para>
<itemizedlist spacing="compact">
<listitem>
<para>HTTP BASIC authentication headers (an IEFT RFC-based
standard)</para>
</listitem>
<listitem>
<para>HTTP Digest authentication headers (an IEFT RFC-based
standard)</para>
</listitem>
<listitem>
<para>HTTP X.509 client certificate exchange (an IEFT RFC-based
standard)</para>
</listitem>
<listitem>
<para>LDAP (a very common approach to cross-platform
authentication needs, especially in large environments)</para>
</listitem>
<listitem>
<para>Form-based authentication (for simple user interface
needs)</para>
</listitem>
<listitem>
<para>OpenID authentication</para>
</listitem>
<listitem>
<para>Computer Associates Siteminder</para>
</listitem>
<listitem>
<para>JA-SIG Central Authentication Service (otherwise known as
CAS, which is a popular open source single sign on system)</para>
</listitem>
<listitem>
<para>Transparent authentication context propagation for Remote
Method Invocation (RMI) and HttpInvoker (a Spring remoting
protocol)</para>
</listitem>
<listitem>
<para>Automatic "remember-me" authentication (so you can tick a
box to avoid re-authentication for a predetermined period of
time)</para>
</listitem>
<listitem>
<para>Anonymous authentication (allowing every call to
automatically assume a particular security identity)</para>
</listitem>
<listitem>
<para>Run-as authentication (which is useful if one call should
proceed with a different security identity)</para>
</listitem>
<listitem>
<para>Java Authentication and Authorization Service (JAAS)</para>
</listitem>
<listitem>
<para>Container integration with JBoss, Jetty, Resin and Tomcat
(so you can still use Container Manager Authentication if
desired)</para>
</listitem>
<listitem>
<para>Java Open Source Single Sign On (JOSSO) *</para>
</listitem>
<listitem>
<para>OpenNMS Network Management Platform *</para>
</listitem>
<listitem>
<para>AppFuse *</para>
</listitem>
<listitem>
<para>AndroMDA *</para>
</listitem>
<listitem>
<para>Mule ESB *</para>
</listitem>
<listitem>
<para>Direct Web Request (DWR) *</para>
</listitem>
<listitem>
<para>Grails *</para>
</listitem>
<listitem>
<para>Tapestry *</para>
</listitem>
<listitem>
<para>JTrac *</para>
</listitem>
<listitem>
<para>Jasypt *</para>
</listitem>
<listitem>
<para>Roller *</para>
</listitem>
<listitem>
<para>Elastic Plath *</para>
</listitem>
<listitem>
<para>Atlassian Crowd *</para>
</listitem>
<listitem>
<para>Your own authentication systems (see below)</para>
</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>
<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 lot of
engineering or requiring the client to change their environment. If
none of the above authentication mechanisms suit your needs, Spring
Security is an open platform and it is quite simple to write your own
authentication mechanism. Many corporate users of Spring Security need
to integrate with "legacy" systems that don't follow any particular
security standards, and Spring Security is happy to "play nicely" with
such systems.</para>
<para>Sometimes the mere process of authentication isn't enough.
Sometimes you need to also differentiate security based on the way a
principal is interacting with your application. For example, you might
want to ensure requests only arrive over HTTPS, in order to protect
passwords from eavesdropping or end users from man-in-the-middle
attacks. Or, you might want to ensure that an actual human being is
making the requests and not some robot or other automated process.
This is especially helpful to protect password recovery processes from
brute force attacks, or simply to make it harder for people to
duplicate your application's key content. To help you achieve these
goals, Spring Security fully supports automatic "channel security",
together with JCaptcha integration for human user detection.</para>
<para>Irrespective of how authentication was undertaken, Spring
Security provides a deep set of authorization capabilities. There are
three main areas of interest in respect of authorization, these being
authorizing web requests, authorizing methods can be invoked, and
authorizing access to individual domain object instances. To help you
understand the differences, consider the authorization capabilities
found in the Servlet Specification web pattern security, EJB Container
Managed Security and file system security respectively. Spring
Security provides deep capabilities in all of these important areas,
which we'll explore later in this reference guide.</para>
</sect1>
<sect1 xml:id="history">
<title>History</title>
<para>Spring Security began in late 2003 as "The Acegi Security System
for Spring". 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 by today's size!), and indeed Spring
itself had only existed as a SourceForge project from early 2003. The
response to the question was that it was a worthwhile area, although a
lack of time currently prevented its exploration.</para>
<para>With that in mind, a simple security implementation was built
and not released. A few weeks later another member of the Spring
community inquired about security, and at the time this code was
offered to them. Several other requests followed, and by January 2004
around twenty people were using the code. These pioneering users were
joined by others who suggested a SourceForge project was in order,
which was duly established in March 2004.</para>
<para>In those early days, the project didn't have any of its own
authentication modules. Container Managed Security was relied upon for
the authentication process, with Acegi Security instead focusing on
authorization. This was suitable at first, but as more and more users
requested additional container support, the fundamental limitation of
container-specific authentication realm interfaces was experienced.
There was also a related issue of adding new JARs to the container's
classpath, which was a common source of end user confusion and
misconfiguration.</para>
<para>Acegi Security-specific authentication services were
subsequently introduced. Around a year later, Acegi Security became an
official Spring Framework subproject. The 1.0.0 final release was
published in May 2006 - after more than two and a half years of active
use in numerous production software projects and many hundreds of
improvements and community contributions.</para>
<para>Acegi Security became an official Spring Portfolio project
towards the end of 2007 and was rebranded as "Spring Security".</para>
<para>Today Spring Security enjoys a strong and active open source
community. There are thousands of messages about Spring Security on
the support forums. There is an active core of developers work
who work on the code itself and an active community which also
regularly share patches and support their peers.</para>
</sect1>
<sect1 xml:id="release-numbering">
<title>Release Numbering</title>
<para>It is useful to understand how Spring Security release numbers
work, as it will help 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 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>
</sect1>
<sect1 xml:id="get-source">
<title>Getting the Source</title>
<para>
Since Spring Security is an Open Source project, we'd strongly encourage you to
check out the source code using subversion. This will give you full access to all the sample
applications and you can build the most up to date version of the project easily.
Having the source for a project is also a huge help in debugging. Exception stack traces are no
longer obscure black-box issues but you can get straight to the line that's causing the problem
and work out what's happening. The source is the ultimate documentation for a project and often
the simplest place to find out how something actually works.
</para>
<para>
To obtain the source for the project trunk, use the following subversion command:
<programlisting>
svn checkout http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/trunk/
</programlisting>
You can checkout specific versions from <literal>http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/tags/</literal>.
</para>
</sect1>
</chapter>
@@ -0,0 +1,134 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="jaas">
<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>
<para>Central to JAAS operation are login configuration files. To
learn more about JAAS login configuration files, consult the JAAS
reference documentation available from Sun Microsystems. We expect you
to have a basic understanding of JAAS and its login configuration file
syntax in order to understand this section.</para>
</section>
<section xml:id="jaas-config">
<info><title>Configuration</title></info>
<para>The <literal>JaasAuthenticationProvider</literal> attempts to
authenticate a users principal and credentials through JAAS.</para>
<para>Lets assume we have a JAAS login configuration file,
<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[
<bean id="jaasAuthenticationProvider"
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="/WEB-INF/login.conf"/>
<property name="loginContextName" value="JAASTest"/>
<property name="callbackHandlers">
<list>
<bean class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler"/>
<bean class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler"/>
</list>
</property>
<property name="authorityGranters">
<list>
<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
</list>
</property>
</bean>
]]></programlisting></para>
<para>The <literal>CallbackHandler</literal>s and
<interfacename>AuthorityGranter</interfacename>s are discussed below.</para>
<section xml:id="jaas-callbackhandler">
<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>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>For those needing full control over the callback behavior,
internally <literal>JaasAutheticationProvider</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>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>
</section>
<section xml:id="jaas-authoritygranter">
<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
<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
<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
<classname>JaasAuthenticationProvider</classname> creates a
<classname>JaasGrantedAuthority</classname> (which implements Spring
Securitys <interfacename>GrantedAuthority</interfacename> interface) containing
the authority string and the JAAS principal that the
<interfacename>AuthorityGranter</interfacename> was passed. The
<classname>JaasAuthenticationProvider</classname> obtains the JAAS
principals by firstly successfully authenticating the users
credentials using the JAAS <literal>LoginModule</literal>, and then
accessing the <literal>LoginContext</literal> it returns. A call to
<literal>LoginContext.getSubject().getPrincipals()</literal> is
made, with each resulting principal passed to each
<interfacename>AuthorityGranter</interfacename> defined against the
<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>
</section>
</section>
</chapter>
@@ -0,0 +1,433 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="ldap">
<info>
<title>LDAP Authentication</title>
</info>
<section xml:id="ldap-overview">
<info>
<title>Overview</title>
</info>
<para>LDAP is often used by organizations as a central repository for user information and
as an authentication service. It can also be used to store the role information for
application users.</para>
<para>There are many different scenarios for how an LDAP server may be configured so Spring
Security's LDAP provider is fully configurable. It uses separate strategy interfaces for
authentication and role retrieval and provides default implementations which can be
configured to handle a wide range of situations.</para>
<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>
</section>
<section>
<info>
<title>Using LDAP with Spring Security</title>
</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>
</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 passwords.
</para>
<para>
We will look at some configuration scenarios below. For full information on available
configuration options, please consult the security namespace schema (information from
which should be available in your XML editor).
</para>
</section>
<section xml:id="ldap-server">
<info>
<title>Configuring an LDAP Server</title>
</info>
<para>
The first thing you need to do is configure the server against which authentication
should take place. This is done using the
<literal>&lt;ldap-server&gt;</literal>
element from the security namespace. This can be configured to point at an external LDAP
server, using the
<literal>url</literal>
attribute:
<programlisting><![CDATA[
<ldap-server url="ldap://springframework.org:389/dc=springframework,dc=org" />
]]>
</programlisting>
</para>
<section>
<info>
<title>Using an Embedded Test Server</title>
</info>
<para>
The
<literal>&lt;ldap-server&gt;</literal>
element can also be used to create an embedded server, which can be very useful for
testing and demonstrations. In this case you use it without the
<literal>url</literal>
attribute:
<programlisting><![CDATA[
<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
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[
<ldap-server ldif="classpath:users.ldif" />
]]></programlisting>
This makes it a lot easier to get up and running with LDAP, since it can be
inconvenient to work all the time with an external server. It also insulates the
user from the complex bean configuration needed to wire up an Apache Directory
server. Using plain Spring Beans the configuration would be much more cluttered. You
must have the necessary Apache Directory dependency jars available for your
application to use. These can be obtained from the LDAP sample application.
</para>
</section>
<section>
<info>
<title>Using Bind Authentication</title>
</info>
<para>
This is the most common LDAP authentication scenario.
<programlisting><![CDATA[
<ldap-authentication-provider user-dn-pattern="uid={0},ou=people"/>
]]></programlisting>
This simple example would obtain the DN for the user by substituting the user login
name in the supplied pattern and attempting to bind as that user with the login
password. This is OK if all your users are stored under a single node in the
directory. If instead you wished to configure an LDAP search filter to locate the
user, you could use the following:
<programlisting><![CDATA[
<ldap-authentication-provider user-search-filter="(uid={0})" user-search-base="ou=people"/>
]]></programlisting>
If used with the server definition above, this would 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 from the root.
</para>
</section>
<section>
<info>
<title>Loading Authorities</title>
</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>
</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 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>
</section>
</section>
<section>
<info>
<title>Implementation Classes</title>
</info>
<para>The namespace configuration options we've used above are simple to use and much more
concise than using Spring beans explicitly. There are situations when you may need to
know how to configure Spring Security LDAP directly in your application context. You may
wish to customize the behaviour of some of the classes, for example. If you're happy
using namespace configuration then you can skip this section and the next one.
</para>
<para>
The main LDAP provider class is
<classname>org.springframework.security.ldap.authentication.LdapAuthenticationProvider</classname>.
This bean 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 authenticating the user and retrieving the user's set of
<interfacename>GrantedAuthority</interfacename>s respectively.</para>
<section xml:id="ldap-ldap-authenticators">
<info>
<title>LdapAuthenticator Implementations</title>
</info>
<para>The authenticator is also responsible for retrieving any required user attributes.
This is because the permissions on the attributes may depend on the type of
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>
</itemizedlist>
</para>
<section xml:id="ldap-ldap-authenticators-common">
<info>
<title>Common Functionality</title>
</info>
<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
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
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>
</section>
<section xml:id="ldap-ldap-authenticators-bind">
<info>
<title>BindAuthenticator</title>
</info>
<para>The class
<classname>org.springframework.security.ldap.authentication.BindAuthenticator</classname>
implements the bind authentication strategy. It simply attempts to bind as the
user.</para>
</section>
<section xml:id="ldap-ldap-authenticators-password">
<info>
<title>PasswordComparisonAuthenticator</title>
</info>
<para>The class
<classname>org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator</classname>
implements the password comparison authentication strategy.</para>
</section>
<section xml:id="ldap-ldap-authenticators-active-directory">
<info>
<title>Active Directory Authentication</title>
</info>
<para>In addition to standard LDAP authentication (binding with a DN), Active
Directory has its own non-standard syntax for user authentication.</para>
</section>
</section>
<section xml:id="ldap-context-source">
<info>
<title>Connecting to the LDAP Server</title>
</info>
<para>The beans discussed above have to be able to connect to the server. They both have
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 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 this class and for Spring LDAP's
<classname>AbstractContextSource</classname>.
</para>
</section>
<section xml:id="ldap-searchobjects">
<info>
<title>LDAP Search Objects</title>
</info>
<para>Often more 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>
</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 supplied with parameters. For this class, the only valid parameter is
<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 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>
</section>
<section xml:id="ldap-bean-config">
<info>
<title>Spring Bean Configuration</title>
</info>
<para>A typical configuration, using some of the beans we've discussed here, might look
like this:
<programlisting><![CDATA[
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/>
<property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
<property name="password" value="password"/>
</bean>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource"/>
<property name="userDnPatterns">
<list><value>uid={0},ou=people</value></list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource"/>
<constructor-arg value="ou=groups"/>
<property name="groupRoleAttribute" value="ou"/>
</bean>
</constructor-arg>
</bean>]]>
</programlisting>
This would set up the provider to access an LDAP server with URL
<literal>ldap://monkeymachine:389/dc=springframework,dc=org</literal>.
Authentication will be performed by attempting to bind with the DN
<literal>uid=&lt;user-login-name&gt;,ou=people,dc=springframework,dc=org</literal>.
After successful authentication, roles will be assigned to the user by searching
under the DN
<literal>ou=groups,dc=springframework,dc=org</literal>
with the default filter
<literal>(member=&lt;user's-DN&gt;)</literal>. The role name will be taken from the
<quote>ou</quote>
attribute of each match.</para>
<para>To configure a user search object, which uses the filter
<literal>(uid=&lt;user-login-name&gt;)</literal>
for use instead of the DN-pattern (or in addition to it), you would configure the
following bean
<programlisting><![CDATA[
<bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value="(uid={0})"/>
<constructor-arg index="2" ref="contextSource" />
</bean> ]]>
</programlisting>
and use it by setting the <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 Security authentication using the standard <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 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[
public interface UserDetailsContextMapper {
UserDetails mapUserFromContext(DirContextOperations ctx, String username, GrantedAuthority[] authority);
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 list 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>BindAuthenticatior</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>
</section>
</section>
</chapter>
@@ -0,0 +1,701 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="ns-config"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Security Namespace Configuration</title>
</info>
<section>
<title>Introduction</title>
<para> Namespace configuration has been available since version 2.0 of the Spring framework. It
allows you to supplement the traditional Spring beans application context syntax with elements
from additional XML schema. You can find more information in the Spring <link
xlink:href="http://static.springframework.org/spring/docs/2.5.x/reference/xsd-config.html">
Reference Documentation</link>. A namespace element can be used simply to allow a more
concise way of configuring an individual bean or, more powerfully, to define an alternative
configuration syntax which more closely matches the problem domain and hides the underlying
complexity from the user. A simple element may conceal the fact that multiple beans and
processing steps are being added to the application context. For example, adding the following
element from the security namespace to an application context will start up an embedded LDAP
server for testing use within the application: <programlisting><![CDATA[
<security:ldap-server />
]]></programlisting> This is much simpler than wiring up the equivalent Apache Directory Server
beans. The most common alternative configuration requirements are supported by attributes on
the <literal>ldap-server</literal> element and the user is isolated from worrying about which
beans they need to be set on and what the bean property names are. <footnote>
<para>You can find out more about the use of the <literal>ldap-server</literal> element in
the chapter on <link xlink:href="#ldap">LDAP</link>.</para>
</footnote>. Use of a good XML editor while editing the application context file should
provide information on the attributes and elements that are available. We would recommend that
you try out the <link xlink:href="http://www.springsource.com/products/sts">SpringSource Tool
Suite</link> as it has special features for working with standard Spring namespaces. </para>
<para> To start using the security namespace in your application context, all you need to do is
add the schema declaration to your application context file: <programlisting language="xml">
<![CDATA[
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
...
</beans>
]]></programlisting> In many of the examples you will see (and in the sample) applications, we
will often use "security" as the default namespace rather than "beans", which means we can
omit the prefix on all the security namespace elements, making the context easier to read. You
may also want to do this if you have your application context divided up into separate files
and have most of your security configuration in one of them. Your security application context
file would then start like this <programlisting language="xml"><![CDATA[
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
...
</beans:beans>
]]></programlisting> We'll assume this syntax is being used from now on in this chapter. </para>
<section>
<title>Design of the Namespace</title>
<para> The namespace is designed to capture the most common uses of the framework and provide
a simplified and concise syntax for enabling them within an application. The design is
largely based around the large-scale dependencies within the framework, and can be divided
up into the following areas: <itemizedlist>
<listitem>
<para>
<emphasis>Web/HTTP Security</emphasis> - the most complex part. Sets up the filters
and related service beans used to apply the framework authentication mechanisms, to
secure URLs, render login and error pages and much more.</para>
</listitem>
<listitem>
<para>
<emphasis>Business Object (Method) Security</emphasis> - options for securing the
service layer.</para>
</listitem>
<listitem>
<para>
<emphasis>AuthenticationManager</emphasis> - handles authentication requests from
other parts of the framework. A default instance will be registered internally by the
namespace.</para>
</listitem>
<listitem>
<para>
<emphasis>AccessDecisionManager</emphasis> - provides access decisions for web and
method security. A default one will be registered, but you can also choose to use a
custom one, declared using normal Spring bean syntax.</para>
</listitem>
<listitem>
<para>
<emphasis>AuthenticationProvider</emphasis>s - mechanisms against which the
authentication manager authenticates users. The namespace provides supports for
several standard options and also a means of adding custom beans declared using a
traditional syntax. </para>
</listitem>
<listitem>
<para>
<emphasis>UserDetailsService</emphasis> - closely related to authentication providers,
but often also required by other beans.</para>
</listitem>
<!-- todo: diagram and link to other sections which describe the interfaces -->
</itemizedlist></para>
<para>We'll see how these work together in the following sections.</para>
</section>
</section>
<section xml:id="ns-getting-started">
<title>Getting Started with Security Namespace Configuration</title>
<para> In this section, we'll look at how you can build up a namespace configuration to use some
of the main features of the framework. Let's assume you initially want to get up and running
as quickly as possible and add authentication support and access control to an existing web
application, with a few test logins. Then we'll look at how to change over to authenticating
against a database or other security information repository. In later sections we'll introduce
more advanced namespace configuration options. </para>
<section xml:id="ns-web-xml">
<title><literal>web.xml</literal> Configuration</title>
<para> The first thing you need to do is add the following filter declaration to your
<literal>web.xml</literal> file: <programlisting language="xml">
<![CDATA[
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting> This provides a hook into the Spring Security web
infrastructure. <classname>DelegatingFilterProxy</classname> is a Spring Framework class
which delegates to a filter implementation which is defined as a Spring bean in your
application context. In this case, the bean is named "springSecurityFilterChain", which is
an internal infrastructure bean created by the namespace to handle web security. Note that
you should not use this bean name yourself. Once you've added this to your
<filename>web.xml</filename>, you're ready to start editing your application context file.
Web security services are configured using the <literal>&lt;http&gt;</literal> element.
</para>
</section>
<section xml:id="ns-minimal">
<title>A Minimal <literal>&lt;http&gt;</literal> Configuration</title>
<para> All you need to enable web security to begin with is <programlisting language="xml"><![CDATA[
<http auto-config='true'>
<intercept-url pattern="/**" access="ROLE_USER" />
</http>
]]>
</programlisting> Which says that we want all URLs within our application to be secured,
requiring the role <literal>ROLE_USER</literal> to access them.</para>
<note>
<para>You can use multiple <literal>&lt;intercept-url&gt;</literal> elements to define
different access requirements for different sets of URLs, but they will be evaluated in
the order listed and the first match will be used. So you must put the most specific
matches at the top.</para>
</note>
<para> To add some users, you can define a set of test data directly in the namespace: <programlisting language="xml"><![CDATA[
<authentication-provider>
<user-service>
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
]]>
</programlisting></para>
<sidebar>
<para>If you are familiar with pre-namespace versions of the framework, you can probably
already guess roughly what's going on here. The &lt;http&gt; element is responsible for
creating a <classname>FilterChainProxy</classname> and the filter beans which it uses.
Common issues like incorrect filter ordering are no longer an issue as the filter
positions are predefined.</para>
<para>The <literal>&lt;authentication-provider&gt;</literal> element creates a
<classname>DaoAuthenticationProvider</classname> bean and the
<literal>&lt;user-service&gt;</literal> element creates an
<classname>InMemoryDaoImpl</classname>. A <literal>ProviderManager</literal> bean is
always created by the namespace processing system and the
<classname>DaoAuthenticationProvider</classname> is automatically registered with it.
You can find more detailed information on the beans that are created in the <link
xlink:href="#appendix-namespace">namespace appendix</link>. </para>
</sidebar>
<para> The configuration above defines two users, their passwords and their roles within the
application (which will be used for access control). It is also possible to load user
information from a standard properties file using the <literal>properties</literal>
attribute on <literal>user-service</literal>. See the section on <link
xlink:href="#in-memory-service">in-memory authentication</link> for more details. Using
the <literal>&lt;authentication-provider&gt;</literal> element means that the user
information will be used by the authentication manager to process authentication requests. </para>
<para> At this point you should be able to start up your application and you will be required
to log in to proceed. Try it out, or try experimenting with the "tutorial" sample
application that comes with the project. The above configuration actually adds quite a few
services to the application because we have used the <literal>auto-config</literal>
attribute. For example, form-based login processing is automatically enabled. </para>
<section xml:id="ns-auto-config">
<title>What does <literal>auto-config</literal> Include?</title>
<para> The <literal>auto-config</literal> attribute, as we have used it above, is just a
shorthand syntax for: <programlisting language="xml"><![CDATA[
<http>
<form-login />
<http-basic />
<logout />
</http>
]]>
</programlisting> These other elements are responsible for setting up form-login,
basic authentication and logout handling services respectively <footnote>
<para>In versions prior to 3.0, this list also inluded remember-me functionality. This
could cause some confusing errors with some configurations and was removed in 3.0. In
3.0, the addition of an <classname>AnonymousProcessingFilter</classname> was made part
of the default <literal>&lt;http></literal> configuration, so the
<literal>&lt;anonymous /></literal> element is effectively added regardless of
whether <literal>auto-config</literal> is enabled.</para>
</footnote> . They each have attributes which can be used to alter their behaviour.
</para>
</section>
<section xml:id="ns-form-and-basic">
<title>Form and Basic Login Options</title>
<para> You might be wondering where the login form came from when you were prompted to log
in, since we made no mention of any HTML files or JSPs. In fact, since we didn't
explicitly set a URL for the login page, Spring Security generates one automatically,
based on the features that are enabled and using standard values for the URL which
processes the submitted login, the default target URL the user will be sent to and so on.
However, the namespace offers plenty of suppport to allow you to customize these options.
For example, if you want to supply your own login page, you could use: <programlisting language="xml"><![CDATA[
<http auto-config='true'>
<intercept-url pattern="/login.jsp*" filters="none"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>
]]>
</programlisting> Note that you could still use <literal>auto-config</literal>. The
<literal>form-login</literal> element just overrides the default settings. Also note
that we've added an extra <literal>intercept-url</literal> element to say that any
requests for the login page should be excluded from processing by the security filters.
Otherwise the request would be matched by the pattern <literal>/**</literal> and it
wouldn't be possible to access the login page itself! If you want to use basic
authentication instead of form login, then change the configuration to <programlisting language="xml"><![CDATA[
<http auto-config='true'>
<intercept-url pattern="/**" access="ROLE_USER" />
<http-basic />
</http>
]]>
</programlisting> Basic authentication will then take precedence and will be used to
prompt for a login when a user attempts to access a protected resource. Form login is
still available in this configuration if you wish to use it, for example through a login
form embedded in another web page. </para>
<section xml:id="ns-form-target">
<title>Setting a Default Post-Login Destination</title>
<para> If a form login isn't prompted by an attempt to access a protected resource, the
<literal>default-target-url</literal> option comes into play. This is the URL the user
will be taken to after logging in, and defaults to "/". You can also configure things so
that they user <emphasis>always</emphasis> ends up at this page (regardless of whether
the login was "on-demand" or they explicitly chose to log in) by setting the
<literal>always-use-default-target</literal> attribute to "true". This is useful if
your application always requires that the user starts at a "home" page, for example: <programlisting language="xml"><![CDATA[
<http>
<intercept-url pattern='/login.htm*' filters='none'/>
<intercept-url pattern='/**' access='ROLE_USER' />
<form-login login-page='/login.htm' default-target-url='/home.htm' always-use-default-target='true' />
</http>
]]>
</programlisting></para>
</section>
</section>
</section>
<section xml:id="ns-auth-providers">
<title>Using other Authentication Providers</title>
<para> In practice you will need a more scalable source of user information than a few names
added to the application context file. Most likely you will want to store your user
information in something like a database or an LDAP server. LDAP namespace configuration is
dealt with in the <link xlink:href="#ldap">LDAP chapter</link>, so we won't cover it here.
If you have a custom implementation of Spring Security's
<classname>UserDetailsService</classname>, called "myUserDetailsService" in your
application context, then you can authenticate against this using <programlisting language="xml"><![CDATA[
<authentication-provider user-service-ref='myUserDetailsService'/>
]]>
</programlisting> If you want to use a database, then you can use <programlisting language="xml"><![CDATA[
<authentication-provider>
<jdbc-user-service data-source-ref="securityDataSource"/>
</authentication-provider>
]]>
</programlisting> Where "securityDataSource" is the name of a
<classname>DataSource</classname> bean in the application context, pointing at a database
containing the standard Spring Security <link xlink:href="#db_schema_users_authorities">user
data tables</link>. Alternatively, you could configure a Spring Security
<classname>JdbcDaoImpl</classname> bean and point at that using the
<literal>user-service-ref</literal> attribute: <programlisting language="xml"><![CDATA[
<authentication-provider user-service-ref='myUserDetailsService'/>
<beans:bean id="myUserDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
]]>
</programlisting> You can also use standard
<interfacename>AuthenticationProvider</interfacename> beans by adding the
<literal>&lt;custom-authentication-provider&gt;</literal> element within the bean
definition. See <xref linkend="ns-auth-manager"/> for more on this. </para>
<section>
<title>Adding a Password Encoder</title>
<para> Often your password data will be encoded using a hashing algorithm. This is supported
by the <literal>&lt;password-encoder&gt;</literal> element. With SHA encoded passwords,
the original authentication provider configuration would look like this: <programlisting language="xml"><![CDATA[
<authentication-provider>
<password-encoder hash="sha"/>
<user-service>
<user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
]]>
</programlisting></para>
<para> When using hashed passwords, it's also a good idea to use a salt value to protect
against dictionary attacks and Spring Security supports this too. Ideally you would want
to use a randomly generated salt value for each user, but you can use any property of the
<classname>UserDetails</classname> object which is loaded by your
<classname>UserDetailsService</classname>. For example, to use the
<literal>username</literal> property, you would use <programlisting><![CDATA[
<password-encoder hash="sha">
<salt-source user-property="username"/>
</password-encoder>
]]></programlisting> You can use a custom password encoder bean by using the
<literal>ref</literal> attribute of <literal>password-encoder</literal>. This should
contain the name of a bean in the application context which is an instance of Spring
Security's <interfacename>PasswordEncoder</interfacename> interface. </para>
</section>
</section>
</section>
<section xml:id="ns-web-advanced">
<title>Advanced Web Features</title>
<section xml:id="ns-remember-me">
<title>Remember-Me Authentication</title>
<para>See the separate <link xlink:href="#remember-me">Remember-Me chapter</link> for
information on remember-me namespace configuration.</para>
</section>
<section xml:id="ns-requires-channel">
<title>Adding HTTP/HTTPS Channel Security</title>
<para>If your application supports both HTTP and HTTPS, and you require that particular URLs
can only be accessed over HTTPS, then this is directly supported using the
<literal>requires-channel</literal> attribute on <literal>&lt;intercept-url&gt;</literal>: <programlisting language="xml"><![CDATA[
<http>
<intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/>
<intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/>
...
</http>]]>
</programlisting> With this configuration in place, if a user attempts to
access anything matching the "/secure/**" pattern using HTTP, they will first be redirected
to an HTTPS URL. The available options are "http", "https" or "any". Using the value "any"
means that either HTTP or HTTPS can be used. </para>
<para> If your application uses non-standard ports for HTTP and/or HTTPS, you can specify a
list of port mappings as follows: <programlisting>
<![CDATA[
<http>
...
<port-mappings>
<port-mapping http="9080" https="9443"/>
</port-mappings>
</http>]]>
</programlisting> You can find a more in-depth discussion of channel security
in <xref xlink:href="#channel-security"/>. </para>
</section>
<section xml:id="ns-concurrent-session">
<title>Concurrent Session Control</title>
<para> If you wish to place constraints on a single user's ability to log in to your
application, Spring Security supports this out of the box with the following simple
additions. First you need to add the following listener to your <filename>web.xml</filename>
file to keep Spring Security updated about session lifecycle events: <programlisting language="xml">
<![CDATA[
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
]]></programlisting> Then add the following line to your application context: <programlisting language="xml"><![CDATA[
<http>
...
<concurrent-session-control max-sessions="1" />
</http>]]>
</programlisting> This will prevent a user from logging in multiple times - a
second login will cause the first to be invalidated. Often you would prefer to prevent a
second login, in which case you can use <programlisting language="xml"><![CDATA[
<http>
...
<concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true"/>
</http>]]>
</programlisting> The second login will then be rejected.
<!-- TODO: Link to main section in docs -->
</para>
</section>
<section xml:id="ns-openid">
<title>OpenID Login</title>
<para>The namespace supports <link xlink:href="http://openid.net/">OpenID</link> login either
instead of, or in addition to normal form-based login, with a simple change: <programlisting language="xml"><![CDATA[
<http>
<intercept-url pattern="/**" access="ROLE_USER" />
<openid-login />
</http>
]]></programlisting> You should then register yourself with an OpenID provider (such as
myopenid.com), and add the user information to your in-memory
<literal>&lt;user-service&gt;</literal>: <programlisting><![CDATA[
<user name="http://jimi.hendrix.myopenid.com/" password="notused" authorities="ROLE_USER" />
]]></programlisting> You should be able to login using the <literal>myopenid.com</literal> site to
authenticate. </para>
</section>
<section xml:id="ns-custom-filters">
<title>Adding in Your Own Filters</title>
<para>If you've used Spring Security before, you'll know that the framework maintains a chain
of filters in order to apply its services. You may want to add your own filters to the stack
at particular locations or use a Spring Security filter for which there isn't currently a
namespace configuration option (CAS, for example). Or you might want to use a customized
version of a standard namespace filter, such as the
<literal>UsernamePasswordAuthenticationProcessingFilter</literal> which is created by the
<literal>&lt;form-login&gt;</literal> element, taking advantage of some of the extra
configuration options which are available by using defining the bean directly. How can you
do this with namespace configuration, since the filter chain is not directly exposed? </para>
<para>The order of the filters is always strictly enforced when using the namespace. Each
Spring Security filter implements the Spring <interfacename>Ordered</interfacename>
interface and the filters created by the namespace are sorted during initialization. The
standard Spring Security filters each have an alias in the namespace. The filters, aliases
and namespace elements/attributes which create the filters are shown in <xref
linkend="filter-stack"/>. <table xml:id="filter-stack">
<title>Standard Filter Aliases and Ordering</title>
<tgroup cols="3" align="left">
<thead>
<row>
<entry align="center">Alias</entry>
<entry align="center">Filter Class</entry>
<entry align="center">Namespace Element or Attribute</entry>
</row>
</thead>
<tbody>
<row>
<entry> CHANNEL_FILTER</entry>
<entry><literal>ChannelProcessingFilter</literal></entry>
<entry><literal>http/intercept-url</literal></entry>
</row>
<row>
<entry> CONCURRENT_SESSION_FILTER</entry>
<entry><literal>ConcurrentSessionFilter</literal>
</entry>
<entry><literal>http/concurrent-session-control</literal></entry>
</row>
<row>
<entry> SESSION_CONTEXT_INTEGRATION_FILTER</entry>
<entry><classname>HttpSessionContextIntegrationFilter</classname></entry>
<entry><literal>http</literal></entry>
</row>
<row>
<entry> LOGOUT_FILTER </entry>
<entry><literal>LogoutFilter</literal></entry>
<entry><literal>http/logout</literal></entry>
</row>
<row>
<entry> X509_FILTER </entry>
<entry><literal>X509PreAuthenticatedProcessigFilter</literal></entry>
<entry><literal>http/x509</literal></entry>
</row>
<row>
<entry> PRE_AUTH_FILTER </entry>
<entry><literal>AstractPreAuthenticatedProcessingFilter</literal> Subclasses</entry>
<entry>N/A</entry>
</row>
<row>
<entry> CAS_PROCESSING_FILTER </entry>
<entry><literal>CasProcessingFilter</literal></entry>
<entry>N/A</entry>
</row>
<row>
<entry> AUTHENTICATION_PROCESSING_FILTER </entry>
<entry><literal>UsernamePasswordAuthenticationProcessingFilter</literal></entry>
<entry><literal>http/form-login</literal></entry>
</row>
<row>
<entry> BASIC_PROCESSING_FILTER </entry>
<entry><literal>BasicProcessingFilter</literal></entry>
<entry><literal>http/http-basic</literal></entry>
</row>
<row>
<entry> SERVLET_API_SUPPORT_FILTER</entry>
<entry><literal>SecurityContextHolderAwareRequestFilter</literal></entry>
<entry><literal>http/@servlet-api-provision</literal></entry>
</row>
<row>
<entry> REMEMBER_ME_FILTER </entry>
<entry><classname>RememberMeProcessingFilter</classname></entry>
<entry><literal>http/remember-me</literal></entry>
</row>
<row>
<entry> ANONYMOUS_FILTER </entry>
<entry><literal>AnonymousProcessingFilter</literal></entry>
<entry><literal>http/anonymous</literal></entry>
</row>
<row>
<entry> EXCEPTION_TRANSLATION_FILTER </entry>
<entry><classname>ExceptionTranslationFilter</classname></entry>
<entry><literal>http</literal></entry>
</row>
<row>
<entry> NTLM_FILTER </entry>
<entry><literal>NtlmProcessingFilter</literal></entry>
<entry>N/A</entry>
</row>
<row>
<entry> FILTER_SECURITY_INTERCEPTOR </entry>
<entry><classname>FilterSecurityInterceptor</classname></entry>
<entry><literal>http</literal></entry>
</row>
<row>
<entry> SWITCH_USER_FILTER </entry>
<entry><literal>SwitchUserProcessingFilter</literal></entry>
<entry>N/A</entry>
</row>
</tbody>
</tgroup>
</table> You can add your own filter to the stack, using the
<literal>custom-filter</literal> element and one of these names to specify the position
your filter should appear at: <programlisting language="xml"><![CDATA[
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter">
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
</beans:bean>
]]></programlisting> You can also use the <literal>after</literal> or <literal>before</literal>
attributes if you want your filter to be inserted before or after another filter in the
stack. The names "FIRST" and "LAST" can be used with the <literal>position</literal>
attribute to indicate that you want your filter to appear before or after the entire stack,
respectively. </para>
<tip>
<title>Avoiding filter position conflicts</title>
<para> If you are inserting a custom filter which may occupy the same position as one of the
standard filters created by the namespace then it's important that you don't include the
namespace versions by mistake. Avoid using the <literal>auto-config</literal> attribute
and remove any elements which create filters whose functionality you want to replace. </para>
<para> Note that you can't replace filters which are created by the use of the
<literal>&lt;http&gt;</literal> element itself -
<classname>HttpSessionContextIntegrationFilter</classname>,
<classname>ExceptionTranslationFilter</classname> or
<classname>FilterSecurityInterceptor</classname>. </para>
</tip>
<para> If you're replacing a namespace filter which requires an authentication entry point
(i.e. where the authentication process is triggered by an attempt by an unauthenticated user
to access to a secured resource), you will need to add a custom entry point bean too. </para>
<section xml:id="ns-entry-point-ref">
<title>Setting a Custom <interfacename>AuthenticationEntryPoint</interfacename></title>
<para> If you aren't using form login, OpenID or basic authentication through the namespace,
you may want to define an authentication filter and entry point using a traditional bean
syntax and link them into the namespace, as we've just seen. The corresponding
<interfacename>AuthenticationEntryPoint</interfacename> can be set using the
<literal>entry-point-ref</literal> attribute on the <literal>&lt;http&gt;</literal>
element. </para>
<para> The CAS sample application is a good example of the use of custom beans with the
namespace, including this syntax. If you aren't familiar with authentication entry points,
they are discussed in the <link xlink:href="#tech-auth-entry-point">technical
overview</link> chapter. </para>
</section>
</section>
<section xml:id="ns-session-fixation">
<title>Session Fixation Attack Protection</title>
<para>
<link xlink:href="http://en.wikipedia.org/wiki/Session_fixation">Session fixation</link>
attacks are a potential risk where it is possible for a malicious attacker to create a
session by accessing a site, then persuade another user to log in with the same session (by
sending them a link containing the session identifier as a parameter, for example). Spring
Security protects against this automatically by creating a new session when a user logs in.
If you don't require this protection, or it conflicts with some other requirement, you can
control the behaviour using the <literal>session-fixation-protection</literal> attribute on
<literal>&lt;http&gt;</literal>, which has three options <itemizedlist>
<listitem>
<para><literal>migrateSession</literal> - creates a new session and copies the existing
session attributes to the new session. This is the default.</para>
</listitem>
<listitem>
<para><literal>none</literal> - Don't do anything. The original session will be
retained.</para>
</listitem>
<listitem>
<para><literal>newSession</literal> - Create a new "clean" session, without copying the
existing session data.</para>
</listitem>
</itemizedlist></para>
</section>
</section>
<section xml:id="ns-method-security">
<title>Method Security</title>
<para> Spring Security 2.0 has improved support substantially for adding security to your
service layer methods. If you are using Java 5 or greater, then support for JSR-250 security
annotations is provided, as well as the framework's native <literal>@Secured</literal>
annotation. You can apply security to a single bean, using the
<literal>intercept-methods</literal> element to decorate the bean declaration, or you can
secure multiple beans across the entire service layer using the AspectJ style pointcuts. </para>
<section xml:id="ns-global-method">
<title>The <literal>&lt;global-method-security&gt;</literal> Element</title>
<para> This element is used to enable annotation-based security in your application (by
setting the appropriate attributes on the element), and also to group together security
pointcut declarations which will be applied across your entire application context. You
should only declare one <literal>&lt;global-method-security&gt;</literal> element. The
following declaration would enable support for both Spring Security's
<literal>@Secured</literal>, and JSR-250 annotations: <programlisting><![CDATA[
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled"/>
]]>
</programlisting> Adding an annotation to a method (on an class or interface) would then limit
the access to that method accordingly. Spring Security's native annotation support defines a
set of attributes for the method. These will be passed to the
<interfacename>AccessDecisionManager</interfacename> for it to make the actual decision.
This example is taken from the <link xlink:href="#tutorial-sample">tutorial sample</link>,
which is a good starting point if you want to use method security in your application:
<programlisting language="java">
public interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account[] findAccounts();
@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
}
</programlisting></para>
<section xml:id="ns-protect-pointcut">
<title>Adding Security Pointcuts using <literal>protect-pointcut</literal></title>
<para> The use of <literal>protect-pointcut</literal> is particularly powerful, as it allows
you to apply security to many beans with only a simple declaration. Consider the following
example: <programlisting language="xml"><![CDATA[
<global-method-security>
<protect-pointcut expression="execution(* com.mycompany.*Service.*(..))" access="ROLE_USER"/>
</global-method-security>
]]>
</programlisting> This will protect all methods on beans declared in the application
context whose classes are in the <literal>com.mycompany</literal> package and whose class
names end in "Service". Only users with the <literal>ROLE_USER</literal> role will be able
to invoke these methods. As with URL matching, the most specific matches must come first
in the list of pointcuts, as the first matching expression will be used. </para>
</section>
</section>
<section xml:id="ns-intercept-methods">
<title>The <literal>intercept-methods</literal> Bean Decorator</title>
<para> This alternative syntax allows you to specify security for a specific bean by adding
this element within the bean itself. <programlisting language="xml"><![CDATA[
<bean:bean id="target" class="com.mycompany.myapp.MyBean">
<intercept-methods>
<protect method="set*" access="ROLE_ADMIN" />
<protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
<protect method="doSomething" access="ROLE_USER" />
</intercept-methods>
</bean:bean>
]]></programlisting> This allows you to configure security attributes for individual methods on the
bean or simple wildcarded patterns. </para>
</section>
</section>
<section xml:id="ns-access-manager">
<title>The Default AccessDecisionManager</title>
<para> This section assumes you have some knowledge of the underlying architecture for
access-control within Spring Security. If you don't you can skip it and come back to it later,
as this section is only really relevant for people who need to do some customization in order
to use more than simple role based security. </para>
<para> When you use a namespace configuration, a default instance of
<interfacename>AccessDecisionManager</interfacename> is automatically registered for you and
will be used for making access decisions for method invocations and web URL access, based on
the access attributes you specify in your <literal>intercept-url</literal> and
<literal>protect-pointcut</literal> declarations (and in annotations if you are using
annotation secured methods). </para>
<para> The default strategy is to use an <classname>AffirmativeBased</classname>
<interfacename>AccessDecisionManager</interfacename> with a <classname>RoleVoter</classname>
and an <classname>AuthenticatedVoter</classname>. </para>
<section xml:id="ns-custom-access-mgr">
<title>Customizing the AccessDecisionManager</title>
<para> If you need to use a more complicated access control strategy then it is easy to set an
alternative for both method and web security. </para>
<para> For method security, you do this by setting the
<literal>access-decision-manager-ref</literal> attribute on
<literal>global-method-security</literal>to the Id of the appropriate
<interfacename>AccessDecisionManager</interfacename> bean in the application context: <programlisting language="xml"><![CDATA[
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>
]]></programlisting></para>
<para> The syntax for web security is the same, but on the <literal>http</literal> element: <programlisting><![CDATA[
<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>
]]></programlisting></para>
</section>
</section>
<section xml:id="ns-auth-manager">
<title>The Default Authentication Manager</title>
<para> We've touched on the idea that the namespace configuration automatically registers an
authentication manager bean for you. This is an instance of Spring Security's
<classname>ProviderManager</classname> class, which you may already be familiar with if
you've used the framework before. You can't use a custom
<classname>AuthenticationManager</classname> if you are using either HTTP or method security
through the namespace, but this should not be a problem as you have full control over the
<classname>AuthenticationProvider</classname>s that are used. </para>
<para> You may want to register additional <classname>AuthenticationProvider</classname> beans
with the <classname>ProviderManager</classname> and you can do this using the
<literal>&lt;custom-authentication-provider&gt;</literal> element within the bean. For
example: <programlisting language="xml"><![CDATA[
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<security:custom-authentication-provider />
...
</bean>
]]></programlisting></para>
<para> Another common requirement is that another bean in the context may require a reference to
the <interfacename>AuthenticationManager</interfacename>. There is a special element which
lets you register an alias for the <interfacename>AuthenticationManager</interfacename> and
you can then use this name elsewhere in your application context. <programlisting language="xml"><![CDATA[
<security:authentication-manager alias="authenticationManager"/>
<bean id="customizedFormLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter">
<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER "/>
<property name="authenticationManager" ref="authenticationManager"/>
...
</bean>
]]></programlisting></para>
</section>
</chapter>
+101
View File
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!DOCTYPE t:templates [
<!ENTITY hsize0 "10pt">
<!ENTITY hsize1 "12pt">
<!ENTITY hsize2 "14.4pt">
<!ENTITY hsize3 "17.28pt">
<!ENTITY hsize4 "20.736pt">
<!ENTITY hsize5 "24.8832pt">
<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 -->
<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 -->
<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 -->
<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 -->
<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 -->
<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 -->
]>
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<t:titlepage t:element="book" t:wrapper="fo:block">
<t:titlepage-content t:side="recto">
<title
t:named-template="division.title"
param:node="ancestor-or-self::book[1]"
text-align="center"
font-size="&hsize5;"
space-before="&hsize5space;"
font-weight="bold"
font-family="{$title.fontset}"
/>
<subtitle
text-align="center"
font-size="&hsize4;"
space-before="&hsize4space;"
font-family="{$title.fontset}"
/>
<corpauthor space-before="0.5em"
font-size="&hsize2;"
/>
<authorgroup space-before="0.5em"
font-size="&hsize2;"
/>
<author space-before="0.5em" font-size="&hsize2;"/>
<mediaobject space-before="2em" space-after="2em"/>
<releaseinfo space-before="5em" font-size="&hsize2;"/>
<othercredit space-before="2em" font-weight="normal" font-size="8"/>
<pubdate space-before="0.5em"/>
<revision space-before="0.5em"/>
<revhistory space-before="0.5em"/>
<abstract space-before="0.5em"
text-align="start"
margin-left="0.1in"
margin-right="0.1in"
font-family="{$body.fontset}"
/>
</t:titlepage-content>
<t:titlepage-content t:side="verso" text-align="start">
<copyright space-before="1.5em"/>
<legalnotice space-before="15em"/>
</t:titlepage-content>
<t:titlepage-separator>
</t:titlepage-separator>
<t:titlepage-before t:side="recto">
</t:titlepage-before>
<t:titlepage-before t:side="verso">
</t:titlepage-before>
</t:titlepage>
<!-- ==================================================================== -->
</t:templates>
+194
View File
@@ -0,0 +1,194 @@
<?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 confiuration or
are planning on writing your own implementation then an understanding of how the
provided implementations work will be useful. You will find classes under the
<package>org.springframework.security.web.authentication.preauth</package>. We just provide an outline
here so you should consult the Javadoc and source where appropriate.
</para>
<section>
<title>AbstractPreAuthenticatedProcessingFilter</title>
<para>
This class will check the current contents of the security context and, if empty, it will attempt to extract
user information from the HTTP request and submit it to the <interfacename>AuthenticationManager</interfacename>.
Subclasses override the following methods to obtain this information:
<programlisting language="java">
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
</programlisting>
After calling these, the filter will create a <classname>PreAuthenticatedAuthenticationToken</classname>
containing the returned data and submit it for authentication. By <quote>authentication</quote> here, we
really just mean further processing to perhaps load the user's authorities, but the standard Spring Security
authentication architecture is followed.
</para>
</section>
<section>
<title>AbstractPreAuthenticatedAuthenticationDetailsSource</title>
<para>
Like other Spring Security authentication filters, the pre-authentication filter has an
<literal>authenticationDetailsSource</literal> property which by default will create a
<classname>WebAuthenticationDetails</classname> object to store additional information such as
the session-identifier and originating IP address in the <literal>details</literal> property of
the <interfacename>Authentication</interfacename> object.
In cases where user role information can be obtained from the pre-authentication mechanism, the
data is also stored in this property. Subclasses of
<classname>AbstractPreAuthenticatedAuthenticationDetailsSource</classname> use an extended details
object which implements the <interfacename>GrantedAuthoritiesContainer</interfacename> interface, thus enabling the
authentication provider to read the authorities which were externally allocated to the user. We'll look at a concrete
example next.
</para>
<section xml:id="j2ee-preauth-details">
<title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title>
<para>
If the filter is configured with an <literal>authenticationDetailsSource</literal> which is an instance of this
class, the authority information is obtained by calling the <methodname>isUserInRole(String role)</methodname> method
for each of a pre-determined set of <quote>mappable roles</quote>. The class gets these from a configured
<interfacename>MappableAttributesRetriever</interfacename>. Possible implementations include hard-coding a list in the application
context and reading the role information from the <literal>&lt;security-role&gt;</literal> information in a
<filename>web.xml</filename> file. The pre-authentication sample application uses the latter approach.
</para>
<para>There is an additional stage where the roles (or attributes) are mapped to Spring Security
<interfacename>GrantedAuthority</interfacename> objects using a configured
<interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>. The default will just add the usual <literal>ROLE_</literal>
prefix to the names, but it gives you full control over the behaviour.
</para>
</section>
</section>
<section>
<title>PreAuthenticatedAuthenticationProvider</title>
<para>
The pre-authenticated provider has little more to do than load the <interfacename>UserDetails</interfacename>
object for the user. It does this by delegating to a <interfacename>AuthenticationUserDetailsService</interfacename>.
The latter is similar to the standard <interfacename>UserDetailsService</interfacename> but takes an
<interfacename>Authentication</interfacename> object rather than just user name:
<programlisting language="java">
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>
</section>
<section>
<title>Http403ForbiddenEntryPoint</title>
<para>
The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the <link xlink:href="#tech-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 is Siteminder, which passes the username in a header called <literal>SM_USER</literal>.
This mechanism is supported by the class <classname>RequestHeaderPreAuthenticatedProcessingFilter</classname> which
simply extracts the username from the header. It defaults to using the name <literal>SM_USER</literal> as the
header name. See the Javadoc for more details.
</para>
<tip>
<para>Note that when using a system like this, the framework performs no authentication checks at all and
it is <emphasis>extremely</emphasis> important that the external system is configured properly and protects all
access to the application. If an attacker is able to forge the headers in their original request without this being
detected then they could potentially choose any userame they wished.
</para>
</tip>
<section>
<title>Siteminder Example Configuration</title>
<para>
A typical configuration using this filter would look like this:
<programlisting><![CDATA[
<bean id="siteminderFilter"
class="org.springframework.security.web.authentication.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
<security:custom-filter position="PRE_AUTH_FILTER" />
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<security:custom-authentication-provider />
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager" />
]]>
</programlisting>
We've assumed here that the security namespace is being used for configuration (hence the user of the <literal>custom-filter</literal>,
<literal>authentication-manager</literal> and <literal>custom-authentication-provider</literal> elements (you can read more about them
in the <link xlink:href="ns-config">namespace chapter</link>). You would leave these out of a traditional bean configuration.
It's also assumed that you have added a <interfacename>UserDetailsService</interfacename> (called <quote>userDetailsService</quote>)
to your configuration to load the user's roles.
</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>
</section>
</section>
</chapter>
@@ -0,0 +1,181 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="remember-me"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Remember-Me Authentication</title></info>
<section xml:id="remember-me-overview">
<info><title>Overview</title></info>
<para>Remember-me or persistent-login authentication refers to web sites being able to
remember the identity of a principal between sessions. This is
typically accomplished by sending a cookie to the browser, with the
cookie being detected during future sessions and causing automated
login to take place. Spring Security provides the necessary hooks for
these operations to take place, and has two concrete
remember-me implementations. One uses hashing to preserve the security of
cookie-based tokens and the other uses a database or other persistent storage
mechanism to store the generated tokens. </para>
<para>
Note that both implemementations require a <interfacename>UserDetailsService</interfacename>.
If you are using an authentication provider which doesn't use a <interfacename>UserDetailsService</interfacename>
(for example, the LDAP provider) then it won't work unless you also have a <interfacename>UserDetailsService</interfacename>
bean in your application context.
</para>
</section>
<section xml:id="remember-me-hash-token">
<title>Simple Hash-Based Token Approach</title>
<para>This approach uses hashing to achieve a useful remember-me strategy.
In essence a cookie is sent to the browser upon successful interactive authentication, with the
cookie being composed as follows:
<programlisting>
base64(username + ":" + expirationTime + ":" + md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
username: As identifiable to the <interfacename>UserDetailsService</interfacename>
password: That matches the one in the retrieved UserDetails
expirationTime: The date and time when the remember-me token expires, expressed in milliseconds
key: A private key to prevent modification of the remember-me token
</programlisting></para>
<para>As such the remember-me token is valid only for the period
specified, and provided that the username, password and key does not
change. Notably, this has a potential security issue in that a
captured remember-me token will be usable from any user agent until
such time as the token expires. This is the same issue as with digest
authentication. If a principal is aware a token has been captured,
they can easily change their password and immediately invalidate all
remember-me tokens on issue. If more significant security is
needed you should use the approach described in the next section. Alternatively
remember-me services should simply not be used at all.</para>
<para>If you are familiar with the topics discussed in the chapter on <link xlink:href="ns-config">namespace configuration</link>,
you can enable remember-me authentication just by adding the <literal>&lt;remember-me&gt;</literal> element:
<programlisting><![CDATA[
<http>
...
<remember-me key="myAppKey"/>
</http>
]]>
</programlisting>
It is automatically enabled for you if you are using the <link xlink:href="ns-auto-config">auto-config</link> setting.
The <interfacename>UserDetailsService</interfacename> will normally be selected automatically. If you have more than one in
your application context, you need to specify which one should be used with the <literal>user-service-ref</literal> attribute,
where the value is the name of your <interfacename>UserDetailsService</interfacename> bean.
</para>
</section>
<section xml:id="remember-me-persistent-token">
<title>Persistent Token Approach</title>
<para>This approach is based on the article
<link xlink:href="http://jaspan.com/improved_persistent_login_cookie_best_practice">http://jaspan.com/improved_persistent_login_cookie_best_practice</link>
with some minor modifications <footnote><para>Essentially, the username is not included in the cookie, to prevent exposing a valid login
name unecessarily. There is a discussion on this in the comments section of this article.</para></footnote>.
To use the this approach with namespace configuration, you would supply a datasource reference:
<programlisting><![CDATA[
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
]]>
</programlisting>
The database should contain a <literal>persistent_logins</literal> table, created using the following SQL (or equivalent):
<programlisting>
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>
<!-- TODO: Add more info on the implementation and behaviour when tokens are stolen etc. Also some info for admins on invalidating tokens using key, or deleting info from db -->
</section>
<section xml:id="remember-me-impls">
<info><title>Remember-Me Interfaces and Implementations</title></info>
<para>Remember-me authentication is not used with basic
authentication, given it is often not used with
<literal>HttpSession</literal>s. Remember-me is used with
<literal>UsernamePasswordAuthenticationProcessingFilter</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>
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication);
</programlisting>
Please refer to the JavaDocs for a fuller discussion on what the
methods do, although note at this stage that
<literal>AbstractAuthenticationProcessingFilter</literal> only calls the
<literal>loginFail()</literal> and <literal>loginSuccess()</literal>
methods. The <literal>autoLogin()</literal> method is called by
<classname>RememberMeProcessingFilter</classname> whenever the
<classname>SecurityContextHolder</classname> does not contain an
<interfacename>Authentication</interfacename>. This interface therefore provides
the underlying remember-me implementation with sufficient
notification of authentication-related events, and delegates to the
implementation whenever a candidate web request might contain a cookie
and wish to be remembered. This design allows any number of remember-me implementation
strategies. We've seen above that Spring Security provides
two implementations. We'll look at thes in turn.</para>
<section>
<title>TokenBasedRememberMeServices</title>
<para>
This implementation supports the simpler approach described in <xref linkend="remember-me-hash-token"/>.
<classname>TokenBasedRememberMeServices</classname> generates a
<literal>RememberMeAuthenticationToken</literal>, which is processed
by <literal>RememberMeAuthenticationProvider</literal>. A
<literal>key</literal> is shared between this authentication provider
and the <literal>TokenBasedRememberMeServices</literal>. In addition,
<literal>TokenBasedRememberMeServices</literal> requires A
UserDetailsService from which it can retrieve the username and
password for signature comparison purposes, and generate the
<literal>RememberMeAuthenticationToken</literal> to contain the
correct <interfacename>GrantedAuthority</interfacename>[]s. Some sort of logout
command should be provided by the application that invalidates the cookie if
the user requests this. <classname>TokenBasedRememberMeServices</classname> also implements Spring Security's
<interfacename>LogoutHandler</interfacename> interface so can be used with <classname>LogoutFilter</classname>
to have the cookie cleared automatically.
</para>
<para>The beans required in an application context to enable remember-me services are as follows:
<programlisting><![CDATA[
<bean id="rememberMeProcessingFilter"
class="org.springframework.security.web.authentication.rememberme.RememberMeProcessingFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
<bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>
]]>
</programlisting>Don't forget to add your
<interfacename>RememberMeServices</interfacename> implementation to your
<literal>UsernamePasswordAuthenticationProcessingFilter.setRememberMeServices()</literal>
property, include the
<literal>RememberMeAuthenticationProvider</literal> in your
<literal>AuthenticationManager.setProviders()</literal> list, and add
<classname>RememberMeProcessingFilter</classname> into your
<classname>FilterChainProxy</classname> (typically immediately after your
<literal>UsernamePasswordAuthenticationProcessingFilter</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>
</section>
</section>
</chapter>
@@ -0,0 +1,104 @@
<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>
<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>
<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>
</section>
<section xml:id="runas-config">
<info><title>Configuration</title></info>
<para>A <literal>RunAsManager</literal> interface is provided by Spring Security:
<programlisting>
Authentication buildRunAs(Authentication authentication, Object object, List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
</programlisting>
</para>
<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,
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>RUN_AS_SERVER</literal> will result in the replacement
<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>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">
<property name="key" value="my_run_as_password"/>
</bean>
<bean id="runAsAuthenticationProvider"
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>
</section>
</chapter>
+117
View File
@@ -0,0 +1,117 @@
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"
version="5.0" xml:id="sample-apps">
<info>
<title xml:id="samples">Sample Applications</title>
</info>
<para> There are several sample web applications that are available with the project. To avoid
an overly large download, only the "tutorial" and "contacts" samples are included in the
distribution zip file. You can either build the others yourself, or you can obtain the war
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.springframework.org/spring-security/">
http://www.springframework.org/spring-security/ </link> if you need it. All paths
referred to in this chapter are relative to the source directory, once you have checked it
out from subversion. </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="#form">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>
</section>
<section xml:id="contacts-sample">
<title>Contacts</title>
<para> The Contacts Sample is an advanced example in that it illustrates the more powerful
features of domain object access control lists (ACLs) in addition to basic application
security. The application provides an interface with which the users are able to
administer a simple database of contacts (the domain objects).</para>
<para>To deploy, simply copy the WAR file from Spring Security distribution into your
containers <literal>webapps</literal> directory. The war should be called
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended
version number will vary depending on what release you are using). </para>
<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>
<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:
<literallayout>
Authentication object is of type: org.springframework.security.authentication.UsernamePasswordAuthenticationToken
Authentication object as a String:
org.springframework.security.providers.UsernamePasswordAuthenticationToken@1f127853:
Principal: org.springframework.security.userdetails.User@b07ed00:
Username: rod; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true;
credentialsNonExpired: true; AccountNonLocked: true;
Granted Authorities: ROLE_SUPERVISOR, ROLE_USER; Password: [PROTECTED]; Authenticated: true;
Details: org.springframework.security.ui.WebAuthenticationDetails@0:
RemoteIpAddress: 127.0.0.1; SessionId: k5qypsawgpwb;
Granted Authorities: ROLE_SUPERVISOR, ROLE_USER
Authentication object holds the following granted authorities:
ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR)
ROLE_USER (getAuthority(): ROLE_USER)
SUCCESS! Your web filters appear to be properly configured!
</literallayout></para>
<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
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
the application context XML files.</para>
<!--
TODO: Reintroduce standalone client example.
<para>The Contacts sample application also includes a
<literal>client</literal> directory. Inside you will find a small
application that queries the backend business objects using several
web services protocols. This demonstrates how to use Spring Security
for authentication with Spring remoting protocols. To try this client,
ensure your servlet container is still running the Contacts sample
application, and then execute <literal>client rod koala</literal>. The
command-line parameters respectively represent the username to use,
and the password to use. Note that you may need to edit
<literal>client.properties</literal> to use a different target
URL.</para>
-->
</section>
<section xml:id="ldap-sample">
<title>LDAP Sample</title>
<para> The LDAP sample application provides a basic configuration and sets up both a
namespace configuration and an equivalent configuration using traditional beans, both in
the same application context file. This means there are actually two identical
authentication providers configured in this application. </para>
</section>
<section xml:id="cas-sample">
<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>
</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
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>
</section>
</chapter>
+327
View File
@@ -0,0 +1,327 @@
<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">
<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>MethodDefinitionSource</interfacename>
instance to obtain the configuration attributes that apply to a particular method invocation.
<classname>MapBasedMethodDefinitionSource</classname> is used to store configuration attributes keyed by method names
(which can be wildcarded) and will be used internally when the attributes are defined in the application context using
the <literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal> elements. Other implementations
will be used to handle annotation-based configuration.
</para>
<section>
<title>Explicit MethodSecurityIterceptor 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.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<value>
com.mycompany.BankManager.delete*=ROLE_SUPERVISOR
com.mycompany.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
</value>
</property>
</bean> ]]>
</programlisting>
</para>
</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[
<bean id="bankManagerSecurity"
class="org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<value>
com.mycompany.BankManager.delete*=ROLE_SUPERVISOR
com.mycompany.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
</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>
package org.springframework.security.samples.aspectj;
import org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.intercept.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
&amp;&amp; execution(public * *(..)) &amp;&amp; !within(DomainObjectInstanceSecurityAspect);
Object around(): domainObjectInstanceExecution() {
if (this.securityInterceptor == null) {
return proceed();
}
AspectJCallback callback = new AspectJCallback() {
public Object proceedWithObject() {
return proceed();
}
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
}
public AspectJSecurityInterceptor getSecurityInterceptor() {
return securityInterceptor;
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
throw new IllegalArgumentException("securityInterceptor required");
}
}</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[
<bean id="domainObjectInstanceSecurityAspect"
class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="aspectJSecurityInterceptor"/>
</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>
<section xml:id="filter-invocation-authorization">
<info><title>FilterInvocation Security Interceptor</title></info>
<para>To secure <classname>FilterInvocation</classname>s, developers need
to add a <classname>FilterSecurityInterceptor</classname> to their filter chain.
A typical configuration example is provided below:</para>
<para>In the application context you will need to configure three
beans:</para>
<programlisting>
<![CDATA[
<bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/acegilogin.jsp"/>
<property name="forceHttps" value="false"/>
</bean>
<bean id="filterSecurityInterceptor"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource">
<security:filter-invocation-definition-source>
<security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
<security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
</security:filter-invocation-definition-source>
</property>
</bean>]]> </programlisting>
<para>The <classname>ExceptionTranslationFilter</classname> provides
the bridge between Java exceptions and HTTP responses. It is solely
concerned with maintaining the user interface. This filter does not do
any actual security enforcement. If an
<exceptionname>AuthenticationException</exceptionname> is detected,
the filter will call the AuthenticationEntryPoint to commence the
authentication process (e.g. a user login).</para>
<para>The <interfacename>AuthenticationEntryPoint</interfacename> will be called
if the user requests a secure HTTP resource but they are not
authenticated. The class handles presenting the appropriate response
to the user so that authentication can begin. Three concrete
implementations are provided with Spring Security:
<classname>LoginUrlAuthenticationEntryPoint</classname> for
commencing a form-based authentication,
<literal>BasicProcessingFilterEntryPoint</literal> for commencing a
HTTP Basic authentication process, and
<literal>CasProcessingFilterEntryPoint</literal> for commencing a
JA-SIG Central Authentication Service (CAS) login. The
<classname>LoginUrlAuthenticationEntryPoint</classname> and
<literal>CasProcessingFilterEntryPoint</literal> have optional
properties related to forcing the use of HTTPS, so please refer to the
JavaDocs if you require this.</para>
<para><classname>FilterSecurityInterceptor</classname> is responsible for
handling the security of HTTP resources. Like any other security
interceptor, it requires a reference to an
<interfacename>AuthenticationManager</interfacename> and an
<interfacename>AccessDecisionManager</interfacename>, which are both discussed in
separate sections below. The
<classname>FilterSecurityInterceptor</classname> is also configured with
configuration attributes that apply to different HTTP URL requests. A
full discussion of configuration attributes is provided in the High
Level Design section of this document.</para>
<para>The <classname>FilterSecurityInterceptor</classname> can be
configured with configuration attributes in two ways. The first,
which is shown above, is using the <literal>&lt;filter-invocation-definition-source&gt;</literal>
namespace element. This is similar to the <literal>&lt;filter-chain-map&gt;</literal>
used to configure a <classname>FilterChainProxy</classname> but the <literal>&lt;intercept-url&gt;</literal>
child elements only use the <literal>pattern</literal> and <literal>access</literal> attributes.
The second is by writing your own
<interfacename>SecurityMetadataSource</interfacename>, although this is beyond the
scope of this document. Irrespective of the approach used, the
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning
a <literal>List&lt;ConfigAttribute&gt;</literal> containing
all of the configuration 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>FilterInvocationDefinitionSource</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>FilterInvocationDefinitionSource</interfacename> as an
<interfacename>SecurityMetadataSource</interfacename>, as the distinction is of
little relevance to most users of the
<classname>FilterSecurityInterceptor</classname>.</para>
<para>When using the namespace option to configure the interceptor,
commas are used to delimit the different configuration
attributes that apply to each HTTP URL. Each configuration attribute
is assigned into its own <literal>SecurityConfig</literal> object. The
<literal>SecurityConfig</literal> object is discussed in the High
Level Design section. The <interfacename>SecurityMetadataSource</interfacename>
created by the property editor,
<interfacename>FilterInvocationDefinitionSource</interfacename>, matches
configuration attributes against <literal>FilterInvocations</literal>
based on expression evaluation of the request URL. Two standard
expression syntaxes are supported. The default is to treat all
expressions as Apache Ant paths and regular expressions are also supported
for ore complex cases. The <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. For example, the
previous configuration using regular expressions instead of Ant paths would be
written as follows:</para>
<programlisting><![CDATA[
<bean id="filterInvocationInterceptor"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="runAsManager" ref="runAsManager"/>
<property name="securityMetadataSource">
<security:filter-invocation-definition-source path-type="regex">
<security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
<security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
</security:filter-invocation-definition-source>
</property>
</bean>]]> </programlisting>
<para>Irrespective of the type of expression syntax used, expressions
are always evaluated in the order they are defined. Thus it is
important that more specific expressions are defined higher in the
list than less specific expressions. 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>
<para>As with other security interceptors, the
<literal>validateConfigAttributes</literal> property is observed. When
set to <literal>true</literal> (the default), at startup time the
<classname>FilterSecurityInterceptor</classname> will evaluate if the
provided configuration attributes are valid. It does this by checking
each configuration attribute can be processed by either the
<interfacename>AccessDecisionManager</interfacename> or the
<literal>RunAsManager</literal>. If neither of these can process a
given configuration attribute, an exception is thrown.</para>
</section>
</chapter>
@@ -0,0 +1,80 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="siteminder"><info><title>Siteminder Authentication Mechanism</title></info>
<section xml:id="siteminder-overview"><info><title>Overview</title></info>
<para>Siteminder is a commercial single sign on solution by Computer
Associates.</para>
<para>Spring Security provides a filter,
<literal>SiteminderUsernamePasswordAuthenticationProcessingFilter</literal> and
provider, <literal>SiteminderAuthenticationProvider</literal> that can
be used to process requests that have been pre-authenticated by
Siteminder. This filter assumes that you're using Siteminder for
<emphasis>authentication</emphasis>, and that you're using Spring
Security for <emphasis>authorization</emphasis>. The use of Siteminder
for <emphasis>authorization</emphasis> is not yet directly supported
by Spring Security.</para>
<para>When using Siteminder, an agent is setup on your web server to
intercept a principal's first call to your application. The agent
redirects the web request to a single sign-on login page, and once
authenticated, your application receives the request. Inside the HTTP
request is a header - such as <literal>SM_USER</literal> - which
identifies the authenticated principal (please refer to your
organization's "single sign-on" group for header details in your
particular configuration).</para>
</section>
<section xml:id="siteminder-config"><info><title>Configuration</title></info>
<para>The first step in setting up Spring Security's Siteminder
support is to define the authentication mechanism that will inspect
the HTTP header discussed earlier. It will be responsible for
generating a <literal>UsernamePasswordAuthenticationToken</literal>
that is later sent to the
<literal>SiteminderAuthenticationProvider</literal>. Let's look at an
example:</para>
<para><programlisting>&lt;bean id="authenticationProcessingFilter"
class="org.springframework.security.ui.webapp.SiteminderUsernamePasswordAuthenticationProcessingFilter"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="authenticationFailureUrl"&gt;&lt;value&gt;/login.jsp?login_error=1&lt;/value&gt;&lt;/property&gt;
&lt;property name="defaultTargetUrl"&gt;&lt;value&gt;/security.do?method=getMainMenu&lt;/value&gt;&lt;/property&gt;
&lt;property name="filterProcessesUrl"&gt;&lt;value&gt;/j_spring_security_check&lt;/value&gt;&lt;/property&gt;
&lt;property name="siteminderUsernameHeaderKey"&gt;&lt;value&gt;SM_USER&lt;/value&gt;&lt;/property&gt;
&lt;property name="formUsernameParameterKey"&gt;&lt;value&gt;j_username&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>In our example above, the bean is being provided an
<interfacename>AuthenticationManager</interfacename>, as is normally needed by
authentication mechanisms. Several URLs are also specified, with the
values being self-explanatory. It's important to also specify the HTTP
header that Spring Security should inspect. If you additionally want
to support form-based authentication (i.e. in your development
environment where Siteminder is not installed), specify the form's
username parameter as well - just don't do this in production!</para>
<para>Note that you'll need a
<literal>SiteminderAuthenticationProvider</literal>
configured against your <literal>ProviderManager</literal> in order to
use the Siteminder authentication mechanism. Normally an
<classname>AuthenticationProvider</classname> expects the password
property to match what it retrieves from the
<literal>UserDetailsSource</literal>, but in this case, authentication
has already been handled by Siteminder, so password property is not
even relevant. This may sound like a security weakness, but remember
that users have to authenticate with Siteminder before your
application ever receives the requests, so the purpose of your custom
<interfacename>UserDetailsService</interfacename> should simply be to build the
complete <interfacename>Authentication</interfacename> object (ie with suitable
<literal>GrantedAuthority[]</literal>s).</para>
<para>Advanced tip and word to the wise: If you additionally want to
support form-based authentication in your development environment
(where Siteminder is typically not installed), specify the form's
username parameter as well. Just don't do this in production!</para>
</section>
</chapter>
+150
View File
@@ -0,0 +1,150 @@
<?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><author>
<personname>Ben Alex, Luke Taylor</personname>
</author>
<releaseinfo>3.0.0.M1</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 an in-depth understaning
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, an understanding of which is important if you need
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 had 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. </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>Overall Architecture</title>
<partintro>
<para>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 introduce Spring Security, before examining these central elements
that are necessary to successfully planning and executing a Spring Security
integration.</para>
</partintro>
<xi:include href="technical-overview.xml"/>
<xi:include href="supporting-infrastructure.xml"/>
<xi:include href="channel-security.xml"/>
</part>
<part xml:id="authentication">
<title>Authentication</title>
<partintro>
<para>We've already introduced Spring Security's authentication architecture in the <link
xlink:href="#technical-overview">Technical Overview</link> chapter. In this part of the
reference guide we will examine individual authentication mechanisms and their corresponding
<classname>AuthenticationProvider</classname>s. We'll also look at how to configure
authentication more generally, including if you have several authentication approaches that
need to be chained together.</para>
<para> With some exceptions, we will be discussing the full details of Spring Security bean
configuration rather than the shorthand <link xlink:href="#ns-config">namespace
syntax</link>. You should review the introduction to using namespace configuration and the
options it provides to see if they will meet your needs. As you come to use the framework
more, and need to customize the internal behaviour, you will probably want to understand
more about how the individual services are implemented, which classes to look at extending
and so on. This part is more targeted at providing this kind of information. We'd recommend
that you supplement the content by browsing the Javadoc and the source itself <footnote>
<para>Links to both Javadoc APIs and browsable source cross-reference are available from
the project web site.</para>
</footnote>. </para>
</partintro>
<xi:include href="common-auth-services.xml"/>
<xi:include href="dao-auth-provider.xml"/>
<xi:include href="ldap-auth-provider.xml"/>
<xi:include href="form-authentication.xml"/>
<xi:include href="basic-authentication.xml"/>
<xi:include href="digest-authentication.xml"/>
<xi:include href="remember-me-authentication.xml"/>
<xi:include href="jaas-auth-provider.xml"/>
<xi:include href="preauth.xml"/>
<xi:include href="anon-auth-provider.xml"/>
<xi:include href="x509-auth-provider.xml"/>
<xi:include href="cas-auth-provider.xml"/>
<xi:include href="runas-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="domain-acls.xml"/>
</part>
<xi:include href="appendix-db-schema.xml"/>
<xi:include href="appendix-namespace.xml"/>
</book>
@@ -0,0 +1,342 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="supporting-infrastructure" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Supporting Infrastructure</title></info>
<para>This chapter introduces some of the supplementary and supporting
infrastructure used by Spring Security. If a capability is not directly
related to security, yet included in the Spring Security project, we
will discuss it in this chapter.</para>
<section xml:id="localization">
<title>Localization</title>
<para>Spring Security supports localization of exception messages that
end users are likely to see. If your application is designed for
English users, you don't need to do anything as by default all
Security Security messages are in English. If you need to support
other locales, everything you need to know is contained in this
section.</para>
<para>All exception messages can be localized, including messages
related to authentication failures and access being denied
(authorization failures). Exceptions and logging that is focused on
developers or system deployers (including incorrect attributes,
interface contract violations, using incorrect constructors, startup
time validation, debug-level logging) etc are not localized and
instead are hard-coded in English within Spring Security's
code.</para>
<para>Shipping in the <literal>spring-security-core-xx.jar</literal> you
will find an <literal>org.springframework.security</literal> package
that in turn contains a <literal>messages.properties</literal> file.
This should be referred to by your
<literal>ApplicationContext</literal>, as Spring Security classes
implement Spring's <literal>MessageSourceAware</literal> interface and
expect the message resolver to be dependency injected at application
context startup time. Usually all you need to do is register a bean
inside your application context to refer to the messages. An example
is shown below:</para>
<para><programlisting><![CDATA[
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="org/springframework/security/messages"/>
</bean>
]]></programlisting></para>
<para>The <literal>messages.properties</literal> is named in
accordance with standard resource bundles and represents the default
language supported by Spring Security messages. This default file is
in English. If you do not register a message source, Spring Security
will still work correctly and fallback to hard-coded English versions
of the messages.</para>
<para>If you wish to customize the
<literal>messages.properties</literal> file, or support other
languages, you should copy the file, rename it accordingly, and
register it inside the above bean definition. There are not a large
number of message keys inside this file, so localization should not be
considered a major initiative. If you do perform localization of this
file, please consider sharing your work with the community by logging
a JIRA task and attaching your appropriately-named localized version
of <literal>messages.properties</literal>.</para>
<para>Rounding out the discussion on localization is the Spring
<literal>ThreadLocal</literal> known as
<literal>org.springframework.context.i18n.LocaleContextHolder</literal>.
You should set the <literal>LocaleContextHolder</literal> to represent
the preferred <literal>Locale</literal> of each user. Spring Security
will attempt to locate a message from the message source using the
<literal>Locale</literal> obtained from this
<literal>ThreadLocal</literal>. Please refer to Spring documentation
for further details on using <literal>LocaleContextHolder</literal>
and the helper classes that can automatically set it for you (eg
<literal>AcceptHeaderLocaleResolver</literal>,
<literal>CookieLocaleResolver</literal>,
<literal>FixedLocaleResolver</literal>,
<literal>SessionLocaleResolver</literal> etc)</para>
</section>
<section xml:id="filters">
<info><title>Filters</title></info>
<para>Spring Security uses many filters, as referred to throughout the
remainder of this reference guide. If you are using <link xlink:href="#ns-config">namespace configuration</link>,
then the you don't usually have to declare the filter beans explicitly. There 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>
<para>In this case, you have a choice in how these filters are added to your web application, in that you can use either
Spring's <literal>DelegatingFilterProxy</literal> or
<classname>FilterChainProxy</classname>. We'll look at both below.</para>
<para>When using <literal>DelegatingFilterProxy</literal>, you will see
something like this in the web.xml file:
<programlisting>
&lt;filter&gt;
&lt;filter-name&gt;myFilter&lt;/filter-name&gt;
&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;myFilter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
</programlisting>
Notice that the filter is actually a <literal>DelegatingFilterProxy</literal>,
and not the filter that will actually implement the logic of the filter. What
<literal>DelegatingFilterProxy</literal> does is delegate the
<literal>Filter</literal>'s methods through to a bean which is
obtained from the Spring application context. This enables the bean to
benefit from the Spring web application context lifecycle support and
configuration flexibility. The bean must implement
<literal>javax.servlet.Filter</literal> and it must have the same name as that in
the <literal>filter-name</literal> element.</para>
<para>There is a lifecycle issue to consider when hosting
<literal>Filter</literal>s in an IoC container instead of a servlet
container. Specifically, which container should be responsible for
calling the <literal>Filter</literal>'s "startup" and "shutdown"
methods? It is noted that the order of initialization and destruction
of a <literal>Filter</literal> can vary by servlet container, and this
can cause problems if one <literal>Filter</literal> depends on
configuration settings established by an earlier initialized
<literal>Filter</literal>. The Spring IoC container on the other hand
has more comprehensive lifecycle/IoC interfaces (such as
<literal>InitializingBean</literal>,
<literal>DisposableBean</literal>, <literal>BeanNameAware</literal>,
<literal>ApplicationContextAware</literal> and many others) as well as
a well-understood interface contract, predictable method invocation
ordering, autowiring support, and even options to avoid implementing
Spring interfaces (eg the <literal>destroy-method</literal> attribute
in Spring XML). For this reason we recommend the use of Spring
lifecycle services instead of servlet container lifecycle services
wherever possible. Read the Javadoc for <classname>DelegatingFilterProxy</classname>
for more information</para>
<para>Rather than using <literal>DelegatingFilterProxy</literal>, we
strongly recommend that you use <classname>FilterChainProxy</classname> instead.
Whilst <literal>DelegatingFilterProxy</literal> is a very useful class,
the problem is that the number of lines of code required for
<literal>&lt;filter&gt;</literal> and
<literal>&lt;filter-mapping&gt;</literal> entries in
<literal>web.xml</literal> explodes when using more than a few
filters. To overcome this issue, Spring Security provides a
<classname>FilterChainProxy</classname> class. It is wired using a
<literal>DelegatingFilterProxy</literal> (just like in the example above),
but the target class is
<literal>org.springframework.security.web.FilterChainProxy</literal>.
The filter chain is then declared in the application context, using
code such as this:</para>
<para><programlisting><![CDATA[
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**"
filters="httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor"/>
<sec:filter-chain pattern="/**"
filters="httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor"/>
</sec:filter-chain-map>
</bean>
]]>
</programlisting></para>
<para>You may notice similarities with the way
<classname>FilterSecurityInterceptor</classname> is declared. 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>HttpSessionContextIntegrationFilter</classname>s in the filter
chain (<literal>ASC</literal> is short for
<literal>allowSessionCreation</literal>, a property of
<classname>HttpSessionContextIntegrationFilter</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>HttpSessionContextIntegrationFilter</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
<literal>init(FilterConfig)</literal> and <literal>destroy()</literal>
methods through to the underlaying <literal>Filter</literal>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> once,
irrespective of how many times it is declared by the
<interfacename>FilterInvocationDefinitionSource</interfacename>. You control the
overall choice as to whether these methods are called or not via the
<literal>targetFilterLifecycle</literal> initialization parameter of the
<literal>DelegatingFilterProxy</literal> that proxies
<literal>DelegatingFilterProxy</literal>. As discussed above, by default
any servlet container lifecycle invocations are not delegated through
to <literal>DelegatingFilterProxy</literal>.</para>
<para>You can use the attribute <literal>filters = "none"</literal>
in the same way that you do when using <link xlink:href="#namespace-auto-config">namespace configuration</link>
to build the <classname>FilterChainProxy</classname>. 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.</para>
<para>The order that filters are defined in <literal>web.xml</literal>
is very important. Irrespective of which filters you are actually
using, the order of the <literal>&lt;filter-mapping&gt;</literal>s
should be as follows:</para>
<orderedlist inheritnum="ignore" continuation="restarts">
<listitem>
<para><literal>ChannelProcessingFilter</literal>, because it might
need to redirect to a different protocol</para>
</listitem>
<listitem>
<para><literal>ConcurrentSessionFilter</literal>, 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>HttpSessionContextIntegrationFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be setup in the
<classname>SecurityContextHolder</classname> at the beginning of a web
request, and any changes to the <interfacename>SecurityContext</interfacename>
can be copied to the <literal>HttpSession</literal> when the web
request ends (ready for use with the next web request)</para>
</listitem>
<listitem>
<para>Authentication processing mechanisms -
<literal>UsernamePasswordAuthenticationProcessingFilter</literal>,
<literal>CasProcessingFilter</literal>,
<literal>BasicProcessingFilter, HttpRequestIntegrationFilter,
JbossIntegrationFilter</literal> 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><literal>AnonymousProcessingFilter</literal>, 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</para>
</listitem>
</orderedlist>
<para>All of the above filters use
<literal>DelegatingFilterProxy</literal> or
<classname>FilterChainProxy</classname>. It is recommended that a single
<literal>DelegatingFilterProxy</literal> proxy through to a single
<classname>FilterChainProxy</classname> for each application, with that
<classname>FilterChainProxy</classname> defining all of Spring Security
filters.</para>
<para>If you're using SiteMesh, ensure Spring Security filters execute
before the SiteMesh filters are called. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for
use by SiteMesh decorators</para>
</section>
<section xml:id="taglib">
<info><title>Tag Libraries</title></info>
<para>Spring Security comes bundled with several JSP tag libraries which provide a range of different
services.</para>
<section xml:id="taglib-config">
<info><title>Configuration</title></info>
<para>All taglib classes are included in the core
<literal>spring-security-xx.jar</literal> file, with the
<literal>security.tld</literal> located in the JAR's
<literal>META-INF</literal> directory. This means for JSP 1.2+ web
containers you can simply include the JAR in the WAR's
<literal>WEB-INF/lib</literal> directory and it will be available. If
you're using a JSP 1.1 container, you'll need to declare the JSP
taglib in your <literal>web.xml file</literal>, and include
<literal>security.tld</literal> in the <literal>WEB-INF/lib</literal>
directory. The following fragment is added to
<literal>web.xml</literal>:
<programlisting><![CDATA[
<taglib>
<taglib-uri>http://www.springframework.org/security/tags</taglib-uri>
<taglib-location>/WEB-INF/security.tld</taglib-location>
</taglib>
]]></programlisting></para>
</section>
<section xml:id="taglib-usage">
<info><title>Usage</title></info>
<para>Now that you've configured the tag libraries, refer to the
individual reference guide sections for details on how to use them.
Note that when using the tags, you should include the taglib reference
in your JSP:
<programlisting>
&lt;%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %&gt;
</programlisting></para>
</section>
</section>
</chapter>
+44
View File
@@ -0,0 +1,44 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="taglib">
<info><title>Tag Libraries</title></info>
<section xml:id="taglib-overview">
<info><title>Overview</title></info>
<para>Spring Security comes bundled with several JSP tag libraries
that eases JSP writing. The tag libraries provide a range of different
services.</para>
</section>
<section xml:id="taglib-config">
<info><title>Configuration</title></info>
<para>All taglib classes are included in the core
<literal>spring-security-xx.jar</literal> file, with the
<literal>security.tld</literal> located in the JAR's
<literal>META-INF</literal> directory. This means for JSP 1.2+ web
containers you can simply include the JAR in the WAR's
<literal>WEB-INF/lib</literal> directory and it will be available. If
you're using a JSP 1.1 container, you'll need to declare the JSP
taglib in your <literal>web.xml file</literal>, and include
<literal>security.tld</literal> in the <literal>WEB-INF/lib</literal>
directory. The following fragment is added to
<literal>web.xml</literal>:</para>
<para><programlisting>
&lt;taglib&gt;
&lt;taglib-uri&gt;http://www.springframework.org/security/tags&lt;/taglib-uri&gt;
&lt;taglib-location&gt;/WEB-INF/security.tld&lt;/taglib-location&gt;
&lt;/taglib&gt;
</programlisting></para>
</section>
<section xml:id="taglib-usage">
<info><title>Usage</title></info>
<para>Now that you've configured the tag libraries, refer to the
individual reference guide sections for details on how to use them.
Note that when using the tags, you should include the taglib reference
in your JSP: <programlisting>
&lt;%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %&gt;
</programlisting></para>
</section>
</chapter>
@@ -0,0 +1,587 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="technical-overview">
<info>
<title>Technical Overview</title>
</info>
<section xml:id="runtime-environment">
<info>
<title>Runtime Environment</title>
</info>
<para>Spring Security 3.0 requires a Java 5.0 Runtime Environment or higher.
As Spring Security aims to operate in a self-contained manner, there is no need
to place any special configuration files into your Java Runtime
Environment. In particular, there is no need to configure a special
Java Authentication and Authorization Service (JAAS) policy file or
place Spring Security into common classpath locations.</para>
<para>Similarly, if you are using an EJB Container or Servlet
Container there is no need to put any special configuration files
anywhere, nor include Spring Security in a server classloader. All the required
files will be contained within your application.</para>
<para>This design offers maximum deployment time flexibility, as
you can simply copy your target artifact (be it a JAR, WAR or EAR)
from one system to another and it will immediately work.</para>
</section>
<section xml:id="shared-components">
<info>
<title>Shared Components</title>
</info>
<para>Let's explore some of the most important shared components in
Spring Security. Components are considered "shared" if they are
central to the framework and the framework cannot operate without
them. These Java types represent the building blocks of the remaining
system, so it's important to understand that they're there, even if
you don't need to directly interact with them.</para>
<section>
<title>
SecurityContextHolder, SecurityContext and Authentication Objects
</title>
<para>The most fundamental object is
<classname>SecurityContextHolder</classname>. This is where we store
details of the present security context of the application, which
includes details of the principal currently using the application. By
default the <classname>SecurityContextHolder</classname> uses a
<literal>ThreadLocal</literal> to store these details, which means
that the security context is always available to methods in the same
thread of execution, even if the security context is not explicitly
passed around as an argument to those methods. Using a
<literal>ThreadLocal</literal> in this way is quite safe if care is
taken to clear the thread after the present principal's request is
processed. Of course, Spring Security takes care of this for you
automatically so there is no need to worry about it.</para>
<para>Some applications aren't entirely suitable for using a
<literal>ThreadLocal</literal>, because of the specific way they work
with threads. For example, a Swing client might want all threads in a
Java Virtual Machine to use the same security context. For this
situation you would use the
<literal>SecurityContextHolder.MODE_GLOBAL</literal>. Other
applications might want to have threads spawned by the secure thread
also assume the same security identity. This is achieved by using
<literal>SecurityContextHolder.MODE_INHERITABLETHREADLOCAL</literal>.
You can change the mode from the default
<literal>SecurityContextHolder.MODE_THREADLOCAL</literal> in two ways.
The first is to set a system property. Alternatively, call a static
method on <classname>SecurityContextHolder</classname>. Most applications
won't need to change from the default, but if you do, take a look at
the JavaDocs for <classname>SecurityContextHolder</classname> to learn
more.</para>
<para>Inside the <classname>SecurityContextHolder</classname> we store
details of the principal currently interacting with the application.
Spring Security uses an <interfacename>Authentication</interfacename> object to
represent this information. Whilst you won't normally need to create
an <interfacename>Authentication</interfacename> object yourself, it is fairly
common for users to query the <interfacename>Authentication</interfacename>
object. You can use the following code block - from anywhere in your
application - to obtain the name of the authenticated user, for example:</para>
<programlisting>
Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (obj instanceof UserDetails) {
String username = ((UserDetails)obj).getUsername();
} else {
String username = obj.toString();
}</programlisting>
<para>The above code introduces a number of interesting relationships
and key objects. First, you will notice that there is an intermediate
object between <classname>SecurityContextHolder</classname> and
<interfacename>Authentication</interfacename>. The
<literal>SecurityContextHolder.getContext()</literal> method is
actually returning a <interfacename>SecurityContext</interfacename>.
<!-- Commented out as Captcha sandboxed
Spring
Security uses a few different <interfacename>SecurityContext</interfacename>
implementations, such as if we need to store special information
related to a request that is not principal-specific.
A good example of
this is our JCaptcha integration, which needs to know whether the
current request came from a human user or not. Because such a decision
has nothing at all to do with the principal the request may or may not
be authenticated as, we store it in the
<interfacename>SecurityContext</interfacename>. -->
</para>
</section>
<section>
<title>The UserDetailsService</title>
<para>Another item to note from the above code fragment is that you
can obtain a principal from the <interfacename>Authentication</interfacename>
object. The principal is just an <literal>Object</literal>. Most of
the time this can be cast into a <interfacename>UserDetails</interfacename>
object. <interfacename>UserDetails</interfacename> is a central interface in
Spring Security. It represents a principal, but in an extensible and
application-specific way. Think of <interfacename>UserDetails</interfacename> as
the adapter between your own user database and what Spring Security
needs inside the <classname>SecurityContextHolder</classname>. Being a
representation of something from your own user database, quite often
you will cast the <interfacename>UserDetails</interfacename> to the original
object that your application provided, so you can call
business-specific methods (like <literal>getEmail()</literal>,
<literal>getEmployeeNumber()</literal> and so on).</para>
<para>By now you're probably wondering, so when do I provide a
<interfacename>UserDetails</interfacename> object? How do I do that? I thought you
said this thing was declarative and I didn't need to write any Java
code - what gives? The short answer is that there is a special
interface called <interfacename>UserDetailsService</interfacename>. The only
method on this interface accepts a <literal>String</literal>-based
username argument and returns a <interfacename>UserDetails</interfacename>. Most
authentication providers that ship with Spring Security delegate to a
<interfacename>UserDetailsService</interfacename> as part of the authentication
process. The <interfacename>UserDetailsService</interfacename> is used to build
the <interfacename>Authentication</interfacename> object that is stored in the
<classname>SecurityContextHolder</classname>. The good news is that we
provide a number of <interfacename>UserDetailsService</interfacename>
implementations, including one that uses an in-memory map and another
that uses JDBC. Most users tend to write their own, though, with such
implementations often simply sitting on top of an existing Data Access
Object (DAO) that represents their employees, customers, or other
users of the enterprise application. Remember the advantage that
whatever your UserDetailsService returns can always be obtained from
the <classname>SecurityContextHolder</classname>, as per the above code
fragment.</para>
</section>
<section xml:id="tech-granted-authority">
<title>GrantedAuthority</title>
<para>Besides the principal, another important method provided by
<interfacename>Authentication</interfacename> is
<literal>getAuthorities(</literal>). This method provides an array of
<interfacename>GrantedAuthority</interfacename> objects. A
<interfacename>GrantedAuthority</interfacename> is, not surprisingly, an authority
that is granted to the principal. Such authorities are usually
"roles", such as <literal>ROLE_ADMINISTRATOR</literal> or
<literal>ROLE_HR_SUPERVISOR</literal>. These roles are later on
configured for web authorization, method authorization and domain
object authorization. Other parts of Spring Security are capable of
interpreting these authorities, and expect them to be present.
<interfacename>GrantedAuthority</interfacename> objects are usually loaded by the
<interfacename>UserDetailsService</interfacename>.</para>
<para>Usually the <interfacename>GrantedAuthority</interfacename> objects are
application-wide permissions. They are not specific to a given domain
object. Thus, you wouldn't likely have a
<interfacename>GrantedAuthority</interfacename> to represent a permission to
<literal>Employee</literal> object number 54, because if there are
thousands of such authorities you would quickly run out of memory (or,
at the very least, cause the application to take a long time to
authenticate a user). Of course, Spring Security is expressly designed
to handle this common requirement, but you'd instead use the project's
domain object security capabilities for this purpose.</para>
</section>
<section xml:id="tech-sec-context-persistence">
<title>Storing the <interfacename>SecurityContext</interfacename></title>
<para>Last but not least, depending on the type of application, there may need to be
a strategy in place to store the security context between user operations.
In a typical web application, for example, a user logs in once and is subsequently identified
by their session Id. The server caches the principal information for the duration session.
In Spring Security, the responsibility for storing the <interfacename>SecurityContext</interfacename>
between requests falls to the <classname>SecurityContextPersistenceFilter</classname>, which
by default stores the context as an <literal>HttpSession</literal> attribute between HTTP
requests. It restores the context to the <classname>SecurityContextHolder</classname> for each request
and, crucially, clears the <classname>SecurityContextHolder</classname> when the request completes.
You should never interact directly with the <literal>HttpSession</literal> for security purposes.
There is simply no justification for doing so - always use the <classname>SecurityContextHolder</classname>
instead.
</para>
<para>
Many other types of application (for example, a stateless RESTful web service) do not use HTTP sessions and
will re-authenticate on every request. However, it is still important that the
<classname>SecurityContextPersistenceFilter</classname> is included in the
chain to make sure that the <classname>SecurityContextHolder</classname> is cleared after each request,
even if
</para>
</section>
<section>
<title>Summary</title>
<para>Just to recap, the major building blocks of Spring Security
are:</para>
<itemizedlist spacing="compact">
<listitem>
<para><classname>SecurityContextHolder</classname>, to provide any
type access to the <interfacename>SecurityContext</interfacename>.</para>
</listitem>
<listitem>
<para><interfacename>SecurityContext</interfacename>, to hold the
<interfacename>Authentication</interfacename> and possibly request-specific
security information.</para>
</listitem>
<listitem>
<para><classname>SecurityContextPersistenceFilter</classname>, to
store the <interfacename>SecurityContext</interfacename> (typically in the
<literal>HttpSession</literal>) between web requests.</para>
</listitem>
<listitem>
<para><interfacename>Authentication</interfacename>, to represent the
principal in a Spring Security-specific manner.</para>
</listitem>
<listitem>
<para><interfacename>GrantedAuthority</interfacename>, to reflect the
application-wide permissions granted to a principal.</para>
</listitem>
<listitem>
<para><interfacename>UserDetails</interfacename>, to provide the necessary
information to build an Authentication object from your
application's DAOs.</para>
</listitem>
<listitem>
<para><interfacename>UserDetailsService</interfacename>, to create a
<interfacename>UserDetails</interfacename> when passed in a
<literal>String</literal>-based username (or certificate ID or
alike).</para>
</listitem>
</itemizedlist>
<para>Now that you've gained an understanding of these repeatedly-used
components, let's take a closer look at the process of
authentication.</para>
</section>
</section>
<section xml:id="common-authentication">
<info><title>Authentication</title></info>
<para>As mentioned in the beginning of this reference guide, Spring
Security can participate in many different authentication
environments. Whilst we recommend people use Spring Security for
authentication and not integrate with existing Container Managed
Authentication, it is nevertheless supported - as is integrating with
your own proprietary authentication system. Let's first explore
authentication from the perspective of Spring Security managing web
security entirely on its own, which is illustrative of the most
complex and most common situation.</para>
<para>Consider a typical web application's authentication
process:</para>
<orderedlist inheritnum="ignore" continuation="restarts">
<listitem>
<para>You visit the home page, and click on a link.</para>
</listitem>
<listitem>
<para>A request goes to the server, and the server decides that
you've asked for a protected resource.</para>
</listitem>
<listitem>
<para>As you're not presently authenticated, the server sends back
a response indicating that you must authenticate. The response
will either be an HTTP response code, or a redirect to a
particular web page.</para>
</listitem>
<listitem>
<para>Depending on the authentication mechanism, your browser will
either redirect to the specific web page so that you can fill out
the form, or the browser will somehow retrieve your identity (eg a
BASIC authentication dialogue box, a cookie, a X509 certificate
etc).</para>
</listitem>
<listitem>
<para>The browser will send back a response to the server. This
will either be an HTTP POST containing the contents of the form
that you filled out, or an HTTP header containing your
authentication details.</para>
</listitem>
<listitem>
<para>Next the server will decide whether or not the presented
credentials are valid. If they're valid, the next step will
happen. If they're invalid, usually your browser will be asked to
try again (so you return to step two above).</para>
</listitem>
<listitem>
<para>The original request that you made to cause the
authentication process will be retried. Hopefully you've
authenticated with sufficient granted authorities to access the
protected resource. If you have sufficient access, the request
will be successful. Otherwise, you'll receive back an HTTP error
code 403, which means "forbidden".</para>
</listitem>
</orderedlist>
<para>Spring Security has distinct classes responsible for most of the
steps described above. The main participants (in the order that they
are used) are the <classname>ExceptionTranslationFilter</classname>, an
<interfacename>AuthenticationEntryPoint</interfacename>, an authentication
mechanism, and an <classname>AuthenticationProvider</classname>.</para>
<section>
<title>ExceptionTranslationFilter</title>
<para><classname>ExceptionTranslationFilter</classname> is a Spring
Security filter that has responsibility for detecting any Spring
Security exceptions that are thrown. Such exceptions will generally be
thrown by an <classname>AbstractSecurityInterceptor</classname>, which is
the main provider of authorization services. We will discuss
<classname>AbstractSecurityInterceptor</classname> in the next section,
but for now we just need to know that it produces Java exceptions and
knows nothing about HTTP or how to go about authenticating a
principal. Instead the <classname>ExceptionTranslationFilter</classname>
offers this service, with specific responsibility for either returning
error code 403 (if the principal has been authenticated and therefore
simply lacks sufficient access - as per step seven above), or
launching an <interfacename>AuthenticationEntryPoint</interfacename> (if the
principal has not been authenticated and therefore we need to go
commence step three).</para>
</section>
<section xml:id="tech-auth-entry-point">
<title>AuthenticationEntryPoint</title>
<para>The <interfacename>AuthenticationEntryPoint</interfacename> is responsible
for step three in the above list. As you can imagine, each web
application will have a default authentication strategy (well, this
can be configured like nearly everything else in Spring Security, but
let's keep it simple for now). Each major authentication system will
have its own <interfacename>AuthenticationEntryPoint</interfacename>
implementation, which takes actions such as described in step
three.</para>
<para>After your browser decides to submit your authentication
credentials (either as an HTTP form post or HTTP header) there needs
to be something on the server that "collects" these authentication
details. By now we're at step six in the above list. In Spring
Security we have a special name for the function of collecting
authentication details from a user agent (usually a web browser), and
that name is "authentication mechanism". After the authentication
details are collected from the user agent, an
"<interfacename>Authentication</interfacename> request" object is built and then
presented to an
<interfacename>AuthenticationProvider</interfacename>.</para>
</section>
<section>
<title>AuthenticationProvider</title>
<para>The last player in the Spring Security authentication process is
an <classname>AuthenticationProvider</classname>. Quite simply, it is
responsible for taking an <interfacename>Authentication</interfacename> request
object and deciding whether or not it is valid. The 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 section and refresh your memory. Most
<classname>AuthenticationProvider</classname>s will ask a
<interfacename>UserDetailsService</interfacename> to provide a
<interfacename>UserDetails</interfacename> object. As mentioned earlier, most
application will provide their own
<interfacename>UserDetailsService</interfacename>, although some will be able to
use the JDBC or in-memory implementation that ships with Spring
Security. The resultant <interfacename>UserDetails</interfacename> object - and
particularly the <literal>GrantedAuthority[]</literal>s contained
within the <interfacename>UserDetails</interfacename> object - will be used when
building the fully populated <interfacename>Authentication</interfacename>
object.</para>
<para>After the authentication mechanism receives back the
fully-populated <interfacename>Authentication</interfacename> object, it will deem
the request valid, put the <interfacename>Authentication</interfacename> into the
<classname>SecurityContextHolder</classname>, and cause the original
request to be retried (step seven above). If, on the other hand, the
<classname>AuthenticationProvider</classname> rejected the request, the
authentication mechanism will ask the user agent to retry (step two
above).</para>
</section>
<section>
<title>Setting the SecurityContextHolder Contents Directly</title>
<para>Whilst this describes the typical authentication workflow, the
good news is that Spring Security doesn't mind how you put an
<interfacename>Authentication</interfacename> inside the
<classname>SecurityContextHolder</classname>. The only critical
requirement is that the <classname>SecurityContextHolder</classname>
contains an <interfacename>Authentication</interfacename> that represents a
principal before the <classname>AbstractSecurityInterceptor</classname>
needs to authorize a request.</para>
<para>You can (and many users do) write their own filters or MVC
controllers to provide interoperability with authentication systems
that are not based on Spring Security. For example, you might be using
Container-Managed Authentication which makes the current user
available from a ThreadLocal or JNDI location. Or you might work for a
company that has a legacy proprietary authentication system, which is
a corporate "standard" over which you have little control. In such
situations it's quite easy to get Spring Security to work, and still
provide authorization capabilities. All you need to do is write a
filter (or equivalent) that reads the third-party user information
from a location, build a Spring Security-specific Authentication
object, and put it onto the SecurityContextHolder. It's quite easy to
do this, and it is a fully-supported integration approach.</para>
</section>
</section>
<section xml:id="secure-objects">
<info><title>Secure Objects</title></info>
<para>Spring Security uses the term "secure object" to refer to any
object that can have security (such as an authorization decision) applied to it.
The most common examples are method invocations and web requests.
</para>
<section>
<title>Security and AOP Advice</title>
<para>If you're familiar with AOP, you'd be aware there are different
types of advice available: before, after, throws and around. An around
advice is very useful, because an advisor can elect whether or not to
proceed with a method invocation, whether or not to modify the
response, and whether or not to throw an exception. Spring Security
provides an around advice for method invocations as well as web
requests. We achieve an around advice for method invocations using Spring's
standard AOP support and we achieve an around advice for web requests using a
standard Filter.</para>
<para>For those not familiar with AOP, the key point to understand is
that Spring Security can help you protect method invocations as well
as web requests. Most people are interested in securing method
invocations on their services layer. This is because the services
layer is where most business logic resides in current-generation J2EE
applications (for clarification, the author disapproves of this design
and instead advocates properly encapsulated domain objects together
with the DTO, assembly, facade and transparent persistence patterns,
but as use of anemic domain objects is the present mainstream approach, we'll
talk about it here). If you just need to secure method invocations to
the services layer, Spring's standard AOP (otherwise known as AOP Alliance)
will be adequate. If you need to secure domain objects directly, you
will likely find that AspectJ is worth considering.</para>
<para>You can elect to perform method authorization using AspectJ or
Spring AOP, or you can elect to perform web request authorization
using filters. You can use zero, one, two or three of these approaches
together. The mainstream usage is to perform some web request
authorization, coupled with some Spring AOP method invocation
authorization on the services layer.</para>
</section>
<section>
<title>AbstractSecurityInterceptor</title>
<para>Each secure object type supported by Spring Security has its own class,
which is a subclass of <classname>AbstractSecurityInterceptor</classname>.
Importantly, by the time the <classname>AbstractSecurityInterceptor</classname> is called, the
<classname>SecurityContextHolder</classname> will contain a valid
<interfacename>Authentication</interfacename> if the principal has been
authenticated.</para>
<para><classname>AbstractSecurityInterceptor</classname> provides a
consistent workflow for handling secure object requests, typically:
<orderedlist>
<listitem><para>Look up the "configuration attributes" associated with the
present request</para></listitem>
<listitem><para>Submitting the secure object, current <interfacename>Authentication</interfacename>
and configuration attributes to the <interfacename>AccessDecisionManager</interfacename> for
an authorization decision</para></listitem>
<listitem><para>Optionally change the <interfacename>Authentication</interfacename> under which the invocation
takes place</para></listitem>
<listitem><para>Allow the secure object to proceed (assuming access was granted)</para></listitem>
<listitem><para>Call the <literal>AfterInvocationManager</literal> if configured, once the invocation
has returned.</para></listitem>
</orderedlist>
</para>
<section>
<title>What are Configuration Attributes?</title>
<para>
A "configuration attribute" can be thought of as a String that has special meaning to the classes used by
<classname>AbstractSecurityInterceptor</classname>. They may be simple role names or have more complex meaning, depending on the
how sophisticated the <interfacename>AccessDecisionManager</interfacename> implementation is.
The <classname>AbstractSecurityInterceptor</classname> is configured with a <interfacename>SecurityMetadataSource</interfacename> which
it uses to look up the attributes for a secure object. Usually this configuration will be hidden from the user. Configuration
attributes will be entered as annotations on secured methods, or as access attributes on secured URLs (using the
namespace <literal>&lt;intercept-url&gt;</literal> syntax).
</para>
</section>
<section>
<title>RunAsManager</title>
<para>Assuming <interfacename>AccessDecisionManager</interfacename> decides to
allow the request, the <classname>AbstractSecurityInterceptor</classname>
will normally just proceed with the request. Having said that, on rare
occasions users may want to replace the
<interfacename>Authentication</interfacename> inside the
<interfacename>SecurityContext</interfacename> with a different
<interfacename>Authentication</interfacename>, which is handled by the
<interfacename>AccessDecisionManager</interfacename> calling a
<literal>RunAsManager</literal>. This might be useful in reasonably
unusual situations, such as if a services layer method needs to call a
remote system and present a different identity. Because Spring
Security automatically propagates security identity from one server to
another (assuming you're using a properly-configured RMI or
HttpInvoker remoting protocol client), this may be useful.</para>
</section>
<section>
<title>AfterInvocationManager</title>
<para>Following the secure object proceeding and then returning -
which may mean a method invocation completing or a filter chain
proceeding - the <classname>AbstractSecurityInterceptor</classname> gets
one final chance to handle the invocation. At this stage the
<classname>AbstractSecurityInterceptor</classname> is interested in
possibly modifying the return object. We might want this to happen
because an authorization decision couldn't be made "on the way in" to
a secure object invocation. Being highly pluggable,
<classname>AbstractSecurityInterceptor</classname> will pass control to an
<literal>AfterInvocationManager</literal> to actually modify the
object if needed. This class can even entirely replace the object, or
throw an exception, or not change it in any way.</para>
<para><classname>AbstractSecurityInterceptor</classname> and its related objects
are shown in <xref linkend="abstract-security-interceptor"/>.
<figure xml:id="abstract-security-interceptor">
<title>The key "secure object" model</title>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/SecurityInterception.gif" format="GIF"/>
</imageobject>
<imageobject role="fo">
<imagedata align="center" fileref="resources/images/SecurityInterception.gif" format="GIF"/>
</imageobject>
</mediaobject>
</figure>
</para>
</section>
<section>
<title>Extending the Secure Object Model</title>
<para>Only developers contemplating an entirely new way of
intercepting and authorizing requests would need to use secure objects
directly. For example, it would be possible to build a new secure
object to secure calls to a messaging system. Anything that requires
security and also provides a way of intercepting a call (like the AOP
around advice semantics) is capable of being made into a secure
object. Having said that, most Spring applications will simply use the
three currently supported secure object types (AOP Alliance
<classname>MethodInvocation</classname>, AspectJ
<literal>JoinPoint</literal> and web request
<classname>FilterInvocation</classname>) with complete
transparency.</para>
</section>
</section>
</section>
</chapter>
@@ -0,0 +1,87 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="x509"><info><title>X.509 Authentication</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
will automatically check that the certificate presented by a server has been issued (ie
digitally signed) by one of a list of trusted certificate authorities which it
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 it's 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 and passes it to the configured X.509 authentication provider
to allow any additional application-specific checks to be applied. It also 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>
</section>
<section><info><title>Adding X.509 Authentication to Your Web Application</title></info>
<para> Enabling X.509 client authentication is very straightforward. Just add the <literal>&lt;x509/&gt;</literal> element to your http security namespace configuration. <programlisting>
&lt;http&gt;
...
&lt;x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/&gt;
...
&lt;/http&gt;
</programlisting> The element has two optional attributes: <itemizedlist>
<listitem>
<para><literal>subject-principal-regex</literal>. The regular expression used to
extract a username from the certificate's subject name. The default value is
shown above. This is the username which will be passed to the <interfacename>UserDetailsService</interfacename> to load the authorities for the
user.</para>
</listitem>
<listitem>
<para><literal>user-service-ref</literal>. This is the bean Id of the
<interfacename>UserDetailsService</interfacename> to be used with X.509.
It isn't needed if there is only one defined in your application
context.</para>
</listitem>
</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
user name of "Jimi Hendrix". The matches are case insensitive. So "emailAddress=(.?),"
will match "EMAILADDRESS=jimi@hendrix.org,CN=..." giving a user name "jimi@hendrix.org".
If the client presents a certificate and a valid username is successfully extracted,
then there should be a valid <classname>Authentication</classname> object in the
security context. If no certificate is found, or no corresponding user could be found
then the security context will remain empty. This means that you can easily use X.509
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>
<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
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
<filename>server.xml</filename> file
<programlisting>
&lt;Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="${catalina.home}/conf/server.jks"
keystoreType="JKS" keystorePass="password"
truststoreFile="${catalina.home}/conf/server.jks"
truststoreType="JKS" truststorePass="password"
/&gt;
</programlisting>
<parameter>clientAuth</parameter> can also be set to <parameter>want</parameter> if you still
want SSL connections to succeed even if the client doesn't provide a certificate.
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>
</section>
</chapter>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB