views:

51

answers:

1

Hi,

I'm working on a grails legacy project. A domain class called User exists. It contains password, username, roles, etc.

This project uses Spring Security for role management. I would like to add expiration of credentials ( force the User to renew its password).

I've modified the User class. Not it implements the UserDetails interface.

However, when I start the server, I get this error>

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageSource': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException:

Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException:

Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.hibernate.PropertyNotFoundException:

Could not find a setter for property accountNonExpired in class com.company.app.user.User

Do I have to register some bean? I find the error quite confusing, since the interface doesn't asks for a setter method.

update

After investigating some more, I ran into my SecurityConfig.groovy, that looks A LOT like this (AcegiSecurity Plugin):

security {
   // see DefaultSecurityConfig.groovy for all settable/overridable properties

   active = true

   loginUserDomainClass = "User"
   authorityDomainClass = "Role"

 ....
}

My User class also looks A LOT like this:

/**
 * User domain class.
 */
class User {
   static transients = ['pass','passwordExpired','credentialsNonExpired']
   static hasMany = [authorities: Role]
   static belongsTo = Role
   /** Username */
   String username
   /** User Real Name*/
   String userRealName
   /** MD5 Password */
   String passwd
   /** enabled */
   boolean enabled

   String email
   boolean emailShow

   /** description */
   String description = ''

   /** plain password to create a MD5 password */
   String pass = '[secret]'

   static constraints = {
      username(blank: false, unique: true)
      userRealName(blank: false)
      passwd(blank: false)
      enabled()
   }

   public boolean isCredentialsNonExpired() {
         return true;
   }
}

I added a method to check if the password should expire or not for this class (isCredentialsNonExpired). I need this method to execute at login. Right now, its not.

So it looks like it's the Acegi approach I should take. Any thoughts? Its my understanding that Acegi uses Spring Security, right?

+3  A: 

Are you using the Acegi plugin, or configuring it directly? If you use the Spring Security Core plugin this will be a lot easier since it's supported out of the box.

You probably don't want your User class to be your UserDetailsService class since it often has other baggage like mapped collections, etc. It can certainly work, but creating a simple data class is a better approach. It's convenient to subclass org.springframework.security.userdetails.User or org.springframework.security.core.userdetails.User depending on the version of Spring Security.

It looks like you just added a getter for accountNonExpired but if it's going to be persisted then it needs a setter too. If you're deriving the value and don't want that field to be in the database then you can add it to the transients list:

static transients = ['accountNonExpired']
Burt Beckwith
Thanks. If I have to check for expired credentials, would it be ['passwordExpired'] and a isCredentialsNonExpired() method?
Tom
Right. This is also supported in the Spring Security Core plugin btw, see section 12.3 in http://burtbeckwith.github.com/grails-spring-security-core/docs/manual/
Burt Beckwith
Cant get it to work, the debugger wont stop at my method :(
Tom