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.

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  

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.

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.