001package org.apache.fulcrum.security.model.turbine;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.HashMap;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.avalon.framework.logger.Logger;
027import org.apache.fulcrum.security.GroupManager;
028import org.apache.fulcrum.security.RoleManager;
029import org.apache.fulcrum.security.entity.Group;
030import org.apache.fulcrum.security.entity.Permission;
031import org.apache.fulcrum.security.entity.Role;
032import org.apache.fulcrum.security.model.turbine.entity.TurbineRole;
033import org.apache.fulcrum.security.model.turbine.entity.TurbineUserGroupRole;
034import org.apache.fulcrum.security.util.FulcrumSecurityException;
035import org.apache.fulcrum.security.util.GroupSet;
036import org.apache.fulcrum.security.util.PermissionSet;
037import org.apache.fulcrum.security.util.RoleSet;
038
039/**
040 * This is a control class that makes it easy to find out if a
041 * particular User has a given Permission.  It also determines if a
042 * User has a a particular Role.
043 *
044 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
045 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
046 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a>
047 * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
048 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
049 * @author <a href="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
050 * @version $Id: TurbineAccessControlList.java 1096130 2019-03-25 10:37:19Z painter $
051 */
052@SuppressWarnings("rawtypes")
053public class TurbineAccessControlListImpl
054        implements TurbineAccessControlList
055{
056    /** Serial version */
057        private static final long serialVersionUID = 2678947159949477950L;
058
059    /** The sets of roles that the user has in different groups */
060    private Map<Group, RoleSet> roleSets;
061    
062    /** The sets of permissions that the user has in different groups */
063    private Map<Group, PermissionSet> permissionSets;
064    
065    /** The global group */
066    private Group globalGroup;
067    
068    /** The group manager */
069    private GroupManager groupManager;
070    
071    /** The distinct list of groups that this user is part of */
072    private GroupSet groupSet = new GroupSet();
073    
074    /** The distinct list of roles that this user is part of */
075    private RoleSet roleSet = new RoleSet();
076    
077    /** the distinct list of permissions that this user has */
078    private PermissionSet permissionSet = new PermissionSet();
079    
080    /** the Avalon logger */
081    private transient Logger logger;
082
083    /**
084     * Constructs a new AccessControlList.
085     *
086     * This class follows 'immutable' pattern - it's objects can't be modified
087     * once they are created. This means that the permissions the users have are
088     * in effect form the moment they log in to the moment they log out, and
089     * changes made to the security settings in that time are not reflected
090     * in the state of this object. If you need to reset an user's permissions
091     * you need to invalidate his session. <br>
092     *
093     * @param turbineUserGroupRoleSet
094     *            The set of user/group/role relations that this acl is built from
095     * @param groupManager the Group manager
096     * @param roleManager the Role manager
097     * @param modelManager the model Manager
098     * @param logger 
099     *
100     * @throws FulcrumSecurityException if the global group cannot be retrieved
101     */
102    public TurbineAccessControlListImpl(
103                Set<? extends TurbineUserGroupRole> turbineUserGroupRoleSet,
104                GroupManager groupManager, RoleManager roleManager, TurbineModelManager modelManager, Logger logger) throws FulcrumSecurityException
105    {
106        this.roleSets = new HashMap<Group, RoleSet>();
107        this.permissionSets = new HashMap<Group, PermissionSet>();
108        this.groupManager = groupManager;
109        
110        this.logger = logger;
111
112        for (TurbineUserGroupRole ugr : turbineUserGroupRoleSet)
113        {
114            Group group = ugr.getGroup();
115            // check if group matches
116            if (this.logger != null && this.groupManager != null && group.getClass() != this.groupManager.getGroupInstance().getClass()) {
117                this.logger.warn( "Turbine group classes do not match, some lookup might fail, check in componentConfiguration.xml. Expected class: " +
118                        this.groupManager.getGroupInstance().getClass() + ", actual class: " +group.getClass()
119            );
120            }
121            groupSet.add(group);
122
123            Role role = ugr.getRole();
124            if (!roleSet.containsId(role.getId()))
125            {
126                // get fresh reference from role manager to make sure the related
127                // permissions are populated
128                if (roleManager != null)
129                {
130                    role = roleManager.getRoleById(role.getId());
131                }
132                roleSet.add(role);
133            }
134            else
135            {
136                role = roleSet.getById(role.getId());
137            }
138            if (roleSets.containsKey(group))
139            {
140                roleSets.get(group).add(role);
141            }
142            else
143            {
144                RoleSet rs = new RoleSet();
145                rs.add(role);
146                roleSets.put(group, rs);
147            }
148            // if required, otherwise skip
149            if (role instanceof TurbineRole) {
150                    PermissionSet ps = ((TurbineRole) role).getPermissions();
151                    permissionSet.add(ps);
152                    if (permissionSets.containsKey(group))
153                    {
154                        permissionSets.get(group).add(ps);
155                    }
156                    else
157                    {
158                        permissionSets.put(group, ps);
159                    }
160            }
161        }
162        // this check might be not needed any more, required for custom group
163        if (modelManager != null)
164        {
165                this.globalGroup = modelManager.getGlobalGroup();
166        }
167    }
168
169    /**
170     * Retrieves a set of Roles an user is assigned in a Group.
171     *
172     * @param group the Group
173     * @return the set of Roles this user has within the Group.
174     */
175    @Override
176    public RoleSet getRoles(Group group)
177    {
178        if (group == null)
179        {
180            return null;
181        }
182        return roleSets.get(group);
183    }
184
185    /**
186     * Retrieves a set of Roles an user is assigned in the global Group.
187     *
188     * @return the set of Roles this user has within the global Group or null.
189     */
190    @Override
191    public RoleSet getRoles()
192    {
193        return getRoles(globalGroup);
194    }
195
196    /**
197     * Retrieves a set of Permissions an user is assigned in a Group.
198     *
199     * @param group the Group
200     * @return the set of Permissions this user has within the Group.
201     */
202    @Override
203    public PermissionSet getPermissions(Group group)
204    {
205        if (group == null)
206        {
207            return null;
208        }
209        return permissionSets.get(group);
210    }
211
212    /**
213     * Retrieves a set of Permissions an user is assigned in the global Group.
214     *
215     * @return the set of Permissions this user has within the global Group.
216     */
217    @Override
218    public PermissionSet getPermissions()
219    {
220        return getPermissions(globalGroup);
221    }
222
223    /**
224     * Checks if the user is assigned a specific Role in the Group.
225     *
226     * @param role the Role
227     * @param group the Group
228     * @return <code>true</code> if the user is assigned the Role in the Group.
229     */
230    @Override
231    public boolean hasRole(Role role, Group group)
232    {
233        RoleSet set = getRoles(group);
234        if (set == null || role == null)
235        {
236            return false;
237        }
238        return set.contains(role);
239    }
240
241    /**
242     * Checks if the user is assigned a specific Role in any of the given
243     * Groups
244     *
245     * @param role the Role
246     * @param groupset a Groupset
247     * @return <code>true</code> if the user is assigned the Role in any of
248     *         the given Groups.
249     */
250    @Override
251    public boolean hasRole(Role role, GroupSet groupset)
252    {
253        if (role == null)
254        {
255            return false;
256        }
257
258        for (Group group : groupset)
259        {
260            RoleSet roles = getRoles(group);
261            if (roles != null && roles.contains(role))
262            {
263                return true;
264            }
265        }
266
267        return false;
268    }
269
270    /**
271     * Checks if the user is assigned a specific Role in the Group.
272     *
273     * @param roleName the Role name
274     * @param groupName the Group name
275     * @return <code>true</code> if the user is assigned the Role in the Group.
276     */
277    @Override
278    public boolean hasRole(String roleName, String groupName)
279    {
280        try
281        {
282                return hasRole(roleSet.getByName(roleName), groupSet.getByName(groupName));
283        }
284        catch (Exception e)
285        {
286            return false;
287        }
288    }
289
290    /**
291     * Checks if the user is assigned a specific Role in any of the given
292     * Groups
293     *
294     * @param rolename the name of the Role
295     * @param groupset a Groupset
296     * @return <code>true</code> if the user is assigned the Role in any of
297     *         the given Groups.
298     */
299    @Override
300    public boolean hasRole(String rolename, GroupSet groupset)
301    {
302        try
303        {
304                return hasRole(roleSet.getByName(rolename), groupset);
305        }
306        catch (Exception e)
307        {
308            return false;
309        }
310    }
311
312    /**
313     * Checks if the user is assigned a specific Role in the global Group.
314     *
315     * @param role the Role
316     * @return <code>true</code> if the user is assigned the Role in the global Group.
317     */
318    @Override
319    public boolean hasRole(Role role)
320    {
321        return hasRole(role, globalGroup);
322    }
323
324    /**
325     * Checks if the user is assigned a specific Role in the global Group.
326     *
327     * @param role the Role
328     * @return <code>true</code> if the user is assigned the Role in the global Group.
329     */
330    @Override
331    public boolean hasRole(String role)
332    {
333        try
334        {
335            return hasRole(roleSet.getByName(role));
336        }
337        catch (Exception e)
338        {
339            return false;
340        }
341    }
342
343    /**
344     * Checks if the user is assigned a specific Permission in the Group.
345     *
346     * @param permission the Permission
347     * @param group the Group
348     * @return <code>true</code> if the user is assigned the Permission in the Group.
349     */
350    @Override
351    public boolean hasPermission(Permission permission, Group group)
352    {
353        PermissionSet set = getPermissions(group);
354        if (set == null || permission == null)
355        {
356            return false;
357        }
358        return set.contains(permission);
359    }
360
361    /**
362     * Checks if the user is assigned a specific Permission in any of the given
363     * Groups
364     *
365     * @param permission the Permission
366     * @param groupset a Groupset
367     * @return <code>true</code> if the user is assigned the Permission in any
368     *         of the given Groups.
369     */
370    @Override
371    public boolean hasPermission(Permission permission, GroupSet groupset)
372    {
373        if (permission == null)
374        {
375            return false;
376        }
377
378        for (Group group : groupset)
379        {
380            PermissionSet permissions = getPermissions(group);
381            if (permissions != null && permissions.contains(permission))
382            {
383                return true;
384            }
385        }
386
387        return false;
388    }
389
390    /**
391     * Checks if the user is assigned a specific Permission in the Group.
392     *
393     * @param permission the Permission
394     * @param group the Group
395     * @return <code>true</code> if the user is assigned the Permission in the Group.
396     */
397    @Override
398    public boolean hasPermission(String permission, String group)
399    {
400        try
401        {
402            return hasPermission(permissionSet.getByName(permission), groupSet.getByName(group));
403        }
404        catch (Exception e)
405        {
406            return false;
407        }
408    }
409
410    /**
411     * Checks if the user is assigned a specific Permission in the Group.
412     *
413     * @param permission the Permission
414     * @param group the Group
415     * @return <code>true</code> if the user is assigned the Permission in the Group.
416     */
417    @Override
418    public boolean hasPermission(String permission, Group group)
419    {
420        try
421        {
422            return hasPermission(permissionSet.getByName(permission), group);
423        }
424        catch (Exception e)
425        {
426            return false;
427        }
428    }
429
430    /**
431     * Checks if the user is assigned a specific Permission in any of the given
432     * Groups
433     *
434     * @param permissionName the name of the Permission
435     * @param groupset a Groupset
436     * @return <code>true</code> if the user is assigned the Permission in any
437     *         of the given Groups.
438     */
439    @Override
440    public boolean hasPermission(String permissionName, GroupSet groupset)
441    {
442        Permission permission;
443        try
444        {
445            permission = permissionSet.getByName(permissionName);
446        }
447        catch (Exception e)
448        {
449            return false;
450        }
451        
452        if (permission == null)
453        {
454            return false;
455        }
456        
457        for (Group group : groupset)
458        {
459            PermissionSet permissions = getPermissions(group);
460            if (permissions != null && permissions.contains(permission))
461            {
462                return true;
463            }
464        }
465        return false;
466    }
467
468    /**
469     * Checks if the user is assigned a specific Permission in the global Group.
470     *
471     * @param permission the Permission
472     * @return <code>true</code> if the user is assigned the Permission in the global Group.
473     */
474    @Override
475    public boolean hasPermission(Permission permission)
476    {
477        return hasPermission(permission, globalGroup);
478    }
479
480    /**
481     * Checks if the user is assigned a specific Permission in the global Group.
482     *
483     * @param permission the Permission
484     * @return <code>true</code> if the user is assigned the Permission in the global Group.
485     */
486    @Override
487    public boolean hasPermission(String permission)
488    {
489        try
490        {
491            return hasPermission(permissionSet.getByName(permission));
492        }
493        catch (Exception e)
494        {
495            return false;
496        }
497    }
498
499    /**
500     * Returns all groups defined in the system.
501     *
502     * This is useful for debugging, when you want to display all roles
503     * and permissions an user is assigned. This method is needed
504     * because you can't call static methods of TurbineSecurity class
505     * from within WebMacro/Velocity template
506     *
507     * @return A Group [] of all groups in the system.
508     */
509    @Override
510    public Group[] getAllGroups()
511    {
512        try
513        {
514            return (groupManager != null)? groupManager.getAllGroups().toArray(new Group[0])
515                    : new Group[0];
516        }
517        catch (FulcrumSecurityException e)
518        {
519            return new Group[0];
520        }
521    }
522
523    @Override
524    public GroupSet getGroupSet()
525    {
526        return groupSet;
527    }
528}