org.craftercms.cstudio.alfresco.service.impl.PermissionServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.craftercms.cstudio.alfresco.service.impl.PermissionServiceImpl.java

Source

/*******************************************************************************
 * Crafter Studio Web-content authoring solution
 *     Copyright (C) 2007-2013 Crafter Software Corporation.
 * 
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     This program 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 General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package org.craftercms.cstudio.alfresco.service.impl;

import javolution.util.FastList;
import javolution.util.FastMap;
import javolution.util.FastSet;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthorityType;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.craftercms.cstudio.alfresco.constant.CStudioConstants;
import org.craftercms.cstudio.alfresco.constant.CStudioXmlConstants;
import org.craftercms.cstudio.alfresco.dm.service.api.DmContentTypeService;
import org.craftercms.cstudio.alfresco.service.api.PermissionService;
import org.craftercms.cstudio.alfresco.service.api.PersistenceManagerService;
import org.craftercms.cstudio.alfresco.service.exception.ServiceException;
import org.craftercms.cstudio.alfresco.to.ContentTypeConfigTO;
import org.craftercms.cstudio.alfresco.to.PermissionsConfigTO;
import org.craftercms.cstudio.alfresco.to.TimeStamped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 * Responsible for determining the permissions based on the user and group. The
 * role mappings and permissions are read from files named roleMappingsFileName
 * and permissionsFileName in the path permissionsPath.
 * 
 * @author Sweta Chalasani
 * @author Sandra O'Keeffe
 * 
 */
public class PermissionServiceImpl extends ConfigurableServiceBase implements PermissionService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionServiceImpl.class);

    protected String _roleMappingsFileName;
    protected String _permissionsFileName;

    /** permission configuration mapping **/
    protected Map<String, PermissionsConfigTO> _permissionsConfigMap = new HashMap<String, PermissionsConfigTO>();

    protected Set<String> allRoles = null;

    @Override
    public void register() {
        this._servicesManager.registerService(PermissionService.class, this);
    }

    /*
    * (non-Javadoc)
    * @see org.craftercms.crafter.alfresco.service.api.PermissionService#getRoles(java.lang.String)
    */
    public Set<String> getRoles(String site) {
        // load roles again if configuration is updated
        if (this.allRoles == null || super.isConfigUpdated(getPermissionsKey(site, _roleMappingsFileName))) {
            // determine whether to refresh the config
            checkForUpdate(site);
            // get the config files from the permissionsConfigMap based on the key
            PermissionsConfigTO rolesConfig = _permissionsConfigMap
                    .get(getPermissionsKey(site, _roleMappingsFileName));
            if (rolesConfig != null) {
                Set<String> uniqueRoles = new FastSet<String>();
                Map<String, List<String>> rolesMapping = rolesConfig.getRoles();
                if (rolesMapping != null) {
                    for (String key : rolesMapping.keySet()) {
                        List<String> roles = rolesMapping.get(key);
                        if (roles != null) {
                            uniqueRoles.addAll(roles);
                        }
                    }
                }
                this.allRoles = uniqueRoles;
            } else {
                this.allRoles = new FastSet<String>(0);
            }
        }
        return this.allRoles;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.craftercms.crafter.alfresco.service.api.PermissionService#getUserRoles
     * (java.lang.String, java.lang.String)
     */
    @Override
    public Set<String> getUserRoles(String site, String user) {

        Set<String> groups = getService(PersistenceManagerService.class)
                .getContainingAuthorities(AuthorityType.GROUP, user, false);
        if (groups != null && groups.size() > 0) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Groups for " + user + " in " + site + ": " + groups);
            }
            // determine whether to refresh the config
            checkForUpdate(site);
            // get the config files from the permissionsConfigMap based on the key
            PermissionsConfigTO rolesConfig = _permissionsConfigMap
                    .get(getPermissionsKey(site, _roleMappingsFileName));
            Set<String> userRoles = new FastSet<String>();
            if (rolesConfig != null) {
                Map<String, List<String>> rolesMap = rolesConfig.getRoles();
                for (String group : groups) {
                    String groupName = group.replaceFirst("GROUP_", "");
                    List<String> roles = rolesMap.get(groupName);
                    if (roles != null) {
                        userRoles.addAll(roles);
                    }
                }
            }
            return userRoles;
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("No groups found for " + user + " in " + site);
            }
        }
        return new FastSet<String>(0);
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.craftercms.crafter.alfresco.service.api.PermissionService#
     * getUserPermissions(java.lang.String, java.lang.String, java.lang.String,
     * java.util.List)
     */
    @Override
    public Set<String> getUserPermissions(String site, String path, String user, List<String> groups) {

        // determine whether to refresh the config
        checkForUpdate(site);

        // get the config files from the permissionsConfigMap based on the key
        PermissionsConfigTO rolesConfig = _permissionsConfigMap.get(getPermissionsKey(site, _roleMappingsFileName));
        PermissionsConfigTO permissionsConfig = _permissionsConfigMap
                .get(getPermissionsKey(site, _permissionsFileName));
        Set<String> roles = new FastSet<String>();
        addUserRoles(roles, site, user);
        addGroupRoles(roles, site, groups, rolesConfig);
        // resolve the permission
        Set<String> permissions = populateUserPermissions(site, path, roles, permissionsConfig);
        // check if the user is allowed to edit the content 
        try {
            DmContentTypeService dmContentTypeService = getService(DmContentTypeService.class);
            ContentTypeConfigTO config = dmContentTypeService.getContentTypeByRelativePath(site, null, path);
            boolean isAllowed = dmContentTypeService.isUserAllowed(roles, config);
            if (!isAllowed) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("The user is not allowed to access " + config.getName() + ". adding permission: "
                            + CStudioConstants.PERMISSION_VALUE_NOT_ALLOWED);
                }
                // If no default role is set
                permissions.add(CStudioConstants.PERMISSION_VALUE_NOT_ALLOWED);
                return permissions;
            }
        } catch (ServiceException e) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Error while getting the content type of " + path
                        + ". skipping user role checking on the content.");
            }
        }
        return permissions;
    }

    /**
     * add user roles 
     * 
     * @param roles
     * @param site
     * @param user
     */
    protected void addUserRoles(Set<String> roles, String site, String user) {
        if (!StringUtils.isEmpty(user)) {
            Set<String> userRoles = this.getUserRoles(site, user);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Adding roles by user: " + userRoles);
            }
            roles.addAll(userRoles);
        }
    }

    /**
     * get roles by groups 
     * 
     * @param site
     * @param groups
     * @param rolesConfig 
     * @return
     */
    protected void addGroupRoles(Set<String> roles, String site, List<String> groups,
            PermissionsConfigTO rolesConfig) {
        if (groups != null) {
            Map<String, List<String>> rolesMap = rolesConfig.getRoles();
            for (String group : groups) {
                List<String> groupRoles = rolesMap.get(group);
                if (groupRoles != null) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Adding roles by group " + group + ": " + roles);
                    }
                    roles.addAll(groupRoles);
                }
            }
        }
    }

    /**
     * populate user permissions
     * 
     * @param site
     * @param path
     * @param roles
     * @param permissionsConfig
     */
    protected Set<String> populateUserPermissions(String site, String path, Set<String> roles,
            PermissionsConfigTO permissionsConfig) {
        Set<String> permissions = new FastSet<String>();
        if (roles != null && !roles.isEmpty()) {
            for (String role : roles) {
                Map<String, Map<String, List<Node>>> permissionsMap = permissionsConfig.getPermissions();
                Map<String, List<Node>> siteRoles = permissionsMap.get(site);
                if (siteRoles == null || siteRoles.isEmpty()) {
                    siteRoles = permissionsMap.get("*");
                }
                if (siteRoles != null && !siteRoles.isEmpty()) {
                    List<Node> ruleNodes = siteRoles.get(role);
                    if (ruleNodes == null || ruleNodes.isEmpty()) {
                        ruleNodes = siteRoles.get("*");
                    }
                    if (ruleNodes != null && !ruleNodes.isEmpty()) {
                        for (Node ruleNode : ruleNodes) {
                            String regex = ruleNode.valueOf(CStudioXmlConstants.DOCUMENT_ATTR_REGEX);
                            if (path.matches(regex)) {
                                if (LOGGER.isDebugEnabled()) {
                                    LOGGER.debug("Permissions found by matching " + regex + " for " + role + " in "
                                            + site);
                                }
                                List<Node> permissionNodes = ruleNode
                                        .selectNodes(CStudioXmlConstants.DOCUMENT_ELM_ALLOWED_PERMISSIONS);
                                for (Node permissionNode : permissionNodes) {
                                    String permission = permissionNode.getText().toLowerCase();
                                    if (LOGGER.isDebugEnabled()) {
                                        LOGGER.debug("adding permissions " + permission + " to " + path + " for "
                                                + role + " in " + site);
                                    }
                                    permissions.add(permission);
                                }
                            }
                        }
                    } else {
                        if (LOGGER.isDebugEnabled()) {
                            LOGGER.debug("No default role is set. adding default permission: "
                                    + CStudioConstants.PERMISSION_VALUE_READ);
                        }
                        // If no default role is set
                        permissions.add(CStudioConstants.PERMISSION_VALUE_READ);
                    }
                } else {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("No default site is set. adding default permission: "
                                + CStudioConstants.PERMISSION_VALUE_READ);
                    }
                    // If no default site is set
                    permissions.add(CStudioConstants.PERMISSION_VALUE_READ);
                }
            }
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("No user or group matching found. adding default permission: "
                        + CStudioConstants.PERMISSION_VALUE_READ);
            }
            // If user or group did not match the roles-mapping file
            permissions.add(CStudioConstants.PERMISSION_VALUE_READ);
        }
        return permissions;
    }

    /*
     * Responsible for refreshing the PermissionConfigTO objects that contain
     * the mappings (non-Javadoc)
     * 
     * @see
     * org.craftercms.crafter.alfresco.service.impl.ConfigurableServiceBase#
     * loadConfiguration(java.lang.String)
     */
    @Override
    protected void loadConfiguration(String key) {

        NodeRef configRef = getConfigRef(key);
        PersistenceManagerService persistenceManagerService = getService(PersistenceManagerService.class);
        Document document = persistenceManagerService.loadXml(configRef);
        if (document != null) {
            PermissionsConfigTO config = new PermissionsConfigTO();
            config.setMapping(document);
            Element root = document.getRootElement();

            // roles file
            loadRoles(root, config);

            // permissions file
            loadPermissions(root, config);

            config.setKey(key);
            config.setLastUpdated(new Date());

            _permissionsConfigMap.put(key, config);
        } else {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("Permission mapping not found for " + key);
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected void loadRoles(Element root, PermissionsConfigTO config) {
        if (root.getName().equals(CStudioXmlConstants.DOCUMENT_ROLE_MAPPINGS)) {
            Map<String, List<String>> rolesMap = new FastMap<String, List<String>>();

            List<Node> userNodes = root.selectNodes(CStudioXmlConstants.DOCUMENT_ELM_USER_NODE);
            rolesMap = getRoles(userNodes, rolesMap);

            List<Node> groupNodes = root.selectNodes(CStudioXmlConstants.DOCUMENT_ELM_GROUPS_NODE);
            rolesMap = getRoles(groupNodes, rolesMap);

            config.setRoles(rolesMap);
        }
    }

    @SuppressWarnings("unchecked")
    protected Map<String, List<String>> getRoles(List<Node> nodes, Map<String, List<String>> rolesMap) {
        for (Node node : nodes) {
            String name = node.valueOf(CStudioXmlConstants.DOCUMENT_ATTR_PERMISSIONS_NAME);
            if (!StringUtils.isEmpty(name)) {
                List<Node> roleNodes = node.selectNodes(CStudioXmlConstants.DOCUMENT_ELM_PERMISSION_ROLE);
                List<String> roles = new FastList<String>();
                for (Node roleNode : roleNodes) {
                    roles.add(roleNode.getText());
                }
                rolesMap.put(name, roles);
            }
        }
        return rolesMap;
    }

    @SuppressWarnings("unchecked")
    protected void loadPermissions(Element root, PermissionsConfigTO config) {
        if (root.getName().equals(CStudioXmlConstants.DOCUMENT_PERMISSIONS)) {
            Map<String, Map<String, List<Node>>> permissionsMap = new FastMap<String, Map<String, List<Node>>>();
            List<Node> siteNodes = root.selectNodes(CStudioXmlConstants.DOCUMENT_ELM_SITE);
            for (Node siteNode : siteNodes) {
                String siteId = siteNode.valueOf(CStudioXmlConstants.DOCUMENT_ATTR_SITE_ID);
                if (!StringUtils.isEmpty(siteId)) {
                    List<Node> roleNodes = siteNode.selectNodes(CStudioXmlConstants.DOCUMENT_ELM_PERMISSION_ROLE);
                    Map<String, List<Node>> rules = new FastMap<String, List<Node>>();
                    for (Node roleNode : roleNodes) {
                        String roleName = roleNode.valueOf(CStudioXmlConstants.DOCUMENT_ATTR_PERMISSIONS_NAME);
                        List<Node> ruleNodes = roleNode
                                .selectNodes(CStudioXmlConstants.DOCUMENT_ELM_PERMISSION_RULE);
                        rules.put(roleName, ruleNodes);
                    }
                    permissionsMap.put(siteId, rules);
                }
            }
            config.setPermissions(permissionsMap);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.craftercms.crafter.alfresco.service.impl.ConfigurableServiceBase#
     * getConfiguration(java.lang.String)
     */
    @Override
    protected TimeStamped getConfiguration(String key) {

        return _permissionsConfigMap.get(key);
    }

    @Override
    protected void removeConfiguration(String key) {
        if (!StringUtils.isEmpty(key)) {
            _permissionsConfigMap.remove(key);
        }
    }

    /*
      * (non-Javadoc)
      *
      * @see
      * org.craftercms.crafter.alfresco.service.impl.ConfigurableServiceBase#
      * getConfigRef(java.lang.String)
      */
    @Override
    protected NodeRef getConfigRef(String key) {
        String siteConfigPath = _configPath.replaceFirst(CStudioConstants.PATTERN_SITE, getSiteFromKey(key));
        PersistenceManagerService persistenceManagerService = getService(PersistenceManagerService.class);
        return persistenceManagerService.getNodeRef(siteConfigPath + "/" + getFilenameFromKey(key));
    }

    /*
     * Checks for updates to both the role & permission mappings files
     * (non-Javadoc)
     * 
     * @see
     * org.craftercms.crafter.alfresco.service.impl.ConfigurableServiceBase#
     * checkForUpdate(java.lang.String)
     */
    @Override
    protected void checkForUpdate(String site) {
        super.checkForUpdate(getPermissionsKey(site, _roleMappingsFileName));
        super.checkForUpdate(getPermissionsKey(site, _permissionsFileName));
    }

    /* Derives the site from the key */
    protected String getSiteFromKey(String key) {
        return key.substring(0, key.indexOf(File.pathSeparator));
    }

    /* Derives the filename from the key */
    protected String getFilenameFromKey(String key) {
        return key.substring(key.indexOf(File.pathSeparator) + 1);
    }

    /* Derives a key based off the site and filename */
    protected String getPermissionsKey(String site, String filename) {
        return new StringBuffer(site).append(File.pathSeparator).append(filename).toString();
    }

    public void setRoleMappingsFileName(String roleMappingsFileName) {
        this._roleMappingsFileName = roleMappingsFileName;
    }

    public void setPermissionsFileName(String permissionsFileName) {
        this._permissionsFileName = permissionsFileName;
    }
}