/* vim: set ts=2 et sw=2 cindent fo=qroca: */ package com.globant.katari.core.security; import org.acegisecurity.AccessDecisionManager; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; import org.acegisecurity.ConfigAttributeDefinition; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource; import org.apache.commons.lang.Validate; import com.globant.katari.core.web.ModuleUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** Secure URL Access Helper. * * This helper is used by the katari secureUrlArea macro and the {@link * MenuAccessFilterer} to determine if an action is accessible for the current * user based on the role configuration of the target url. * * @author gerardo.bercovich */ public class SecureUrlAccessHelper { /** The class logger. */ private static Logger log = LoggerFactory.getLogger(SecureUrlAccessHelper.class); /** The acegi definition source implementation. * * It is used to obtain the ConfigAttributeDefinition with the * roles for a given url. It is never null. */ private final AbstractFilterInvocationDefinitionSource definitionSource; /** The acegi decider. * * It is never null. */ private final AccessDecisionManager accessDecider; /** * Constructor. * * It constructs a SecureUrlAccessHelper with the AccessDesicionManager * and the {@link AbstractFilterInvocationDefinitionSource} given. * * @param thedefinitionSource the definition source used to obtain the roles * that can access a url. It cannot be null. * * @param theAccessDecisionManager the access decision manager used to check * if the user has the necessary roles. It cannot be null. */ public SecureUrlAccessHelper( final AbstractFilterInvocationDefinitionSource thedefinitionSource, final AccessDecisionManager theAccessDecisionManager) { Validate.notNull(thedefinitionSource, "Filter invocation access definition " + "source cannot be null"); Validate.notNull(theAccessDecisionManager, "Access Decision Manager " + "cannot be null"); definitionSource = thedefinitionSource; accessDecider = theAccessDecisionManager; } /** * Verify if the given url is accessible by the current user based on the * given url and the current uri. * * The current uri is used if the given url is relative. * * @param currentUri the current uri. If the target url is relative it cannot * be null. * * @param targetUrl the target url. It cannot be null. * * @return True if the current user has access to the given url (theUrl). */ public boolean canAccessUrl(final String currentUri, final String targetUrl) { log.trace("Entering canAccessUrl({}, {})", currentUri, targetUrl); Validate.notNull(targetUrl, "The url cannot be null"); Validate.isTrue(!targetUrl.matches("^[^:]+://.+"), "The url has protocol"); Authentication authentication; authentication = SecurityContextHolder.getContext().getAuthentication(); Validate.notNull(authentication, "The authentication cannot be null"); String url = null; if (!targetUrl.startsWith("/")) { // if the url is relative compose url. Validate.notNull(currentUri, "The current uri cannot be null for a relative url"); Validate.isTrue(currentUri.matches(".*/module/.*"), "The corrent uri does not contain any module"); String globalContextPath = ModuleUtils.getGlobalContextPath(currentUri); url = currentUri.substring(globalContextPath.length()); // Strip the last path component. int lastSlash = url.lastIndexOf('/'); url = url.substring(0, lastSlash + 1); url = url + targetUrl; } else { // if is absolute validate context path. String globalContextPath = ModuleUtils.getGlobalContextPath(targetUrl); Validate.isTrue(targetUrl.matches(".*/module/.*"), "The target url does not contain any module"); url = targetUrl.substring(globalContextPath.length()); } log.debug("Checking {}", url); ConfigAttributeDefinition attributes; try { attributes = definitionSource.lookupAttributes(url); } catch (AccessDeniedException e) { log.trace("Leaving canAccessUrl with false. No attribute matched the" + " link."); return false; } Validate.notNull(attributes, "No attribtues found for url"); try { accessDecider.decide(authentication, url, attributes); } catch (AccessDeniedException e) { log.trace("Leaving canAccessUrl with false"); return false; } log.trace("Leaving canAccessUrl with true"); return true; } }