r257 - in trunk/nuiton-security/src/main: java/org/nuiton/web/security java/org/nuiton/web/security/actions resources
Author: echatellier Date: 2013-03-20 15:33:52 +0100 (Wed, 20 Mar 2013) New Revision: 257 Url: http://nuiton.org/projects/nuiton-web/repository/revisions/257 Log: fixes #2618: Redirect user to referer page if user ask for login page by himself fixes #2617: Cache user shiro autorization Modified: trunk/nuiton-security/src/main/java/org/nuiton/web/security/SecurityShiroFilter.java trunk/nuiton-security/src/main/java/org/nuiton/web/security/TopiaSecurityRealm.java trunk/nuiton-security/src/main/java/org/nuiton/web/security/actions/LoginAction.java trunk/nuiton-security/src/main/resources/struts.xml Modified: trunk/nuiton-security/src/main/java/org/nuiton/web/security/SecurityShiroFilter.java =================================================================== --- trunk/nuiton-security/src/main/java/org/nuiton/web/security/SecurityShiroFilter.java 2013-03-19 17:14:04 UTC (rev 256) +++ trunk/nuiton-security/src/main/java/org/nuiton/web/security/SecurityShiroFilter.java 2013-03-20 14:33:52 UTC (rev 257) @@ -66,9 +66,9 @@ public static final String ROOT_CONTEXT_CONTEXT = SecurityShiroFilter.class.getName() + "#" + TopiaContext.class.getName(); public static final String ANON_LOGIN = "anonymous"; - - public static final String SESSION_SAVED_URL = "savedUrl"; + public static final String SESSION_REQUESTED_URL = "securityRequestedUrl"; + protected ApplicationConfig config; protected TopiaContext rootContext; @@ -138,14 +138,20 @@ } // to have permission, a user must be authenticated - if (!subjectUser.isAuthenticated()) { + // can't use !subjectUser.isAuthenticated() here (for cache purpose) + if (subjectUser.getPrincipal() == null) { subjectUser.login(new UsernamePasswordToken(ANON_LOGIN, "")); } + // configuration + String loginUrl = config.getOption("topia.security.loginurl"); + // get permission from requested uri without context path HttpServletRequest httpServletRequest = ((HttpServletRequest)servletRequest); String contextPath = httpServletRequest.getContextPath(); String uri = httpServletRequest.getRequestURI(); + // removing jsession id from url + uri = uri.replaceFirst(";(jsessionid|JSESSIONID)=[\\w-]*", ""); if (uri.startsWith(contextPath)) { uri = uri.substring(contextPath.length()); } @@ -160,13 +166,22 @@ // dans ca cas, il faut sauvegarder la page d'avant comme url // de retour (seulement s'il n'y a pas deja une valeur de retour) Session session = subjectUser.getSession(); - if (uri.equals(config.getOption("topia.security.loginurl"))) { - if (session.getAttribute(SESSION_SAVED_URL) == null) { - String referrer = httpServletRequest.getHeader("referer"); - session.setAttribute(SESSION_SAVED_URL, referrer); + if (uri.equals(loginUrl)) { + // il ne faut pas ecraser l'url intercepter lors + // de la redirection vers la page de login + if (session.getAttribute(SESSION_REQUESTED_URL) == null) { + String referer = httpServletRequest.getHeader("referer"); + if (referer != null) { + // removing jsession id from url + referer = referer.replaceFirst(";(jsessionid|JSESSIONID)=[\\w-]*", ""); + if (!referer.endsWith(loginUrl)) { + if (log.isDebugEnabled()) { + log.debug("Remembering referer as " + referer); + } + session.setAttribute(SESSION_REQUESTED_URL, referer); + } + } } - } else { - session.removeAttribute(SESSION_SAVED_URL); } // on devrait appeler simplement super.doFilterInternal(servletRequest, servletResponse, chain); @@ -187,8 +202,9 @@ if (log.isDebugEnabled()) { log.debug("User is NOT permitted to access " + perm); } - // anon n'est pas considéré comme authenticated - if (ANON_LOGIN.equals(subjectUser.getPrincipal())) { + if (subjectUser.isAuthenticated()) { + ((HttpServletResponse)servletResponse).sendError(401, "Not authorized to access " + uri); + } else { if (log.isDebugEnabled()) { log.debug("Redirecting user to login page"); } @@ -198,11 +214,9 @@ if (httpServletRequest.getQueryString() != null) { requestURL.append('?').append(httpServletRequest.getQueryString()); } - session.setAttribute(SESSION_SAVED_URL, requestURL.toString()); + session.setAttribute(SESSION_REQUESTED_URL, requestURL.toString()); String redirect = contextPath + config.getOption("topia.security.loginurl"); ((HttpServletResponse)servletResponse).sendRedirect(redirect); - } else { - ((HttpServletResponse)servletResponse).sendError(401, "Not authorized to access " + uri); } } } Modified: trunk/nuiton-security/src/main/java/org/nuiton/web/security/TopiaSecurityRealm.java =================================================================== --- trunk/nuiton-security/src/main/java/org/nuiton/web/security/TopiaSecurityRealm.java 2013-03-19 17:14:04 UTC (rev 256) +++ trunk/nuiton-security/src/main/java/org/nuiton/web/security/TopiaSecurityRealm.java 2013-03-20 14:33:52 UTC (rev 257) @@ -24,6 +24,8 @@ package org.nuiton.web.security; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; import org.apache.commons.lang3.StringUtils; @@ -42,8 +44,8 @@ import org.nuiton.topia.TopiaContext; import org.nuiton.topia.TopiaException; import org.nuiton.topia.TopiaRuntimeException; +import org.nuiton.util.StringUtil; import org.nuiton.util.config.ApplicationConfig; -import org.nuiton.util.StringUtil; import org.nuiton.web.SecurityDAOHelper; /** @@ -59,10 +61,13 @@ protected ApplicationConfig config; + /** Authorization cache (invalidated at login). */ + protected transient Map<String, SimpleAuthorizationInfo> authorizationCache; + public TopiaSecurityRealm(TopiaContext rootContext, ApplicationConfig config) { this.rootContext = rootContext; this.config = config; - + authorizationCache = new HashMap<String, SimpleAuthorizationInfo>(); setCredentialsMatcher(this); } @@ -79,42 +84,43 @@ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { - SimpleAuthorizationInfo result = null; - - Properties props = config.getFlatOptions(); - TopiaContext transaction = null; - try { - String login = (String) principals.getPrimaryPrincipal(); - transaction = rootContext.beginTransaction(); - SecurityUserDAO securityUserDAO = SecurityDAOHelper.getSecurityUserDAO(transaction); - - if (log.isDebugEnabled()) { - log.debug("Build autorisation list for user : " + login); - } - - SecurityUser securityUser = securityUserDAO.findByLogin(login); - result = new SimpleAuthorizationInfo(); - for (SecurityRole role : securityUser.getSecurityRole()) { - for (String permission : role.getPermissions()) { - //result.addStringPermission(permission); - if (log.isDebugEnabled()) { - log.debug("- add permission : " + permission); - } - - for (String prop : props.stringPropertyNames()) { - if (prop.startsWith("topia.security.permission.")) { - String endProp = StringUtils.removeStart(prop, "topia.security.permission."); - String[] subs = endProp.split("\\."); - if (subs.length == 3) { - if (subs[2].equals("perm")) { - if (subs[1].equals(permission)) { - String perms = props.getProperty(prop); - // use ; separator because shiro use , - String[] permTab = perms.split("\\s*\\;\\s*"); - for (String perm : permTab) { - result.addStringPermission(perm); - if (log.isDebugEnabled()) { - log.debug(" string permission : " + perm); + String login = (String) principals.getPrimaryPrincipal(); + SimpleAuthorizationInfo result = authorizationCache.get(login); + if (result == null) { + Properties props = config.getFlatOptions(); + TopiaContext transaction = null; + try { + transaction = rootContext.beginTransaction(); + SecurityUserDAO securityUserDAO = SecurityDAOHelper.getSecurityUserDAO(transaction); + + if (log.isDebugEnabled()) { + log.debug("Build autorisation list for user : " + login); + } + + SecurityUser securityUser = securityUserDAO.findByLogin(login); + result = new SimpleAuthorizationInfo(); + for (SecurityRole role : securityUser.getSecurityRole()) { + for (String permission : role.getPermissions()) { + //result.addStringPermission(permission); + if (log.isDebugEnabled()) { + log.debug("- add permission : " + permission); + } + + for (String prop : props.stringPropertyNames()) { + if (prop.startsWith("topia.security.permission.")) { + String endProp = StringUtils.removeStart(prop, "topia.security.permission."); + String[] subs = endProp.split("\\."); + if (subs.length == 3) { + if (subs[2].equals("perm")) { + if (subs[1].equals(permission)) { + String perms = props.getProperty(prop); + // use ; separator because shiro use , + String[] permTab = perms.split("\\s*\\;\\s*"); + for (String perm : permTab) { + result.addStringPermission(perm); + if (log.isDebugEnabled()) { + log.debug(" string permission : " + perm); + } } } } @@ -123,40 +129,47 @@ } } } - } + + // si seul l'utilisateur anon existe + // on lui offre une promotion + if (login.equals(SecurityShiroFilter.ANON_LOGIN) && securityUserDAO.count() == 1) { + result.addStringPermission("*"); + if (log.isDebugEnabled()) { + log.debug("Grant all rigth (*) because no user exists"); + } + } + + // si la securité est desactivee, + if (config.getOptionAsBoolean("topia.security.disable")) { + result.addStringPermission("*"); + } + + // ajout de l'url de login et logout quand meme !!! + result.addStringPermission("url" + SecurityUtil.convertToShiroPerm(config.getOption("topia.security.loginurl"), + config.getOption("topia.security.separators"))); + result.addStringPermission("url" + SecurityUtil.convertToShiroPerm(config.getOption("topia.security.logouturl"), + config.getOption("topia.security.separators"))); - // si seul l'utilisateur anon existe - // on lui offre une promotion - if (login.equals(SecurityShiroFilter.ANON_LOGIN) && securityUserDAO.count() == 1) { - result.addStringPermission("*"); - if (log.isDebugEnabled()) { - log.debug("Grant all rigth (*) because no user exists"); + // cache authorization + authorizationCache.put(login, result); + } catch (Exception ex) { + if (log.isErrorEnabled()) { + log.error("Can't get user permission", ex); } + } finally { + if (transaction != null) { + try { + transaction.closeContext(); + } catch (TopiaException ex) { + throw new TopiaRuntimeException(ex); + } + } } - - // si la securité est desactivee, - if (config.getOptionAsBoolean("topia.security.disable")) { - result.addStringPermission("*"); + } else { + if (log.isTraceEnabled()) { + log.trace("Using autorisation from cache for " + login); } - - // ajout de l'url de login et logout quand meme !!! - result.addStringPermission("url" + SecurityUtil.convertToShiroPerm(config.getOption("topia.security.loginurl"), - config.getOption("topia.security.separators"))); - result.addStringPermission("url" + SecurityUtil.convertToShiroPerm(config.getOption("topia.security.logouturl"), - config.getOption("topia.security.separators"))); - - } catch (Exception ex) { - - } finally { - if (transaction != null) { - try { - transaction.closeContext(); - } catch (TopiaException ex) { - throw new TopiaRuntimeException(ex); - } - } } - return result; } @@ -186,6 +199,9 @@ result = new SimpleAuthenticationInfo(securityUser.getLogin(), securityUser.getPassword(), getName()); } + + // invalidate cache for login + authorizationCache.remove(login); } } catch (TopiaException ex) { Modified: trunk/nuiton-security/src/main/java/org/nuiton/web/security/actions/LoginAction.java =================================================================== --- trunk/nuiton-security/src/main/java/org/nuiton/web/security/actions/LoginAction.java 2013-03-19 17:14:04 UTC (rev 256) +++ trunk/nuiton-security/src/main/java/org/nuiton/web/security/actions/LoginAction.java 2013-03-20 14:33:52 UTC (rev 257) @@ -26,9 +26,6 @@ import static org.nuiton.i18n.I18n._; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.shiro.SecurityUtils; @@ -40,11 +37,9 @@ import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; -import org.apache.struts2.interceptor.ServletRequestAware; -import org.apache.struts2.interceptor.ServletResponseAware; import org.nuiton.web.security.SecurityShiroFilter; -public class LoginAction extends AbstractAction implements ServletRequestAware, ServletResponseAware { +public class LoginAction extends AbstractAction { private static final Log log = LogFactory.getLog(LoginAction.class); @@ -55,19 +50,8 @@ protected String password; - protected HttpServletRequest request; - protected HttpServletResponse response; + protected String savedUrl; - @Override - public void setServletRequest(HttpServletRequest request) { - this.request = request; - } - - @Override - public void setServletResponse(HttpServletResponse response) { - this.response = response; - } - public void setLogin(String login) { this.login = login; } @@ -78,7 +62,7 @@ @Override public String execute() throws Exception { - String result = null; + String result = SUCCESS; if (login == null || password == null) { result = input(); @@ -87,18 +71,19 @@ Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(login, password); currentUser.login(token); - result = SUCCESS; - + // marche pas :( //SavedRequest savedRequest = WebUtils.getAndClearSavedRequest(request); Session session = currentUser.getSession(); - String requestURL = (String)session.getAttribute(SecurityShiroFilter.SESSION_SAVED_URL); - if (request != null) { // can be + savedUrl = (String)session.getAttribute(SecurityShiroFilter.SESSION_REQUESTED_URL); + if (savedUrl != null) { // can be if (log.isDebugEnabled()) { - log.debug("Redirecting to saved url " + requestURL); + log.debug("Redirecting to saved url " + savedUrl); } - session.removeAttribute(SecurityShiroFilter.SESSION_SAVED_URL); - response.sendRedirect(requestURL); + session.removeAttribute(SecurityShiroFilter.SESSION_REQUESTED_URL); + result = "redirect"; + } else { + result = SUCCESS; } } catch (UnknownAccountException ex) { addActionError(_("Identifiant ou mot de passe invalide !")); @@ -125,4 +110,8 @@ return result; } + public String getSavedUrl() { + return savedUrl; + } + } Modified: trunk/nuiton-security/src/main/resources/struts.xml =================================================================== --- trunk/nuiton-security/src/main/resources/struts.xml 2013-03-19 17:14:04 UTC (rev 256) +++ trunk/nuiton-security/src/main/resources/struts.xml 2013-03-20 14:33:52 UTC (rev 257) @@ -58,6 +58,7 @@ <result name="success" type="redirectAction"> <param name="actionName">user-roles</param> </result> + <result name="redirect" type="redirect">${savedUrl}</result> </action> <action name="logout" class="org.nuiton.web.security.actions.LogoutAction"> <result name="success" type="redirectAction">
participants (1)
-
echatellier@users.nuiton.org