|
|
|
|
@ -1,139 +1,71 @@
@@ -1,139 +1,71 @@
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
|
<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=" |
|
|
|
|
securityContextPersistenceFilter, |
|
|
|
|
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>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>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> |
|
|
|
|
|
|
|
|
|
<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><![CDATA[ |
|
|
|
|
<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><![CDATA[ |
|
|
|
|
<bean id="authenticationManager" |
|
|
|
|
class="org.springframework.security.authentication.ProviderManager"> |
|
|
|
|
<property name="providers"> |
|
|
|
|
@ -143,60 +75,47 @@
@@ -143,60 +75,47 @@
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
|
</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[ |
|
|
|
|
<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="authenticationEntryPoint"/> |
|
|
|
|
@ -211,132 +130,105 @@
@@ -211,132 +130,105 @@
|
|
|
|
|
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> |
|
|
|
|
</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> |
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
|
</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> |
|
|
|
|
<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[ |
|
|
|
|
<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[ |
|
|
|
|
</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> |
|
|
|
|
]]></programlisting> The properties file should contain entries in the form |
|
|
|
|
<programlisting> |
|
|
|
|
username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] |
|
|
|
|
</programlisting> |
|
|
|
|
For example |
|
|
|
|
<programlisting> |
|
|
|
|
<programlisting> |
|
|
|
|
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled |
|
|
|
|
bob=bobspassword,ROLE_USER,enabled |
|
|
|
|
</programlisting> |
|
|
|
|
</para> |
|
|
|
|
</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> |
|
|
|
|
<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"/> |
|
|
|
|
@ -347,21 +239,17 @@
@@ -347,21 +239,17 @@
|
|
|
|
|
|
|
|
|
|
<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. |
|
|
|
|
</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> |
|
|
|
|
<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, |
|
|
|
|
@ -375,66 +263,49 @@
@@ -375,66 +263,49 @@
|
|
|
|
|
|
|
|
|
|
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> |
|
|
|
|
</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><![CDATA[ |
|
|
|
|
<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><![CDATA[ |
|
|
|
|
<listener> |
|
|
|
|
<listener-class> |
|
|
|
|
org.springframework.security.web.session.HttpSessionEventPublisher |
|
|
|
|
</listener-class> |
|
|
|
|
</listener> ]]> |
|
|
|
|
</programlisting> |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
</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> |
|
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
|
<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" |
|
|
|
|
@ -453,25 +324,24 @@
@@ -453,25 +324,24 @@
|
|
|
|
|
class="org.springframework.security.authentication.concurrent.SessionRegistryImpl"/> |
|
|
|
|
<property> |
|
|
|
|
</bean> |
|
|
|
|
]]></programlisting></para> |
|
|
|
|
]]></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> |
|
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
<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> |
|
|
|
|
</chapter> |
|
|
|
|
|