mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 09:12:14 +00:00
463 lines
24 KiB
XML
463 lines
24 KiB
XML
<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> |