views:

1571

answers:

7

I am writing a web app in Grails with the Acegi/Spring Security plug-in, and am having trouble getting it to see changes I make to User instances. I have only been working with Groovy/Grails for about three weeks, so please forgive me if this problem is trivial, since I have been poring over mailing lists and tutorials trying to find the answer.

I have been adding new attributes to the User domain class whenever I need a User to contain more information such as an email confirmation token or real name, since I couldn't find any recommendations to the contrary. Everything seems to be fine for creating new users, but when I edit the user, the changes show up in the user list, but the Acegi tag libraries and associated functions don't seem to see the changes.

Here is the relevant snippet from UserController.update():

def person = User.get(params.id)
//...snip error checking...

//Update user attributes
person.username = params.email
person.email = params.email
person.userRealName = params.userRealName

//Attempt to save changes
if (person.save()) {
    //If successful, redirect back to profile viewing page
    redirect action: show, id: person.id
    return
}
else {
    //Otherwise, show errors and edit again
    render view: 'edit', model: buildPersonModel(person)
    return
}

After this code runs, I can see the changes if I always get user data by ID, but not if I use the Acegi tags or functions. For example, this does not work:

loggedInUserInfo(field:'realName')

But this does:

User.get(loggedInUserInfo(field:'id').toLong()).realName

The new information sometimes shows up after I log out and in again, but usually it doesn't, often not showing up even after three or more relogs. Also, I tried adding "flush:true" to person.save() with no effect.

(Peripheral question: is it bad for me to be fiddling with the User class like this? If not, what's the best way to add information to it?)

Update after more investigation: It looks like if I use loggedInUserInfo() in a normal page, it works fine, but if I use it inside a layout, it exhibits the behavior I described. Could there be some odd caching thing going on?

+2  A: 

Did you run grails generate-manager after modifying your user class?

Maximilian Schweitzer
No, I did not, and had no idea that I needed to. Thank you!I can't test this until Monday, so I'm going to wait a couple of days before I say whether it's the solution or not.
Steve Johnson
I didn't know either about 3 month ago. But on http://www.infoq.com/articles/grails-acegi-integration I found the answer in the comment "How can I add new fields to AuthUser / User? Why 2 types of users?"That solved my problem.
Maximilian Schweitzer
Sorry, but that doesn't fix it. The issue persists. Thanks for the link, though.I suspect it has something to do with data being cached in sessions, but I'm not sure.
Steve Johnson
Then I have no idea. I'm sorry but Miguel's post sounds good.
Maximilian Schweitzer
+1  A: 

Acegi caches User info, if I remember correctly. Check the 'DefaultSecurityConfig' file (I think that's the name, under config/) for disabling user info cache. You can also call some method on authenticateService (can't remember what method right now) to evict the user cache.

You may be able to find the latter within the UserController#update closure.

Miguel Ping
Sorry, setting cacheUsers=false didn't fix the problem. Also, I couldn't find the method to evict the user cache in authenticateService.
Steve Johnson
+1  A: 

Hi Steve,

I faced same problem, and followed advice given by Maximilian Schweitzer above. It did not work for me in the beginning.

Give these steps a try and see if it resolves the issue:

  1. I ran generate-manager as per answer above by Maximilian Schweitzer .
  2. Tried to login with users created before I ran generate-manager - Didn't work
  3. I created new user (with new UserController, gsp, etc)
  4. Tried to login with new user works just fine.
  5. Deleted old users created before and recreated them. It worked fine.

Though not sure if it applies to your situation.

HTH!

peacefulfire
If I hadn't already made a bunch of modifications to the various models and controllers, I would try this, but since I have the workaround, I'm going to let it lie.
Steve Johnson
A: 

Did you ever resolve this ? I'm facing a similar problem. I can create a user but when I change the password it is not recognised by the acegi plugin - I get "springsecurity.GrailsDaoImpl User [Company1] has no GrantedAuthority".

The password is saved to DB correctly - caller User.get(id) returns correct value. Seems like a cacing problem, but not sure where to look.

Tom Appleton
No, I never actually solved the problem. I ended up just using the workaround I described in the original question.
Steve Johnson
+2  A: 

I have a workaround for this issue and i've also created a JIRA entry for the problem.

There seems to be a bug in how Acegi updates it's users internally. I provide a workaround in the form of a grails filter which updates the user's authorities manually every time a controller is accessed. Not ideal but it works.

Cheers,

sinjax
Thanks for the link. Could you provide an example of how to write such a filter? I no longer work on the project that has the problem, but I'm sure someone else could benefit from seeing it.
Steve Johnson
sure thing. The guide to grails filters is here: http://www.grails.org/Filters but short version is that you just have to put that filter file in your grails-app/conf directory and it works. Cheers
sinjax
+1 - I had the same issue with roles, and the workaround Filter provided in the JIRA solved the issue.
Rob Hruska
+1  A: 

I was facing the same problem. My solution was to make an update of the acegi plugin to version 0.5.1 (acegi 0.5.1 -- Grails Spring Security 2.0 Plugin).

Then I've set at /plugins/acegi-0.5.1/grails-app/conf/DefaultSecurityConfig.groovy

cacheUsers = false

and now voila! it is working!

Luis

Luixv
A: 

You have to reset the authenticated user. The code below does just that (from http://blog.lourish.com/2010/02/23/how-to-login-a-user-with-the-grails-spring-security-plugin/).

import org.springframework.security.context.SecurityContextHolder
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserImpl
import org.springframework.security.GrantedAuthority
import org.springframework.security.GrantedAuthorityImpl

...

def refreshAuthenticatedUser(user) {
    GrantedAuthority[] auths = user.authorities.collect {
        new GrantedAuthorityImpl(it.authority)
    }
    def grailsUser = new GrailsUserImpl(
            user.username,
            "",
            user.enabled,
            true,
            true,
            true,
            auths,
            user)
    def authToken = new UsernamePasswordAuthenticationToken(grailsUser, '', auths)
    SecurityContextHolder.context.authentication = authToken

}
Dave