I'm currently developing an application for my new brand company and I'd like that supports authentication with username and password , and OpenId.
I could install Acegi Grails Plugin , but I'm very happy using JSecurity , ok no problem let's hack.
First, I have to install OpenId Plugin to support OpenId authenticantion, with this plugin I can manage login process and get openid identifier for OpenId users.
With JSecurity installed and done QuickStart, I need to pass Openid identifier in auth process, for this I've created class OpenIdContextHolder to save in a ThreadLocal context.
class OpenIdContextHolder{ private static final ThreadLocal openIdContextHolder = new ThreadLocal(); static void resetContext() { openIdContextHolder.set(null); } static def getOpenIdIdentifier(){ openIdContextHolder.get() } static void setOpenIdIdentifier(id){ openIdContextHolder.set(id) } }
def login = { if(openidService.isLoggedIn(session)){ return redirect(action:'signIn') } return [ username: params.username, rememberMe: (params.rememberMe != null), targetUri: params.targetUri ] } def signIn = { // if is logged with openid set contextholder if(openidService.isLoggedIn(session)){ def openId = openidService.getIdentifier(session) OpenIdContextHolder.setOpenIdIdentifier(openId) params.rememberMe = true params.username = openId params.password = "nullpass" } def authToken = new UsernamePasswordToken(params.username, params.password) // continues the default generated code... // ... }
def authenticate(authToken) { log.info "Attempting to authenticate ${authToken.username} in DB realm..." // experimental!! def openid = OpenIdContextHolder.getOpenIdIdentifier() OpenIdContextHolder.resetContext() log.info "OpenIdContextHolder request with openid: ${openid}" if(openid){ def openidUser = User.findByOpenid(openid) if (!openidUser) throw new UnknownAccountException("No account found for user [${username}]") log.info "Jsecurity with Openid ${openidUser.username} : ${openidUser.openid}" authToken.password = 'secret' authToken.username = openidUser.username }else { def openidUser = User.findByUsername(authToken.username) if(openidUser?.openid?.trim()){ // trying to access with password for openid user log.info "Jsecurity: Trying to access with password for user: ${openidUser.username} : ${openidUser.openid}" throw new IncorrectCredentialsException("Invalid password for openid user '${authToken.username}', try to use openid instead user:password") } } def username = authToken.username // continues the default generated code... // ...
And that's all folks.