Chapter 8. Common Authentication Services

Table of Contents

Mechanisms, Providers and Entry Points
UserDetails and Associated Types
In-Memory Authentication
JDBC Authentication
Concurrent Session Handling
Authentication Tag Libraries

Mechanisms, Providers and Entry Points

To use Spring Security's authentication services, you'll usually need to configure a web filter, together with an AuthenticationProvider and AuthenticationEntryPoint. 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).

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:

<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>

The above declarations will cause every web request to be passed through to the bean called filterChainProxy which will usually be an instance of Spring Security's FilterChainProxy. As explained in the filters section of this reference guide, the FilterChainProxy 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:

<bean id="filterChainProxy"
        class="org.springframework.security.util.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>

The filter-chain-map syntax from the security namespace allows you to define the mapping from URLs to filter chains, using a sequence of filter-chain child elements. Each of these defines a set of URLs using the pattern attribute and a chain of filters using the filters 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 id 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 httpSessionContextIntegrationFilter, logoutFilter 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.

In our example we have the AuthenticationProcessingFilter and BasicProcessingFilter 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 DigestProcessingFilter or CasProcessingFilter. Refer to the individual chapters of this part of the reference guide to learn how to configure each of these authentication mechanisms.

Recall that HttpSessionContextIntegrationFilter keeps the contents of the SecurityContext 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 GrantedAuthority[]s) after the initial authentication step? Let's look at how that is handled now.

The major authorization provider for secure objects has previously been introduced as AbstractSecurityInterceptor. This class needs to have access to an AuthenticationManager. It also has configurable settings to indicate whether an Authentication object should be re-authenticated on each secure object invocation. By default it just accepts any Authentication inside the SecurityContextHolder is authenticated if Authentication.isAuthenticated() 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 AbstractSecurityInterceptor.alwaysReauthenticate property to true.

You might be asking yourself, "what's this AuthenticationManager?". We haven't explored it before, but we have discussed the concept of an AuthenticationProvider. Quite simply, an AuthenticationManager 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 AuthenticationManager implementation shipped with Spring Security, so let's look at how it's configured for the example we're using in this chapter:

<bean id="authenticationManager"
        class="org.springframework.security.providers.ProviderManager">
<property name="providers">
<list>
  <ref local="daoAuthenticationProvider"/>
  <ref local="anonymousAuthenticationProvider"/>
  <ref local="rememberMeAuthenticationProvider"/>
</list>
</property>
</bean>

It's probably worth mentioning at this point that your authentication mechanisms (which are usually filters) are also injected with a reference to the AuthenticationManager. So both AbstractSecurityInterceptor as well as the authentication mechanisms will use the above ProviderManager to poll a list of AuthenticationProviders.

In our example we have three providers. They are tried in the order shown (which is implied by the use of a List instead of a Set), with each provider able to attempt authentication, or skip authentication by simply returning null. If all implementations return null, the ProviderManager will throw a suitable exception. If you're interested in learning more about chaining providers, please refer to the ProviderManager JavaDocs.

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 DaoAuthenticationProvider 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 AuthenticationProvider. 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 CasAuthenticationProvider. A further example of a one-to-one mapping would be the LDAP authentication mechanism, which can only be processed an the LdapAuthenticationProvider. 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 ProviderNotFoundException when an attempt to authenticate is made.

After configuring the correct authentication mechanisms in the FilterChainProxy, and ensuring that a corresponding AuthenticationProvider is registered in the ProviderManager, your last step is to configure an AuthenticationEntryPoint. Recall that earlier we discussed the role of ExceptionTranslationFilter, 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:

<bean id="exceptionTranslationFilter"
        class="org.springframework.security.ui.ExceptionTranslationFilter">
  <property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/>
  <property name="accessDeniedHandler">
    <bean class="org.springframework.security.ui.AccessDeniedHandlerImpl">
      <property name="errorPage" value="/accessDenied.jsp"/>
    </bean>
  </property>
</bean>

<bean id="authenticationProcessingFilterEntryPoint"
        class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
  <property name="loginFormUrl" value="/login.jsp"/>
  <property name="forceHttps">< value="false"/>
</bean>

Notice that the ExceptionTranslationFilter requires two collaborators. The first, AccessDeniedHandlerImpl, uses a RequestDispatcher forward to display the specified access denied error page. We use a forward so that the SecurityContextHolder 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). AccessDeniedHandlerImpl will also set the HTTP header to 403, which is the official error code to indicate access denied. In the case of the AuthentionEntryPoint, 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 AuthenticationProcessinFilterEntryPoint and the URL of the login page. Your application will usually only have one entry point, and most authentication approaches define their own specific AuthenticationEntryPoint. Details of which entry point to use for each authentication approach is discussed in the authentication approach-specific chapters of this reference guide.