Common Authentication Services

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

8.2. UserDetails and Associated Types

As mentioned in the first part of the reference guide, most authentication providers take advantage of the UserDetails and UserDetailsService interfaces. The contract for this latter interface consists of a single method:

  UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;
    

The returned UserDetails 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 UserDetailsService, even if the username and password are not actually used as part of the authentication decision. Generally such providers will be using the returned UserDetails object just for its GrantedAuthority[] information, because some other system (like LDAP or X509 or CAS etc) has undertaken the responsibility of actually validating the credentials.

A single concrete implementation of UserDetails is provided with Spring Security, being the User class. Spring Security users will need to decide when writing their UserDetailsService what concrete UserDetails class to return. In most cases User will be used directly or subclassed, although special circumstances (such as object relational mappers) may require users to write their own UserDetails 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 UserDetails 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.

Given UserDetailsService 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.

8.2.1. In-Memory Authentication

Whilst it is easy to use create a custom UserDetailsService 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 UserDetailsService implementations. For this sort of situation, a simple option is to use the user-service element from the security namespace:

    <user-service id="userDetailsService">
      <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
      <user name="bob" password="bobspassword" authorities="ROLE_USER" />
    </user-service>
  

This also suppots the use of an external properties file:

    <user-service id="userDetailsService" properties="users.properties"/>
  
        

The properties file should contain entries in the form

  username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]

For example

  jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
  bob=bobspassword,ROLE_USER,enabled  

8.2.2. JDBC Authentication

Spring Security also includes a UserDetailsService 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 UserDetailsService to reuse the mapping files you've probably already created. Returning to JdbcDaoImpl, an example configuration is shown below:


<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.userdetails.jdbc.JdbcDaoImpl">
  <property name="dataSource" ref="dataSource"/>
</bean>        

You can use different relational database management systems by modifying the DriverManagerDataSource shown above. You can also use a global data source obtained from JNDI, as per normal Spring options.

8.2.2.1. Default User Database Schema

Irrespective of the database you are using and how a DataSource is obtained, a standard schema must be in place. The DDL for an HSQL database instance would be:

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

If the default schema is unsuitable for your needs, JdbcDaoImpl 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 UserDetails implementation returned, you'd be better off writing your own UserDetailsService. The base implementation provided with Spring Security is intended for typical situations, rather than catering for all possible requirements.

8.3. Concurrent Session Handling

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.

To use concurrent session support, you'll need to add the following to web.xml:

<listener>
    <listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>        
      

In addition, you will need to add the org.springframework.security.concurrent.ConcurrentSessionFilter to your FilterChainProxy. The ConcurrentSessionFilter requires two properties, sessionRegistry, which generally points to an instance of SessionRegistryImpl, and expiredUrl, which points to the page to display when a session has expired.

The web.xml HttpSessionEventPublisher causes an ApplicationEvent to be published to the Spring ApplicationContext every time a HttpSession commences or terminates. This is critical, as it allows the SessionRegistryImpl to be notified when a session ends.

You will also need to wire up the ConcurrentSessionControllerImpl and refer to it from your ProviderManager bean:

<bean id="authenticationManager"
    class="org.springframework.security.providers.ProviderManager">
  <property name="providers">
    <!-- your providers go here -->
  </property>
  <property name="sessionController" ref="concurrentSessionController"/>
</bean>

<bean id="concurrentSessionController"
    class="org.springframework.security.concurrent.ConcurrentSessionControllerImpl">
  <property name="maximumSessions" value="1"/>
  <property name="sessionRegistry">
    <bean class="org.springframework.security.concurrent.SessionRegistryImpl"/>
  <property>
</bean>

8.4. Authentication Tag Libraries

AuthenticationTag is used to simply output a property of the current Authentication object to the web page.

The following JSP fragment illustrates how to use the AuthenticationTag:

<security:authentication property="principal.username"/>

This tag would cause the principal's name to be output. Here we are assuming the Authentication.getPrincipal() is a UserDetails object, which is generally the case when using one of Spring Security's stadard AuthenticationProvider implementations.