TurbineAccessControlListImpl.java

package org.apache.fulcrum.security.model.turbine;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.avalon.framework.logger.Logger;
import org.apache.fulcrum.security.GroupManager;
import org.apache.fulcrum.security.RoleManager;
import org.apache.fulcrum.security.entity.Group;
import org.apache.fulcrum.security.entity.Permission;
import org.apache.fulcrum.security.entity.Role;
import org.apache.fulcrum.security.model.turbine.entity.TurbineRole;
import org.apache.fulcrum.security.model.turbine.entity.TurbineUserGroupRole;
import org.apache.fulcrum.security.util.FulcrumSecurityException;
import org.apache.fulcrum.security.util.GroupSet;
import org.apache.fulcrum.security.util.PermissionSet;
import org.apache.fulcrum.security.util.RoleSet;

/**
 * This is a control class that makes it easy to find out if a
 * particular User has a given Permission.  It also determines if a
 * User has a a particular Role.
 *
 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a>
 * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 * @author <a href="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
 * @version $Id: TurbineAccessControlList.java 1096130 2019-03-25 10:37:19Z painter $
 */
@SuppressWarnings("rawtypes")
public class TurbineAccessControlListImpl
        implements TurbineAccessControlList
{
    /** Serial version */
	private static final long serialVersionUID = 2678947159949477950L;

    /** The sets of roles that the user has in different groups */
    private Map<Group, RoleSet> roleSets;
    
    /** The sets of permissions that the user has in different groups */
    private Map<Group, PermissionSet> permissionSets;
    
    /** The global group */
    private Group globalGroup;
    
    /** The group manager */
    private GroupManager groupManager;
    
    /** The distinct list of groups that this user is part of */
    private GroupSet groupSet = new GroupSet();
    
    /** The distinct list of roles that this user is part of */
    private RoleSet roleSet = new RoleSet();
    
    /** the distinct list of permissions that this user has */
    private PermissionSet permissionSet = new PermissionSet();
    
    /** the Avalon logger */
    private transient Logger logger;

    /**
     * Constructs a new AccessControlList.
     *
     * This class follows 'immutable' pattern - it's objects can't be modified
     * once they are created. This means that the permissions the users have are
     * in effect form the moment they log in to the moment they log out, and
     * changes made to the security settings in that time are not reflected
     * in the state of this object. If you need to reset an user's permissions
     * you need to invalidate his session. <br>
     *
     * @param turbineUserGroupRoleSet
     *            The set of user/group/role relations that this acl is built from
     * @param groupManager the Group manager
     * @param roleManager the Role manager
     * @param modelManager the model Manager
     * @param logger 
     *
     * @throws FulcrumSecurityException if the global group cannot be retrieved
     */
    public TurbineAccessControlListImpl(
    		Set<? extends TurbineUserGroupRole> turbineUserGroupRoleSet,
    		GroupManager groupManager, RoleManager roleManager, TurbineModelManager modelManager, Logger logger) throws FulcrumSecurityException
    {
        this.roleSets = new HashMap<Group, RoleSet>();
        this.permissionSets = new HashMap<Group, PermissionSet>();
        this.groupManager = groupManager;
        
        this.logger = logger;

        for (TurbineUserGroupRole ugr : turbineUserGroupRoleSet)
        {
            Group group = ugr.getGroup();
            // check if group matches
            if (this.logger != null && this.groupManager != null && group.getClass() != this.groupManager.getGroupInstance().getClass()) {
                this.logger.warn( "Turbine group classes do not match, some lookup might fail, check in componentConfiguration.xml. Expected class: " +
                        this.groupManager.getGroupInstance().getClass() + ", actual class: " +group.getClass()
            );
            }
            groupSet.add(group);

            Role role = ugr.getRole();
            if (!roleSet.containsId(role.getId()))
            {
                // get fresh reference from role manager to make sure the related
                // permissions are populated
                if (roleManager != null)
                {
                    role = roleManager.getRoleById(role.getId());
                }
                roleSet.add(role);
            }
            else
            {
                role = roleSet.getById(role.getId());
            }
            if (roleSets.containsKey(group))
            {
            	roleSets.get(group).add(role);
            }
            else
            {
            	RoleSet rs = new RoleSet();
            	rs.add(role);
            	roleSets.put(group, rs);
            }
            // if required, otherwise skip
            if (role instanceof TurbineRole) {
	            PermissionSet ps = ((TurbineRole) role).getPermissions();
	            permissionSet.add(ps);
	            if (permissionSets.containsKey(group))
	            {
	            	permissionSets.get(group).add(ps);
	            }
	            else
	            {
	            	permissionSets.put(group, ps);
	            }
            }
        }
        // this check might be not needed any more, required for custom group
        if (modelManager != null)
        {
        	this.globalGroup = modelManager.getGlobalGroup();
        }
    }

    /**
     * Retrieves a set of Roles an user is assigned in a Group.
     *
     * @param group the Group
     * @return the set of Roles this user has within the Group.
     */
    @Override
    public RoleSet getRoles(Group group)
    {
        if (group == null)
        {
            return null;
        }
        return roleSets.get(group);
    }

    /**
     * Retrieves a set of Roles an user is assigned in the global Group.
     *
     * @return the set of Roles this user has within the global Group or null.
     */
    @Override
    public RoleSet getRoles()
    {
        return getRoles(globalGroup);
    }

    /**
     * Retrieves a set of Permissions an user is assigned in a Group.
     *
     * @param group the Group
     * @return the set of Permissions this user has within the Group.
     */
    @Override
    public PermissionSet getPermissions(Group group)
    {
        if (group == null)
        {
            return null;
        }
        return permissionSets.get(group);
    }

    /**
     * Retrieves a set of Permissions an user is assigned in the global Group.
     *
     * @return the set of Permissions this user has within the global Group.
     */
    @Override
    public PermissionSet getPermissions()
    {
        return getPermissions(globalGroup);
    }

    /**
     * Checks if the user is assigned a specific Role in the Group.
     *
     * @param role the Role
     * @param group the Group
     * @return <code>true</code> if the user is assigned the Role in the Group.
     */
    @Override
    public boolean hasRole(Role role, Group group)
    {
        RoleSet set = getRoles(group);
        if (set == null || role == null)
        {
            return false;
        }
        return set.contains(role);
    }

    /**
     * Checks if the user is assigned a specific Role in any of the given
     * Groups
     *
     * @param role the Role
     * @param groupset a Groupset
     * @return <code>true</code> if the user is assigned the Role in any of
     *         the given Groups.
     */
    @Override
    public boolean hasRole(Role role, GroupSet groupset)
    {
        if (role == null)
        {
            return false;
        }

        for (Group group : groupset)
        {
            RoleSet roles = getRoles(group);
            if (roles != null && roles.contains(role))
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Checks if the user is assigned a specific Role in the Group.
     *
     * @param roleName the Role name
     * @param groupName the Group name
     * @return <code>true</code> if the user is assigned the Role in the Group.
     */
    @Override
    public boolean hasRole(String roleName, String groupName)
    {
        try
        {
        	return hasRole(roleSet.getByName(roleName), groupSet.getByName(groupName));
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Checks if the user is assigned a specific Role in any of the given
     * Groups
     *
     * @param rolename the name of the Role
     * @param groupset a Groupset
     * @return <code>true</code> if the user is assigned the Role in any of
     *         the given Groups.
     */
    @Override
    public boolean hasRole(String rolename, GroupSet groupset)
    {
        try
        {
        	return hasRole(roleSet.getByName(rolename), groupset);
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Checks if the user is assigned a specific Role in the global Group.
     *
     * @param role the Role
     * @return <code>true</code> if the user is assigned the Role in the global Group.
     */
    @Override
    public boolean hasRole(Role role)
    {
        return hasRole(role, globalGroup);
    }

    /**
     * Checks if the user is assigned a specific Role in the global Group.
     *
     * @param role the Role
     * @return <code>true</code> if the user is assigned the Role in the global Group.
     */
    @Override
    public boolean hasRole(String role)
    {
        try
        {
            return hasRole(roleSet.getByName(role));
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Checks if the user is assigned a specific Permission in the Group.
     *
     * @param permission the Permission
     * @param group the Group
     * @return <code>true</code> if the user is assigned the Permission in the Group.
     */
    @Override
    public boolean hasPermission(Permission permission, Group group)
    {
        PermissionSet set = getPermissions(group);
        if (set == null || permission == null)
        {
            return false;
        }
        return set.contains(permission);
    }

    /**
     * Checks if the user is assigned a specific Permission in any of the given
     * Groups
     *
     * @param permission the Permission
     * @param groupset a Groupset
     * @return <code>true</code> if the user is assigned the Permission in any
     *         of the given Groups.
     */
    @Override
    public boolean hasPermission(Permission permission, GroupSet groupset)
    {
        if (permission == null)
        {
            return false;
        }

        for (Group group : groupset)
        {
            PermissionSet permissions = getPermissions(group);
            if (permissions != null && permissions.contains(permission))
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Checks if the user is assigned a specific Permission in the Group.
     *
     * @param permission the Permission
     * @param group the Group
     * @return <code>true</code> if the user is assigned the Permission in the Group.
     */
    @Override
    public boolean hasPermission(String permission, String group)
    {
        try
        {
            return hasPermission(permissionSet.getByName(permission), groupSet.getByName(group));
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Checks if the user is assigned a specific Permission in the Group.
     *
     * @param permission the Permission
     * @param group the Group
     * @return <code>true</code> if the user is assigned the Permission in the Group.
     */
    @Override
    public boolean hasPermission(String permission, Group group)
    {
        try
        {
            return hasPermission(permissionSet.getByName(permission), group);
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Checks if the user is assigned a specific Permission in any of the given
     * Groups
     *
     * @param permissionName the name of the Permission
     * @param groupset a Groupset
     * @return <code>true</code> if the user is assigned the Permission in any
     *         of the given Groups.
     */
    @Override
    public boolean hasPermission(String permissionName, GroupSet groupset)
    {
        Permission permission;
        try
        {
            permission = permissionSet.getByName(permissionName);
        }
        catch (Exception e)
        {
            return false;
        }
        
        if (permission == null)
        {
            return false;
        }
        
        for (Group group : groupset)
        {
            PermissionSet permissions = getPermissions(group);
            if (permissions != null && permissions.contains(permission))
            {
            	return true;
            }
        }
        return false;
    }

    /**
     * Checks if the user is assigned a specific Permission in the global Group.
     *
     * @param permission the Permission
     * @return <code>true</code> if the user is assigned the Permission in the global Group.
     */
    @Override
    public boolean hasPermission(Permission permission)
    {
        return hasPermission(permission, globalGroup);
    }

    /**
     * Checks if the user is assigned a specific Permission in the global Group.
     *
     * @param permission the Permission
     * @return <code>true</code> if the user is assigned the Permission in the global Group.
     */
    @Override
    public boolean hasPermission(String permission)
    {
        try
        {
            return hasPermission(permissionSet.getByName(permission));
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Returns all groups defined in the system.
     *
     * This is useful for debugging, when you want to display all roles
     * and permissions an user is assigned. This method is needed
     * because you can't call static methods of TurbineSecurity class
     * from within WebMacro/Velocity template
     *
     * @return A Group [] of all groups in the system.
     */
    @Override
    public Group[] getAllGroups()
    {
        try
        {
            return (groupManager != null)? groupManager.getAllGroups().toArray(new Group[0])
                    : new Group[0];
        }
        catch (FulcrumSecurityException e)
        {
            return new Group[0];
        }
    }

    @Override
    public GroupSet getGroupSet()
    {
        return groupSet;
    }
}