Home > spring-roo, spring-security > Writing a custom JPA UserDetailService

Writing a custom JPA UserDetailService

When using Spring Security in a ROO application, often there is a need for user management, where you can add, edit and delete users etc.. For that you make entity beans for users, roles, groups etc. – depending on your needs. Then you change some sql queries in the jdbc-user-service section of the applicationContext-security.xml file, so that Spring Security uses the same tables as the new entity beans. I would prefer the security to access the tables in the same manner as the rest of the application. Here I will describe how to make a custom UserDetailService, that uses the JPA entity beans in the login process.
For this I only use one entity bean for the users, I have 4 roles and I don’t need more, so they are of type enum, but it could just as well have been a @ManyToMany relation to a role entity. Here is the user entity:

public class SiteUser {

    @Size(min = 3, max = 30)
    @Column(unique = true)
    private String username;

    @Size(max = 100)
    private String passwd;

    private Boolean enabled;

    private Set<SiteRole> roles = new HashSet<SiteRole>();


You need to create a new class that implements UserDetailService. There is only one method in the interface loadUserByUsername and it gives the fully populated User. Spring recommends to return an immutable implementation of UserDetails, so I will the return the usual spring User. The SiteUser. FindSiteUsersByUsername method is a ROO generated finder.

public class JpaUserDetailService implements UserDetailsService {

    public UserDetails loadUserByUsername(String username) throws 								UsernameNotFoundException, DataAccessException {
        TypedQuery<SiteUser> siteUsersQuery = SiteUser.findSiteUsersByUsername(username);
        List<SiteUser> siteUsers = siteUsersQuery.getResultList();
        if (siteUsers.isEmpty()) {
            throw new UsernameNotFoundException("Username " + username + " not found");
        SiteUser siteUser = siteUsers.get(0);
        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        Set<SiteRole> siteRoles = siteUser.getRoles();
        System.out.println("siteRoles = " + siteRoles);
        for (SiteRole siteRole : siteRoles) {
            authorities.add(new GrantedAuthorityImpl(siteRole.name()));
        return new User(siteUser.getUsername(), siteUser.getPasswd(), siteUser.getEnabled(),
                true, true, true, authorities);

Now we only need to tell spring security to use the new UserDetailservice. In applicationContext-security.xml do the following.

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="customUserDetailsService">
            <password-encoder hash="sha-256"/>

    <beans:bean id="customUserDetailsService" class="dk.amfibia.cv.security.JpaUserDetailService"/>

In the first attempt I ran into a LazyInitializationException in the siteUser.getRoles()

This error is described here https://jira.springsource.org/browse/ROO-609. It should have been solved in ROO 1.0.2 but the problem seems to be still here in 1.1.3 – I left a comment in jira. As described in the jira, the solution is, in the web.xml, to move the filter mapping of springSecurityFilterChain below the filter-mapping of Spring OpenEntityManagerInViewFilter. Now it works.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: