All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.manydesigns.portofino.logic.SecurityLogic Maven / Gradle / Ivy

/*
 * Copyright (C) 2005-2017 ManyDesigns srl.  All rights reserved.
 * http://www.manydesigns.com/
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package com.manydesigns.portofino.logic;

import com.manydesigns.elements.ElementsThreadLocals;
import com.manydesigns.portofino.dispatcher.Dispatch;
import com.manydesigns.portofino.dispatcher.PageInstance;
import com.manydesigns.portofino.modules.BaseModule;
import com.manydesigns.portofino.pages.Page;
import com.manydesigns.portofino.pages.Permissions;
import com.manydesigns.portofino.security.AccessLevel;
import com.manydesigns.portofino.security.RequiresAdministrator;
import com.manydesigns.portofino.security.RequiresPermissions;
import com.manydesigns.portofino.shiro.GroupPermission;
import com.manydesigns.portofino.shiro.PagePermission;
import net.sourceforge.stripes.action.ActionBean;
import org.apache.commons.configuration.Configuration;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author Paolo Predonzani     - [email protected]
 * @author Angelo Lupo          - [email protected]
 * @author Giampiero Granatella - [email protected]
 * @author Alessio Stalla       - [email protected]
 */
public class SecurityLogic {
    public static final String copyright =
            "Copyright (C) 2005-2017 ManyDesigns srl";

    //**************************************************************************
    // Default groups
    //**************************************************************************

    public static final String GROUP_ALL = "group.all";
    public static final String GROUP_ANONYMOUS = "group.anonymous";
    public static final String GROUP_REGISTERED = "group.registered";
    public static final String GROUP_ADMINISTRATORS = "group.administrators";
    public static final String GROUP_ALL_DEFAULT = "all";
    public static final String GROUP_ANONYMOUS_DEFAULT = "anonymous";
    public static final String GROUP_REGISTERED_DEFAULT = "registered";
    public static final String GROUP_ADMINISTRATORS_DEFAULT = "administrators";

    public static final Logger logger = LoggerFactory.getLogger(SecurityLogic.class);

    public static boolean hasPermissions(Configuration conf, Dispatch dispatch, Subject subject, Method handler) {
        logger.debug("Checking action permissions");
        return hasPermissions(conf, dispatch.getLastPageInstance(), subject, handler);
    }

    public static boolean hasPermissions(Configuration conf, PageInstance instance, Subject subject, Method handler) {
        logger.debug("Checking action permissions");
        Class theClass = instance.getActionClass();
        RequiresPermissions requiresPermissions = getRequiresPermissionsAnnotation(handler, theClass);
        if(requiresPermissions != null) {
            AccessLevel accessLevel = requiresPermissions.level();
            String[] permissions = requiresPermissions.permissions();
            return hasPermissions(conf, instance, subject, accessLevel, permissions);
        }
        return true;
    }

    public static boolean hasPermissions
            (Configuration conf, PageInstance instance, Subject subject, AccessLevel accessLevel, String... permissions) {
        Permissions configuration = calculateActualPermissions(instance);
        return hasPermissions(conf, configuration, subject, accessLevel, permissions);
    }

    public static Permissions calculateActualPermissions(PageInstance instance) {
        List pages = new ArrayList();
        while (instance != null) {
            pages.add(0, instance.getPage());
            instance = instance.getParent();
        }

        return calculateActualPermissions(new Permissions(), pages);
    }

    public static Permissions calculateActualPermissions(Permissions basePermissions, List pages) {
        Permissions result = new Permissions();
        Map resultLevels = result.getActualLevels();
        resultLevels.putAll(basePermissions.getActualLevels());
        for (Page current : pages) {
            Permissions currentPerms = current.getPermissions();

            Map currentLevels = currentPerms.getActualLevels();
            for(Map.Entry entry : currentLevels.entrySet()) {
                String currentGroup = entry.getKey();
                AccessLevel currentLevel = entry.getValue();
                AccessLevel resultLevel = resultLevels.get(currentGroup);

                if(resultLevel != AccessLevel.DENY && currentLevel != null) {
                    resultLevels.put(currentGroup, currentLevel);
                }
            }
        }

        if (pages.size() > 0) {
            Page lastPage = pages.get(pages.size() - 1);
            Map> lastPermissions =
                    lastPage.getPermissions().getActualPermissions();
            result.getActualPermissions().putAll(lastPermissions);
        } else {
            result.getActualPermissions().putAll(basePermissions.getActualPermissions());
        }

        return result;
    }

    public static boolean hasPermissions
            (Configuration conf, Permissions configuration, Subject subject, Method handler, Class theClass) {
        logger.debug("Checking action permissions");
        RequiresPermissions requiresPermissions = getRequiresPermissionsAnnotation(handler, theClass);
        if(requiresPermissions != null) {
            return hasPermissions(conf, configuration, subject, requiresPermissions);
        } else {
            return true;
        }
    }

    public static boolean hasPermissions
            (Configuration conf, Permissions configuration, Subject subject, RequiresPermissions thing) {
        return hasPermissions(conf, configuration, subject, thing.level(), thing.permissions());
    }

    public static RequiresPermissions getRequiresPermissionsAnnotation(Method handler, Class theClass) {
        RequiresPermissions requiresPermissions = handler.getAnnotation(RequiresPermissions.class);
        if (requiresPermissions != null) {
            logger.debug("Action method requires specific permissions: {}", handler);
        } else {
            requiresPermissions = theClass.getAnnotation(RequiresPermissions.class);
            if (requiresPermissions != null) {
                logger.debug("Action class requires specific permissions: {}",
                             theClass);
            }
        }
        return requiresPermissions;
    }

    public static boolean hasPermissions
            (Configuration conf, Permissions configuration, Subject subject, AccessLevel level, String... permissions) {
        Object principal = subject.getPrincipal();
        if(principal != null) {
            String administratorsGroup = getAdministratorsGroup(conf);
            if(isUserInGroup(administratorsGroup)) {
                return true;
            }
            PagePermission pagePermission = new PagePermission(configuration, level, permissions);
            return subject.isPermitted(pagePermission);
        } else {
            //Shiro does not check permissions for non authenticated users
            return hasAnonymousPermissions(conf, configuration, level, permissions);
        }
    }

    public static boolean hasPermissions
            (Configuration conf, Permissions configuration, org.apache.shiro.mgt.SecurityManager securityManager,
             PrincipalCollection principals, AccessLevel level, String... permissions) {
        if(principals != null) {
            PagePermission pagePermission = new PagePermission(configuration, level, permissions);
            return securityManager.isPermitted(principals, pagePermission);
        } else {
            //Shiro does not check permissions for non authenticated users
            return hasAnonymousPermissions(conf, configuration, level, permissions);
        }
    }

    public static boolean hasAnonymousPermissions
            (Configuration conf, Permissions configuration, AccessLevel level, String... permissions) {
        PagePermission pagePermission = new PagePermission(configuration, level, permissions);
        List groups = new ArrayList();
        groups.add(getAllGroup(conf));
        groups.add(getAnonymousGroup(conf));
        return new GroupPermission(groups).implies(pagePermission);
    }

    public static boolean isUserInGroup(String groupId) {
        Subject subject = SecurityUtils.getSubject();
        return subject.hasRole(groupId);
    }

    public static boolean isAdministrator(ServletRequest request) {
        ServletContext servletContext = ElementsThreadLocals.getServletContext();
        Configuration conf =
                (Configuration) servletContext.getAttribute(BaseModule.PORTOFINO_CONFIGURATION);
        return isAdministrator(conf);
    }

    public static boolean isAdministrator(Configuration conf) {
        String administratorsGroup = getAdministratorsGroup(conf);
        return isUserInGroup(administratorsGroup);
    }

    public static boolean satisfiesRequiresAdministrator(HttpServletRequest request, ActionBean actionBean, Method handler) {
        logger.debug("Checking if action or method required administrator");
        boolean requiresAdministrator = false;
        if (handler.isAnnotationPresent(RequiresAdministrator.class)) {
            logger.debug("Action method requires administrator: {}", handler);
            requiresAdministrator = true;
        } else {
            Class actionClass = actionBean.getClass();
            while (actionClass != null) {
                if (actionClass.isAnnotationPresent(RequiresAdministrator.class)) {
                    logger.debug("Action class requires administrator: {}", actionClass);
                    requiresAdministrator = true;
                    break;
                }
                actionClass = actionClass.getSuperclass();
            }
        }

        boolean isNotAdmin = !isAdministrator(request);
        boolean doesNotSatisfy = requiresAdministrator && isNotAdmin;
        if (doesNotSatisfy) {
            logger.info("User is not an administrator");
            return false;
        }
        return true;
    }

    public static String getAdministratorsGroup(Configuration conf) {
        return conf.getString(GROUP_ADMINISTRATORS, GROUP_ADMINISTRATORS_DEFAULT);
    }

    public static String getAllGroup(Configuration conf) {
        return conf.getString(GROUP_ALL, GROUP_ALL_DEFAULT);
    }

    public static String getAnonymousGroup(Configuration conf) {
        return conf.getString(GROUP_ANONYMOUS, GROUP_ANONYMOUS_DEFAULT);
    }

    public static String getRegisteredGroup(Configuration conf) {
        return conf.getString(GROUP_REGISTERED, GROUP_REGISTERED_DEFAULT);
    }

    public static boolean isAllowed(
            HttpServletRequest request, Dispatch dispatch, ActionBean actionBean, Method handler) {
        Subject subject = SecurityUtils.getSubject();

        if (!satisfiesRequiresAdministrator(request, actionBean, handler)) {
            return false;
        }

        logger.debug("Checking page permissions");
        boolean isNotAdmin = !isAdministrator(request);
        if (isNotAdmin) {
            ServletContext servletContext = request.getServletContext();
            Configuration configuration = (Configuration) servletContext.getAttribute(BaseModule.PORTOFINO_CONFIGURATION);
            Permissions permissions;
            String resource;
            boolean allowed;
            if(dispatch != null) {
                logger.debug("The protected resource is a page action");
                resource = dispatch.getLastPageInstance().getPath();
                allowed = hasPermissions(configuration, dispatch, subject, handler);
            } else {
                logger.debug("The protected resource is a plain Stripes ActionBean");
                resource = request.getRequestURI();
                permissions = new Permissions();
                allowed = hasPermissions
                        (configuration, permissions, subject, handler, actionBean.getClass());
            }
            if(!allowed) {
                logger.info("Access to {} is forbidden", resource);
                return false;
            }
        }
        return true;
    }

    public static boolean hasPermissions
            (Configuration conf, Method method, Class fallbackClass, PageInstance pageInstance, Subject subject) {
        RequiresPermissions requiresPermissions =
                    SecurityLogic.getRequiresPermissionsAnnotation(method, fallbackClass);
        if(requiresPermissions != null) {
            Permissions permissions = SecurityLogic.calculateActualPermissions(pageInstance);
            return SecurityLogic.hasPermissions
                    (conf, permissions, subject, requiresPermissions);
        } else {
            return true;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy