Grails Spring Security max concurrent session -
i have grails 2.5.1 app spring security plugin(2.0-rc5). block number of current session per user. have read blog , doesn't work.(http://www.block-consult.com/blog/2012/01/20/restricting-concurrent-user-sessions-in-grails-2-using-spring-security-core-plugin/) resources.groovy
beans = { sessionregistry(sessionregistryimpl) concurrencyfilter(concurrentsessionfilter,sessionregistry,'/main/index'){ logouthandlers = [ref("remembermeservices"), ref("securitycontextlogouthandler")] } concurrentsessioncontrolstrategy(concurrentsessioncontrolauthenticationstrategy, sessionregistry) { exceptionifmaximumexceeded = true maximumsessions = 1 } }
in boostrap.groovy
def init = { servletcontext -> springsecurityutils.clientregisterfilter('concurrencyfilter', securityfilterposition.concurrent_session_filter) }
and config.groovy have added this:
grails.plugin.springsecurity.usehttpsessioneventpublisher = true
thanks..
to start with, let me warn if decided continue solution.
- sessionregistryimpl not scalable. need create own scalable implementation based on scaling plan(e.g. data grid). session replication not enough.
- currently, default logout handlers did not remove sessionregistry properly. have created sample logout handler called customsessionlogouthandler.
- you have override grails spring-security-core login controller handle sessionauthenticationexception.
- you can change number of users can login maximumsessions = 1 -1 unlimited sessions.
first, in resources.groovy
import org.springframework.security.core.session.sessionregistryimpl; import org.springframework.security.web.authentication.session.concurrentsessioncontrolauthenticationstrategy; import org.springframework.security.web.authentication.session.sessionfixationprotectionstrategy; import org.springframework.security.web.authentication.session.registersessionauthenticationstrategy; import org.springframework.security.web.authentication.session.compositesessionauthenticationstrategy; import com.basic.customsessionlogouthandler // place spring dsl code here beans = { sessionregistry(sessionregistryimpl) customsessionlogouthandler(customsessionlogouthandler,ref('sessionregistry') ) concurrentsessioncontrolauthenticationstrategy(concurrentsessioncontrolauthenticationstrategy,ref('sessionregistry')){ exceptionifmaximumexceeded = true maximumsessions = 1 } sessionfixationprotectionstrategy(sessionfixationprotectionstrategy){ migratesessionattributes = true alwayscreatesession = true } registersessionauthenticationstrategy(registersessionauthenticationstrategy,ref('sessionregistry')) sessionauthenticationstrategy(compositesessionauthenticationstrategy,[ref('concurrentsessioncontrolauthenticationstrategy'),ref('sessionfixationprotectionstrategy'),ref('registersessionauthenticationstrategy')]) }
in config.groovy make sure customsessionlogouthandler first before securitycontextlogouthandler:
grails.plugin.springsecurity.logout.handlernames = ['customsessionlogouthandler','securitycontextlogouthandler']
concurrentsessioncontrolauthenticationstrategy uses i18n. can have in language:
concurrentsessioncontrolauthenticationstrategy.exceededallowed = maximum sessions principal exceeded. {0}
this sample customsessionlogouthandler can save in src/groovy/com/basic/customsessionlogouthandler.groovy:
/* * copyright 2002-2013 original author or authors. * * licensed under apache license, version 2.0 (the "license"); * may not use file except in compliance license. * may obtain copy of license @ * * http://www.apache.org/licenses/license-2.0 * * unless required applicable law or agreed in writing, software * distributed under license distributed on "as is" basis, * without warranties or conditions of kind, either express or implied. * see license specific language governing permissions , * limitations under license. */ package com.basic; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import org.springframework.security.core.authentication; import org.springframework.security.web.authentication.logout.logouthandler; import org.springframework.util.assert; import org.springframework.security.core.session.sessionregistry; /** * {@link customsessionlogouthandler} in charge of removing {@link sessionregistry} upon logout. * new {@link sessionregistry} generated framework upon next request. * * @author mohd qusyairi * @since 0.1 */ public final class customsessionlogouthandler implements logouthandler { private final sessionregistry sessionregistry; /** * creates new instance * @param sessionregistry {@link sessionregistry} use */ public customsessionlogouthandler(sessionregistry sessionregistry) { assert.notnull(sessionregistry, "sessionregistry cannot null"); this.sessionregistry = sessionregistry; } /** * clears {@link sessionregistry} * * @see org.springframework.security.web.authentication.logout.logouthandler#logout(javax.servlet.http.httpservletrequest, * javax.servlet.http.httpservletresponse, * org.springframework.security.core.authentication) */ public void logout(httpservletrequest request, httpservletresponse response, authentication authentication) { this.sessionregistry.removesessioninformation(request.getsession().getid()); } }
my sample login controller (i copied source) if need too. save normal controller in project override default. see line 115 below handle sessionauthenticationexception:
/* copyright 2013-2016 original author or authors. * * licensed under apache license, version 2.0 (the "license"); * may not use file except in compliance license. * may obtain copy of license @ * * http://www.apache.org/licenses/license-2.0 * * unless required applicable law or agreed in writing, software * distributed under license distributed on "as is" basis, * without warranties or conditions of kind, either express or implied. * see license specific language governing permissions , * limitations under license. */ package com.basic import grails.converters.json import org.springframework.security.access.annotation.secured import org.springframework.security.authentication.accountexpiredexception import org.springframework.security.authentication.authenticationtrustresolver import org.springframework.security.authentication.credentialsexpiredexception import org.springframework.security.authentication.disabledexception import org.springframework.security.authentication.lockedexception import org.springframework.security.core.authentication import org.springframework.security.core.context.securitycontextholder import org.springframework.security.web.webattributes import org.springframework.security.web.authentication.session.sessionauthenticationexception import javax.servlet.http.httpservletresponse import grails.plugin.springsecurity.springsecurityutils @secured('permitall') class logincontroller { /** dependency injection authenticationtrustresolver. */ authenticationtrustresolver authenticationtrustresolver /** dependency injection springsecurityservice. */ def springsecurityservice /** default action; redirects 'defaulttargeturl' if logged in, /login/auth otherwise. */ def index() { if (springsecurityservice.isloggedin()) { redirect uri: conf.successhandler.defaulttargeturl } else { redirect action: 'auth', params: params } } /** show login page. */ def auth() { def conf = getconf() if (springsecurityservice.isloggedin()) { redirect uri: conf.successhandler.defaulttargeturl return } string posturl = request.contextpath + conf.apf.filterprocessesurl render view: 'auth', model: [posturl: posturl, remembermeparameter: conf.rememberme.parameter, usernameparameter: conf.apf.usernameparameter, passwordparameter: conf.apf.passwordparameter, gsplayout: conf.gsp.layoutauth] } /** redirect action ajax requests. */ def authajax() { response.setheader 'location', conf.auth.ajaxloginformurl render(status: httpservletresponse.sc_unauthorized, text: 'unauthorized') } /** show denied page. */ def denied() { if (springsecurityservice.isloggedin() && authenticationtrustresolver.isrememberme(authentication)) { // have cookie page guarded is_authenticated_fully (or equivalent expression) redirect action: 'full', params: params return } [gsplayout: conf.gsp.layoutdenied] } /** login page users remember-me cookie accessing is_authenticated_fully page. */ def full() { def conf = getconf() render view: 'auth', params: params, model: [hascookie: authenticationtrustresolver.isrememberme(authentication), posturl: request.contextpath + conf.apf.filterprocessesurl, remembermeparameter: conf.rememberme.parameter, usernameparameter: conf.apf.usernameparameter, passwordparameter: conf.apf.passwordparameter, gsplayout: conf.gsp.layoutauth] } /** callback after failed login. redirects auth page warning message. */ def authfail() { string msg = '' def exception = session[webattributes.authentication_exception] if (exception) { if (exception instanceof accountexpiredexception) { msg = message(code: 'springsecurity.errors.login.expired') } else if (exception instanceof credentialsexpiredexception) { msg = message(code: 'springsecurity.errors.login.passwordexpired') } else if (exception instanceof disabledexception) { msg = message(code: 'springsecurity.errors.login.disabled') } else if (exception instanceof lockedexception) { msg = message(code: 'springsecurity.errors.login.locked') } else if (exception instanceof sessionauthenticationexception){ msg = exception.getmessage() } else { msg = message(code: 'springsecurity.errors.login.fail') } } if (springsecurityservice.isajax(request)) { render([error: msg] json) } else { flash.message = msg redirect action: 'auth', params: params } } /** ajax success redirect url. */ def ajaxsuccess() { render([success: true, username: authentication.name] json) } /** ajax denied redirect url. */ def ajaxdenied() { render([error: 'access denied'] json) } protected authentication getauthentication() { securitycontextholder.context?.authentication } protected configobject getconf() { springsecurityutils.securityconfig } }
Comments
Post a Comment