开发者

login automatically with Grails Spring Security

开发者 https://www.devze.com 2023-03-29 07:07 出处:网络
My Grails app is using the Spring Security plugin. I need to login a user programatically, and I don\'t have access to their password. I tried the following, which supposedly worked when using the Ace

My Grails app is using the Spring Security plugin. I need to login a user programatically, and I don't have access to their password. I tried the following, which supposedly worked when using the Acegi plugin (an ancestor of the Spring Security plugin):

// automatically login a user and assign them the USER role. 
// In my app, the email address is also the username
GrantedAuthority[] auths = [new GrantedAuthorityImpl('USER')]
SecurityContextHolder.context.authentication 
        = new UsernamePasswordAuthenticationToken(email, 'unknown', auths)

It seems like this has almost worked, because if I call springSecurityService.principal after executing the above, I get back the email address of the automatically logged in user. However, if I call springSecurityService.currentUser I get an error. The root cause of this error is that:

SpringSecurityUtils.securityConfig.userLookup.userDomainClassName

returns "Person" which 开发者_Python百科is not the name of my user class. The various tags such as <sec:loggedInUser> also don't work, presumably for the same reason.

I wonder if this problem is somehow related to the fact that I'm using pre-existing domain classes for user and role (rather than classes generated by the plugin)? If the user logs in by entering their username and password into the form (rather than programatically), everything seems to work fine.

Update

Following Burt's advice, I replaced the code above with:

springSecurityService.reauthenticate(email)

But I still get an error on these lines within SpringSecurityService.getCurrentUser()

String className = SpringSecurityUtils.securityConfig.userLookup.userDomainClassName
grailsApplication.getClassForName(className).get(principal.id)

Because className is set to "Person", rather than the name of my User class.


If the user exists in the database use springSecurityService.reauthenticate() - see this link for Grails 2 or this link for Grails 3.

This method is designed to update the authentication when a user change has made it out of sync with the database, but it's also useful for this scenario where you want to force a valid authentication for an existing user but don't know the password.


Maybe this code snippit from a webapp I wrote will help. We had to auth users using a RESTful API and they provided a username and an API key..The key piece in this code is setting the authorities and the authenticated boolean.

class CustomAppTokenAuthenticationProvider implements AuthenticationProvider {

  def userDetailsService

  Authentication authenticate(Authentication customAuth) {
    def userDetails = userDetailsService.loadUserByUsername(customAuth.principal)
    def user = User.get(userDetails.id)
    if (user?.apiKey.equals(customAuth.credentials)) {
      customAuth.authorities = userDetails.authorities
      customAuth.authenticated = true
      return customAuth
    } else {
      return customAuth
    }
  }

  boolean supports(Class authentication) {
    return CustomAppTokenAuthentication.class.isAssignableFrom(authentication)
  }
}

And here is code from the filter that intercepts the API calls to handle the authentication

    def userId = request.getHeader("x-user-external-id")
    def apiKey = request.getHeader("x-user-api-key")
    if (userId && apiKey) {
      def user = User.findByExternalId(userId)

      def myAuth = new CustomAppTokenAuthentication(
              name: userId,
              credentials: apiKey,
              principal: user.username,
              authenticated: false
      )

      def auth = authenticationManager.authenticate(myAuth);
      if (auth?.authorities?.size() >= 0) {
        log.info "Successfully Authenticated ${userId} in object ${auth}"
        // Store to SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(myAuth);
      } else {
        SecurityContextHolder.getContext().setAuthentication(null)
      }


The reauthenticate() method has two limitations:

  • It don't check password
  • It don't fire events. That's why a lot of plugins that listen events may not work. For example the brute force defender plugin.
0

精彩评论

暂无评论...
验证码 换一张
取 消