001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 * 
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.security;
029
030import org.opencms.db.CmsSecurityManager;
031import org.opencms.file.CmsGroup;
032import org.opencms.file.CmsObject;
033import org.opencms.file.CmsResource;
034import org.opencms.file.CmsResourceFilter;
035import org.opencms.file.CmsUser;
036import org.opencms.main.CmsException;
037import org.opencms.main.OpenCms;
038
039import java.util.ArrayList;
040import java.util.Iterator;
041import java.util.List;
042import java.util.Set;
043
044import com.google.common.collect.Lists;
045
046/**
047 * This manager provide access to the role related operations.<p>
048 * 
049 * @since 6.5.6
050 */
051public class CmsRoleManager {
052
053    /** The security manager. */
054    private final CmsSecurityManager m_securityManager;
055
056    /**
057     * Returns the groups which constitute a given role, i.e. the set of groups such that a member of any of them
058     * has the given role.<p>
059     * 
060     * @param cms the CMS context 
061     * @param role the role 
062     * @param directUsersOnly if true, only the role's direct group will be returned
063     *  
064     * @return the groups constituting the given role
065     * 
066     * @throws CmsException if something goes wrong  
067     */
068    public Set<CmsGroup> getRoleGroups(CmsObject cms, CmsRole role, boolean directUsersOnly) throws CmsException {
069
070        return m_securityManager.getRoleGroups(cms.getRequestContext(), role, directUsersOnly);
071    }
072
073    /**
074     * Default constructor.<p>
075     * 
076     * @param securityManager the security manager
077     */
078    public CmsRoleManager(CmsSecurityManager securityManager) {
079
080        m_securityManager = securityManager;
081    }
082
083    /**
084     * Adds a user to the given role.<p>
085     * 
086     * @param cms the opencms context
087     * @param role the role
088     * @param username the name of the user that is to be added to the role
089     * 
090     * @throws CmsException if something goes wrong
091     */
092    public void addUserToRole(CmsObject cms, CmsRole role, String username) throws CmsException {
093
094        m_securityManager.addUserToGroup(cms.getRequestContext(), username, role.getGroupName(), true);
095    }
096
097    /**
098     * Checks if the user of this OpenCms context is a member of the given role
099     * for the given organizational unit.<p>
100     * 
101     * The user must have the given role in at least one parent organizational unit.<p>
102     * 
103     * @param cms the opencms context
104     * @param role the role to check
105     * 
106     * @throws CmsRoleViolationException if the user does not have the required role permissions
107     */
108    public void checkRole(CmsObject cms, CmsRole role) throws CmsRoleViolationException {
109
110        m_securityManager.checkRole(cms.getRequestContext(), role);
111    }
112
113    /**
114     * Checks if the user of this OpenCms context is a member of the given role
115     * for the given resource.<p>
116     * 
117     * The user must have the given role in at least one organizational unit to which this resource belongs.<p>
118     * 
119     * @param cms the opencms context
120     * @param role the role to check
121     * @param resourceName the name of the resource to check the role for
122     * 
123     * @throws CmsRoleViolationException if the user does not have the required role permissions
124     * @throws CmsException if something goes wrong, while reading the resource
125     */
126    public void checkRoleForResource(CmsObject cms, CmsRole role, String resourceName)
127    throws CmsException, CmsRoleViolationException {
128
129        CmsResource resource = cms.readResource(resourceName);
130        m_securityManager.checkRoleForResource(cms.getRequestContext(), role, resource);
131    }
132
133    /**
134     * Returns all groups of organizational units for which the current user 
135     * has the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
136     * 
137     * @param cms the current cms context
138     * @param ouFqn the fully qualified name of the organizational unit
139     * @param includeSubOus if sub organizational units should be included in the search 
140     *  
141     * @return a list of {@link org.opencms.file.CmsGroup} objects
142     * 
143     * @throws CmsException if something goes wrong
144     */
145    public List<CmsGroup> getManageableGroups(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
146
147        List<CmsGroup> groups = new ArrayList<CmsGroup>();
148        Iterator<CmsOrganizationalUnit> it = getOrgUnitsForRole(
149            cms,
150            CmsRole.ACCOUNT_MANAGER.forOrgUnit(ouFqn),
151            includeSubOus).iterator();
152        while (it.hasNext()) {
153            CmsOrganizationalUnit orgUnit = it.next();
154            groups.addAll(OpenCms.getOrgUnitManager().getGroups(cms, orgUnit.getName(), false));
155        }
156        return groups;
157    }
158
159    /**
160     * Returns all resources of organizational units for which the current user has 
161     * the given role role.<p>
162     * 
163     * @param cms the current cms context
164     * @param role the role to check
165     *  
166     * @return a list of {@link org.opencms.file.CmsResource} objects
167     * 
168     * @throws CmsException if something goes wrong
169     */
170    public List<CmsResource> getManageableResources(CmsObject cms, CmsRole role) throws CmsException {
171
172        return m_securityManager.getManageableResources(cms.getRequestContext(), role);
173    }
174
175    /**
176     * Returns all users of organizational units for which the current user has 
177     * the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
178     * 
179     * @param cms the current cms context
180     * @param ouFqn the fully qualified name of the organizational unit
181     * @param includeSubOus if sub organizational units should be included in the search 
182     *  
183     * @return a list of {@link org.opencms.file.CmsUser} objects
184     * 
185     * @throws CmsException if something goes wrong
186     */
187    public List<CmsUser> getManageableUsers(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
188
189        return getManageableUsers(cms, ouFqn, includeSubOus, false);
190    }
191
192    /**
193     * Returns all users of organizational units for which the current user has 
194     * the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
195     * 
196     * @param cms the current cms context
197     * @param ouFqn the fully qualified name of the organizational unit
198     * @param includeSubOus if sub organizational units should be included in the search
199     * @param includeWebusers if webuser organizational units should be included in the search
200     *  
201     * @return a list of {@link org.opencms.file.CmsUser} objects
202     * 
203     * @throws CmsException if something goes wrong
204     */
205    public List<CmsUser> getManageableUsers(CmsObject cms, String ouFqn, boolean includeSubOus, boolean includeWebusers)
206    throws CmsException {
207
208        List<CmsOrganizationalUnit> ous = getManageableOrgUnits(cms, ouFqn, includeSubOus, includeWebusers);
209        List<CmsUser> users = new ArrayList<CmsUser>();
210        Iterator<CmsOrganizationalUnit> it = ous.iterator();
211        while (it.hasNext()) {
212            CmsOrganizationalUnit orgUnit = it.next();
213            users.addAll(OpenCms.getOrgUnitManager().getUsers(cms, orgUnit.getName(), false));
214        }
215        return users;
216    }
217
218    /**
219     * Returns a list of those organizational units whose members can be managed by the current user.<p>
220     * 
221     * @param cms the current CMS context 
222     * @param ouFqn the fully qualified name of the organizational unit 
223     * @param includeSubOus if sub organizational units should be included in the search 
224     * @param includeWebusers if webuser organizational units should be included in the search 
225     * 
226     * @return a list of organizational units 
227     * 
228     * @throws CmsException if something goes wrong 
229     */
230    public List<CmsOrganizationalUnit> getManageableOrgUnits(
231        CmsObject cms,
232        String ouFqn,
233        boolean includeSubOus,
234        boolean includeWebusers) throws CmsException {
235
236        List<CmsOrganizationalUnit> result = Lists.newArrayList();
237        List<CmsOrganizationalUnit> ous = getOrgUnitsForRole(
238            cms,
239            CmsRole.ACCOUNT_MANAGER.forOrgUnit(ouFqn),
240            includeSubOus);
241        for (CmsOrganizationalUnit ou : ous) {
242            if (includeWebusers || !ou.hasFlagWebuser()) {
243                result.add(ou);
244            }
245        }
246        return result;
247    }
248
249    /**
250     * Returns all the organizational units for which the current user has the given role.<p>
251     * 
252     * @param cms the current cms context
253     * @param role the role to check
254     * @param includeSubOus if sub organizational units should be included in the search 
255     *  
256     * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects
257     * 
258     * @throws CmsException if something goes wrong
259     */
260    public List<CmsOrganizationalUnit> getOrgUnitsForRole(CmsObject cms, CmsRole role, boolean includeSubOus)
261    throws CmsException {
262
263        return m_securityManager.getOrgUnitsForRole(cms.getRequestContext(), role, includeSubOus);
264    }
265
266    /**
267     * Returns all roles, in the given organizational unit.<p>
268     *
269     * @param cms the opencms context
270     * @param ouFqn the fully qualified name of the organizational unit of the role
271     * @param includeSubOus include roles of child organizational units
272     * 
273     * @return a list of all <code>{@link CmsRole}</code> objects
274     *
275     * @throws CmsException if operation was not successful
276     */
277    public List<CmsRole> getRoles(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
278
279        CmsOrganizationalUnit ou = OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, ouFqn);
280        List<CmsGroup> groups = m_securityManager.getGroups(cms.getRequestContext(), ou, includeSubOus, true);
281        List<CmsRole> roles = new ArrayList<CmsRole>(groups.size());
282        Iterator<CmsGroup> itGroups = groups.iterator();
283        while (itGroups.hasNext()) {
284            CmsGroup group = itGroups.next();
285            roles.add(CmsRole.valueOf(group));
286        }
287        return roles;
288    }
289
290    /**
291     * Returns all roles the given user has over the given resource.<p>
292     * 
293     * @param cms the current cms context
294     * @param userFqn the user name to check
295     * @param resourceName the resource name
296     * 
297     * @return a list of {@link CmsRole} objects
298     * 
299     * @throws CmsException if something goes wrong
300     */
301    public List<CmsRole> getRolesForResource(CmsObject cms, String userFqn, String resourceName) throws CmsException {
302
303        CmsUser user = cms.readUser(userFqn);
304        CmsResource resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
305        return m_securityManager.getRolesForResource(cms.getRequestContext(), user, resource);
306    }
307
308    /**
309     * Returns all roles the given user belongs to, in the given organizational unit.<p>
310     *
311     * @param cms the opencms context
312     * @param username the name of the user to get all roles for
313     * @param ouFqn the fully qualified name of the organizational unit to restrict the search to
314     * @param includeChildOus include roles of child organizational units
315     * @param directRolesOnly if set only the direct assigned roles will be returned, if not also indirect roles
316     * @param recursive if this is set, also roles of higher organizational unit are considered
317     * 
318     * @return a list of <code>{@link org.opencms.security.CmsRole}</code> objects
319     *
320     * @throws CmsException if operation was not successful
321     */
322    public List<CmsRole> getRolesOfUser(
323        CmsObject cms,
324        String username,
325        String ouFqn,
326        boolean includeChildOus,
327        boolean directRolesOnly,
328        boolean recursive) throws CmsException {
329
330        List<CmsGroup> groups;
331        ouFqn = CmsOrganizationalUnit.removeLeadingSeparator(ouFqn);
332        if (!recursive) {
333            groups = m_securityManager.getGroupsOfUser(
334                cms.getRequestContext(),
335                username,
336                ouFqn,
337                includeChildOus,
338                true,
339                directRolesOnly,
340                cms.getRequestContext().getRemoteAddress());
341        } else {
342            groups = new ArrayList<CmsGroup>();
343            Iterator<CmsGroup> itAllGroups = m_securityManager.getGroupsOfUser(
344                cms.getRequestContext(),
345                username,
346                "",
347                true,
348                true,
349                directRolesOnly,
350                cms.getRequestContext().getRemoteAddress()).iterator();
351            while (itAllGroups.hasNext()) {
352                CmsGroup role = itAllGroups.next();
353                if (!includeChildOus && role.getOuFqn().equals(ouFqn)) {
354                    groups.add(role);
355                }
356                if (includeChildOus && role.getOuFqn().startsWith(ouFqn)) {
357                    groups.add(role);
358                }
359            }
360        }
361        List<CmsRole> roles = new ArrayList<CmsRole>(groups.size());
362        Iterator<CmsGroup> itGroups = groups.iterator();
363        while (itGroups.hasNext()) {
364            CmsGroup group = itGroups.next();
365            roles.add(CmsRole.valueOf(group));
366        }
367        return roles;
368    }
369
370    /**
371     * Returns all direct users of a given role, in the given organizational unit.<p>
372     *
373     * Users that are "indirectly" in the role are not returned in the result.<p>
374     *
375     * @param cms the opencms context
376     * @param role the role to get all users for
377     * @param includeOtherOuUsers include users of other organizational units
378     * @param directUsersOnly if set only the direct assigned users will be returned, 
379     *                          if not also indirect users, ie. members of child groups
380     * 
381     * @return all <code>{@link org.opencms.file.CmsUser}</code> objects in the group
382     *
383     * @throws CmsException if operation was not successful
384     */
385    public List<CmsUser> getUsersOfRole(
386        CmsObject cms,
387        CmsRole role,
388        boolean includeOtherOuUsers,
389        boolean directUsersOnly) throws CmsException {
390
391        return m_securityManager.getUsersOfGroup(
392            cms.getRequestContext(),
393            role.getGroupName(),
394            includeOtherOuUsers,
395            directUsersOnly,
396            true);
397    }
398
399    /**
400     * Checks if the given context user has the given role in the given organizational unit.<p>
401     *  
402     * @param cms the opencms context
403     * @param role the role to check
404     * 
405     * @return <code>true</code> if the given context user has the given role in the given organizational unit
406     */
407    public boolean hasRole(CmsObject cms, CmsRole role) {
408
409        return m_securityManager.hasRole(cms.getRequestContext(), cms.getRequestContext().getCurrentUser(), role);
410    }
411
412    /**
413     * Checks if the given user has the given role in the given organizational unit.<p> 
414     *  
415     * @param cms the opencms context
416     * @param userName the name of the user to check the role for
417     * @param role the role to check
418     * 
419     * @return <code>true</code> if the given user has the given role in the given organizational unit
420     */
421    public boolean hasRole(CmsObject cms, String userName, CmsRole role) {
422
423        CmsUser user;
424        try {
425            user = cms.readUser(userName);
426        } catch (CmsException e) {
427            // ignore
428            return false;
429        }
430        return m_securityManager.hasRole(cms.getRequestContext(), user, role);
431    }
432
433    /**
434     * Checks if the given context user has the given role for the given resource.<p>
435     *  
436     * @param cms the opencms context
437     * @param role the role to check
438     * @param resourceName the name of the resource to check
439     * 
440     * @return <code>true</code> if the given context user has the given role for the given resource
441     */
442    public boolean hasRoleForResource(CmsObject cms, CmsRole role, String resourceName) {
443
444        CmsResource resource;
445        try {
446            resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
447        } catch (CmsException e) {
448            // ignore
449            return false;
450        }
451        return m_securityManager.hasRoleForResource(
452            cms.getRequestContext(),
453            cms.getRequestContext().getCurrentUser(),
454            role,
455            resource);
456    }
457
458    /**
459     * Checks if the given context user has the given role for the given resource.<p>
460     *  
461     * @param cms the opencms context
462     * @param userName the name of the user to check the role for
463     * @param role the role to check
464     * @param resourceName the name of the resource to check
465     * 
466     * @return <code>true</code> if the given context user has the given role for the given resource
467     */
468    public boolean hasRoleForResource(CmsObject cms, String userName, CmsRole role, String resourceName) {
469
470        CmsResource resource;
471        try {
472            resource = cms.readResource(resourceName);
473        } catch (CmsException e) {
474            // ignore
475            return false;
476        }
477        CmsUser user;
478        try {
479            user = cms.readUser(userName);
480        } catch (CmsException e) {
481            // ignore
482            return false;
483        }
484        return m_securityManager.hasRoleForResource(cms.getRequestContext(), user, role, resource);
485    }
486
487    /**
488     * Removes a user from a role, in the given organizational unit.<p>
489     *
490     * @param cms the opencms context
491     * @param role the role to remove the user from
492     * @param username the name of the user that is to be removed from the group
493     * 
494     * @throws CmsException if operation was not successful
495     */
496    public void removeUserFromRole(CmsObject cms, CmsRole role, String username) throws CmsException {
497
498        m_securityManager.removeUserFromGroup(cms.getRequestContext(), username, role.getGroupName(), true);
499    }
500
501}