AcegiSecurity Plugin - Custom UserDetailsService

Hopefully the standard configuraton, plus the configurability exposed in DefaultSecurityConfig.groovy and SecurityConfig.groovy, enable most customization needs for your applications. However security is a large topic and there are many possible ways to secure an application.

When authenticating users from a database using DaoAuthenticationProvider (the default mode in the Acegi plugin if you haven't enabled OpenID or LDAP), an implementation of UserDetailsService is required. This class is responsible for returning a concrete implementation of UserDetails. The Acegi plugin uses GrailsDaoImpl as its UserDetailsService implementation and GrailsUserImpl as its UserDetails implementation. GrailsUserImpl actually implements GrailsUser which extends UserDetails to add a getDomainClass() method. This way GrailsDaoImpl returns a UserDetails instance that satisfies the Spring Security contract and also contains the domain User instance.

You can extend or replace GrailsDaoImpl with your own class by defining a bean in resources.groovy (or resources.xml) with the same bean name, 'userDetailsService'. This is because application beans are configured after plugin beans and there can only be one bean for each name.

You just have to make sure that your implementation returns a class implementing GrailsUser to avoid missing method exceptions. If you don't have a need to attach the database User instance to the GrailsUser instance (e.g. you don't want to store the User in the session along with the GrailsUser) you can just return null from getDomainClass().

Here's an example UserDetails (GrailsUser) and UserDetailsService implementation (there's really not much to implement other than your application-specific lookup code): 

package com.foo.bar;
public class MyUserDetails extends User implements GrailsUser {

   public MyUserDetails(
         String username, String password, boolean enabled,
         boolean accountNonExpired, boolean credentialsNonExpired,
         boolean accountNonLocked, GrantedAuthority[] authorities) {
      super(username, password, enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, authorities);
   }

   public GroovyObject getDomainClass() {
      return null;
   }
}
package com.foo.bar;
public class MyUserDetailsService implements UserDetailsService {

   public UserDetails loadUserByUsername(final String username)
         throws UsernameNotFoundException, DataAccessException {

      // lookup user and data

      return new MyUserDetails(username, password, enabled,
            accountNonExpired, credentialsNonExpired,
            accountNonLocked, authorities);
   }
}

and to use it, register it in resources.groovy using 

userDetailsService(com.foo.bar.MyUserDetailsService) {}

 
Another option if you want to load users and roles from the database is to subclass GrailsDaoImpl - the methods are protected so you can override whatever you want.

Also note that this approach works with all beans defined in AcegiGrailsPlugin.doWithSpring() - you can replace or subclass any of the Spring beans to provide your own functionality when the standard extension mechanisms aren't sufficient. 

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.