Restructured docs, faq and removed use of docbkx plugin
@@ -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/</</;
|
||||
$title =~ s/>/>/;
|
||||
$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><http></literal> Element</title>
|
||||
<para>
|
||||
The <literal><http></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><http></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><http></literal> Attributes</title>
|
||||
<para>
|
||||
The attributes on the <literal><http></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><intercept-url></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><intercept-url></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><port-mappings></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><port-mappings></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><port-mapping></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><form-login></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><http-basic></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><remember-me></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><concurrent-session-control></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><anonymous></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><x509></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><openid-login></literal> Element</title>
|
||||
<para>
|
||||
Similar to <literal><form-login></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><logout></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 <authentication-provider> 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><custom-authentication-provider></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><authentication-manager></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><global-method-security></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><secured-annotations></literal> and <literal><jsr250-annotations></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><protect-pointcut></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><protect-pointcut></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><custom-after-invocation-provider></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><global-method-security></literal>
|
||||
namespace.
|
||||
</para>
|
||||
<para>
|
||||
The syntax is the same as for <literal><custom-authentication-provider></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><ldap-server></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><ldap-provider></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><password-compare></literal> Element</title>
|
||||
<para>
|
||||
This is used as child element to <literal><ldap-provider></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><password-encoder></literal>
|
||||
element to hash the password before submitting it to the directory for comparison.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>The <literal><ldap-user-service></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><ldap-provider></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<ConfigAttribute> 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<ConfigAttribute> config);
|
||||
boolean supports(ConfigAttribute attribute);
|
||||
boolean supports(Class clazz);
|
||||
</programlisting>
|
||||
Concrete implementations return an <literal>int</literal>, with
|
||||
possible values being reflected in the
|
||||
<interfacename>AccessDecisionVoter</interfacename> static fields
|
||||
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal>
|
||||
and <literal>ACCESS_GRANTED</literal>. A voting implementation will
|
||||
return <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an
|
||||
authorization decision. If it does have an opinion, it must return
|
||||
either <literal>ACCESS_DENIED</literal> or
|
||||
<literal>ACCESS_GRANTED</literal>.</para>
|
||||
|
||||
<para>There are three concrete
|
||||
<interfacename>AccessDecisionManager</interfacename>s provided with Spring
|
||||
Security that tally the votes. The <literal>ConsensusBased</literal>
|
||||
implementation will grant or deny access based on the consensus of
|
||||
non-abstain votes. Properties are provided to control behavior in the
|
||||
event of an equality of votes or if all votes are abstain. The
|
||||
<literal>AffirmativeBased</literal> implementation will grant access
|
||||
if one or more <literal>ACCESS_GRANTED</literal> votes were received
|
||||
(i.e. a deny vote will be ignored, provided there was at least one grant
|
||||
vote). Like the <literal>ConsensusBased</literal> implementation,
|
||||
there is a parameter that controls the behavior if all voters abstain.
|
||||
The <literal>UnanimousBased</literal> provider expects unanimous
|
||||
<literal>ACCESS_GRANTED</literal> votes in order to grant access,
|
||||
ignoring abstains. It will deny access if there is any
|
||||
<literal>ACCESS_DENIED</literal> vote. Like the other implementations,
|
||||
there is a parameter that controls the behaviour if all voters
|
||||
abstain.</para>
|
||||
|
||||
<para>It is possible to implement a custom
|
||||
<interfacename>AccessDecisionManager</interfacename> that tallies votes
|
||||
differently. For example, votes from a particular
|
||||
<interfacename>AccessDecisionVoter</interfacename> might receive additional
|
||||
weighting, whilst a deny vote from a particular voter may have a veto
|
||||
effect.</para>
|
||||
|
||||
<section>
|
||||
<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">
|
||||
<bean id="basicProcessingFilter" class="org.springframework.security.web.authentication.www.BasicProcessingFilter">
|
||||
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||
<property name="authenticationEntryPoint"><ref bean="authenticationEntryPoint"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationEntryPoint"
|
||||
class="org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint">
|
||||
<property name="realmName"><value>Name Of Your Realm</value></property>
|
||||
</bean>
|
||||
|
||||
</programlisting></para>
|
||||
|
||||
<para>The configured <interfacename>AuthenticationManager</interfacename>
|
||||
processes each authentication request. If authentication fails, the
|
||||
configured <interfacename>AuthenticationEntryPoint</interfacename> will be used to
|
||||
retry the authentication process. Usually you will use the
|
||||
<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&ticket=ST-0-ER94xMJmn6pha35CQRoZ&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&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>
|
||||
<servlet>
|
||||
<servlet-name>casproxy</servlet-name>
|
||||
<servlet-class>edu.yale.its.tp.cas.proxy.ProxyTicketReceptor</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>casproxy</servlet-name>
|
||||
<url-pattern>/casProxy/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</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><welcome-file></literal> points to an HTTPS location,
|
||||
and the application never directs the user to an HTTP location. Spring
|
||||
Security provides a solution to assist with the latter.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="channel-security-config">
|
||||
<info><title>Configuration</title></info>
|
||||
<para>Channel security is supported by the <link xlink:href="#ns-requires-channel">security namespace</link>
|
||||
by means of the <literal>requires-channel</literal> attribute on the <literal><intercept-url></literal>
|
||||
element and this is the simplest (and 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><welcome-file></literal> or
|
||||
a well-known home page URL), but once this is done the filter will
|
||||
perform redirects as defined by your application context.</para>
|
||||
|
||||
<para>You can also add your own <literal>ChannelProcessor</literal>
|
||||
implementations to the <literal>ChannelDecisionManagerImpl</literal>.
|
||||
For example, you might set a <literal>HttpSession</literal> attribute
|
||||
when a human user is detected via a "enter the contents of this
|
||||
graphic" procedure. Your <literal>ChannelProcessor</literal> would
|
||||
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><bean id="authenticationManager"
|
||||
class="org.springframework.security.authentication.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref local="daoAuthenticationProvider"/>
|
||||
<ref local="anonymousAuthenticationProvider"/>
|
||||
<ref local="rememberMeAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean></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>
|
||||
<listener>
|
||||
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
|
||||
</listener>
|
||||
</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><security:authentication property="principal.username"/></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>
|
||||
@@ -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><bean id="authByAdapterProvider"
|
||||
class="org.springframework.security.adapters.AuthByAdapterProvider">
|
||||
<property name="key"><value>my_password</value></property>
|
||||
</bean> </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><Configure class></literal> section has a new
|
||||
<literal>addRealm</literal> call:</para>
|
||||
|
||||
<para><programlisting>
|
||||
<Call name="addRealm">
|
||||
<Arg>
|
||||
<New class="org.springframework.security.adapters.jetty.JettySpringSecurityUserRealm">
|
||||
<Arg>Spring Powered Realm</Arg>
|
||||
<Arg>my_password</Arg>
|
||||
<Arg>etc/acegisecurity.xml</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
</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><realm-name></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><Policy></literal> section:</para>
|
||||
|
||||
<para><programlisting>
|
||||
<application-policy name = "SpringPoweredRealm">
|
||||
<authentication>
|
||||
<login-module code = "org.springframework.security.adapters.jboss.JbossSpringSecurityLoginModule"
|
||||
flag = "required">
|
||||
<module-option name = "appContextLocation">acegisecurity.xml</module-option>
|
||||
<module-option name = "key">my_password</module-option>
|
||||
</login-module>
|
||||
</authentication>
|
||||
</application-policy>
|
||||
|
||||
</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>
|
||||
<application-policy name = "SpringPoweredRealm">
|
||||
<authentication>
|
||||
<login-module code = "org.springframework.security.adapters.jboss.JbossSpringSecurityLoginModule"
|
||||
flag = "required">
|
||||
<module-option name = "singletonId">springRealm</module-option>
|
||||
<module-option name = "key">my_password</module-option>
|
||||
<module-option name = "authenticationManager">authenticationManager</module-option>
|
||||
</login-module>
|
||||
</authentication>
|
||||
</application-policy>
|
||||
|
||||
</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>
|
||||
<beans>
|
||||
<bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<value>acegisecurity.xml</value>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</beans>
|
||||
|
||||
</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><security-domain></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>
|
||||
<jboss-web>
|
||||
<security-domain>java:/jaas/SpringPoweredRealm</security-domain>
|
||||
</jboss-web></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>
|
||||
<web-app>
|
||||
<authenticator>
|
||||
<type>org.springframework.security.adapters.resin.ResinAcegiAuthenticator</type>
|
||||
<init>
|
||||
<app-context-location>WEB-INF/resin-acegisecurity.xml</app-context-location>
|
||||
<key>my_password</key>
|
||||
</init>
|
||||
</authenticator>
|
||||
</web-app>
|
||||
|
||||
</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><authenticator></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><Engine></literal> section contains only one
|
||||
active <literal><Realm></literal> entry. An example realm
|
||||
entry:</para>
|
||||
|
||||
<para><programlisting> <Realm
|
||||
className="org.springframework.security.adapters.catalina.CatalinaSpringSecurityUserRealm"
|
||||
appContextLocation="conf/acegisecurity.xml"
|
||||
key="my_password" /></programlisting></para>
|
||||
|
||||
<para>Be sure to remove any other <literal><Realm></literal>
|
||||
entry from your <literal><Engine></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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 user’s principal and credentials through JAAS.</para>
|
||||
|
||||
<para>Let’s assume we have a JAAS login configuration file,
|
||||
<literal>/WEB-INF/login.conf</literal>, with the following
|
||||
contents:
|
||||
<programlisting>
|
||||
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
|
||||
Security’s <interfacename>GrantedAuthority</interfacename> interface) containing
|
||||
the authority string and the JAAS principal that the
|
||||
<interfacename>AuthorityGranter</interfacename> was passed. The
|
||||
<classname>JaasAuthenticationProvider</classname> obtains the JAAS
|
||||
principals by firstly successfully authenticating the user’s
|
||||
credentials using the JAAS <literal>LoginModule</literal>, and then
|
||||
accessing the <literal>LoginContext</literal> it returns. A call to
|
||||
<literal>LoginContext.getSubject().getPrincipals()</literal> is
|
||||
made, with each resulting principal passed to each
|
||||
<interfacename>AuthorityGranter</interfacename> defined against the
|
||||
<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><ldap-server></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><ldap-server></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=<user-login-name>,ou=people,dc=springframework,dc=org</literal>.
|
||||
After successful authentication, roles will be assigned to the user by searching
|
||||
under the DN
|
||||
<literal>ou=groups,dc=springframework,dc=org</literal>
|
||||
with the default filter
|
||||
<literal>(member=<user's-DN>)</literal>. The role name will be taken from the
|
||||
<quote>ou</quote>
|
||||
attribute of each match.</para>
|
||||
<para>To configure a user search object, which uses the filter
|
||||
<literal>(uid=<user-login-name>)</literal>
|
||||
for use instead of the DN-pattern (or in addition to it), you would configure the
|
||||
following bean
|
||||
<programlisting><![CDATA[
|
||||
<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><http></literal> element.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="ns-minimal">
|
||||
<title>A Minimal <literal><http></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><intercept-url></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 <http> 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><authentication-provider></literal> element creates a
|
||||
<classname>DaoAuthenticationProvider</classname> bean and the
|
||||
<literal><user-service></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><authentication-provider></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><http></literal> configuration, so the
|
||||
<literal><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><custom-authentication-provider></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><password-encoder></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><intercept-url></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><user-service></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><form-login></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><http></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><http></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><http></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><global-method-security></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><global-method-security></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><custom-authentication-provider></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>
|
||||
@@ -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>
|
||||
@@ -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><security-role></literal> information in a
|
||||
<filename>web.xml</filename> file. The pre-authentication sample application uses the latter approach.
|
||||
</para>
|
||||
<para>There is an additional stage where the roles (or attributes) are mapped to Spring Security
|
||||
<interfacename>GrantedAuthority</interfacename> objects using a configured
|
||||
<interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>. The default will just add the usual <literal>ROLE_</literal>
|
||||
prefix to the names, but it gives you full control over the behaviour.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>PreAuthenticatedAuthenticationProvider</title>
|
||||
<para>
|
||||
The pre-authenticated provider has little more to do than load the <interfacename>UserDetails</interfacename>
|
||||
object for the user. It does this by delegating to a <interfacename>AuthenticationUserDetailsService</interfacename>.
|
||||
The latter is similar to the standard <interfacename>UserDetailsService</interfacename> but takes an
|
||||
<interfacename>Authentication</interfacename> object rather than just user name:
|
||||
<programlisting language="java">
|
||||
public interface AuthenticationUserDetailsService {
|
||||
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
|
||||
}
|
||||
</programlisting>
|
||||
This interface may have also other uses but with pre-authentication it allows access to the authorities which
|
||||
were packaged in the <interfacename>Authentication</interfacename> object, as we saw in the previous section.
|
||||
The <classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class does this.
|
||||
Alternatively, it may delegate to a standard <interfacename>UserDetailsService</interfacename> via the
|
||||
<classname>UserDetailsByNameServiceWrapper</classname> implementation.
|
||||
</para>
|
||||
</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><remember-me></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<ConfigAttribute> 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>
|
||||
@@ -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
|
||||
container’s <literal>webapps</literal> directory. The war should be called
|
||||
<filename>spring-security-samples-contacts-3.0.x.war</filename> (the appended
|
||||
version number will vary depending on what release you are using). </para>
|
||||
<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>
|
||||
@@ -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><intercept-methods></literal> or <literal><protect-point></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)
|
||||
&& execution(public * *(..)) && !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><filter-invocation-definition-source></literal>
|
||||
namespace element. This is similar to the <literal><filter-chain-map></literal>
|
||||
used to configure a <classname>FilterChainProxy</classname> but the <literal><intercept-url></literal>
|
||||
child elements only use the <literal>pattern</literal> and <literal>access</literal> attributes.
|
||||
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<ConfigAttribute></literal> containing
|
||||
all of the configuration attributes associated with a single secure
|
||||
HTTP URL.</para>
|
||||
|
||||
<para>It should be noted that the
|
||||
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal>
|
||||
method actually expects an instance of
|
||||
<interfacename>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><bean id="authenticationProcessingFilter"
|
||||
class="org.springframework.security.ui.webapp.SiteminderUsernamePasswordAuthenticationProcessingFilter">
|
||||
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||
<property name="authenticationFailureUrl"><value>/login.jsp?login_error=1</value></property>
|
||||
<property name="defaultTargetUrl"><value>/security.do?method=getMainMenu</value></property>
|
||||
<property name="filterProcessesUrl"><value>/j_spring_security_check</value></property>
|
||||
<property name="siteminderUsernameHeaderKey"><value>SM_USER</value></property>
|
||||
<property name="formUsernameParameterKey"><value>j_username</value></property>
|
||||
</bean></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>
|
||||
@@ -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>
|
||||
<filter>
|
||||
<filter-name>myFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>myFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
</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><filter></literal> and
|
||||
<literal><filter-mapping></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><filter-mapping></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>
|
||||
<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %>
|
||||
|
||||
</programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -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>
|
||||
<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>
|
||||
<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %>
|
||||
|
||||
</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><intercept-url></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><x509/></literal> element to your http security namespace configuration. <programlisting>
|
||||
<http>
|
||||
...
|
||||
<x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/>
|
||||
...
|
||||
</http>
|
||||
</programlisting> The element has two optional attributes: <itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>subject-principal-regex</literal>. The regular expression used to
|
||||
extract a username from the certificate's subject name. The default value is
|
||||
shown above. This is the username which will be passed to the <interfacename>UserDetailsService</interfacename> to load the authorities for the
|
||||
user.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>user-service-ref</literal>. This is the bean Id of the
|
||||
<interfacename>UserDetailsService</interfacename> to be used with X.509.
|
||||
It isn't needed if there is only one defined in your application
|
||||
context.</para>
|
||||
</listitem>
|
||||
</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>
|
||||
<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"
|
||||
/>
|
||||
</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>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 36 KiB |