Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails Security: how to preprocess username (to make it case-insensitive)?

The default implementation of Spring Security treats the username as case-sensitive, I need to make it case-insensitive for usability reasons (one major reasons is users with mobile devices whose default behavior is to capitalize the first letter of an input text). This is a business requirement.

By the time control is passed to the LoginController generated by the plugin, it's too late: Spring Security has already determined the login failed. With a debugger I can see the flow passes through org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#attemptAuthentication but I don't know how to intervene from Grails. In fact, the plugin uses a subclass, org.codehaus.groovy.grails.plugins.springsecurity.RequestHolderAuthenticationFilter, but that's inside the plugin source, not my application, so I don't know where to intervene.

Any pointers are appreciated. Thank you.

Environment: Grails 2.3, Spring Security Plugin 1.2.7.3

like image 513
wishihadabettername Avatar asked Oct 17 '13 00:10

wishihadabettername


1 Answers

You can do this with a custom UserDetailsService - see https://grails-plugins.github.io/grails-spring-security-core/v3/index.html#userDetailsService

package com.yourcompany.yourapp

import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserDetailsService
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UsernameNotFoundException

class MyUserDetailsService implements GrailsUserDetailsService {

   static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]

   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      User.withTransaction { status ->
         User user = User.findByUsernameIlike(username)
         if (!user) throw new UsernameNotFoundException('User not found', username)

         def authorities = user.authorities.collect { new GrantedAuthorityImpl(it.authority) }

         new GrailsUser(user.username, user.password, user.enabled, !user.accountExpired, !user.passwordExpired,
            !user.accountLocked, authorities ?: NO_ROLES, user.id)
      }
   }

   UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException {
      loadUserByUsername username
   }
}

Register this in grails-app/conf/spring/resources.groovy to override the plugin's implementation:

beans = {
   userDetailsService(com.yourcompany.yourapp.MyUserDetailsService)
}
like image 200
Burt Beckwith Avatar answered Oct 06 '22 00:10

Burt Beckwith