001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (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 & Co. KG, 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     * Default constructor.<p>
058     *
059     * @param securityManager the security manager
060     */
061    public CmsRoleManager(CmsSecurityManager securityManager) {
062
063        m_securityManager = securityManager;
064    }
065
066    /**
067     * Adds a user to the given role.<p>
068     *
069     * @param cms the opencms context
070     * @param role the role
071     * @param username the name of the user that is to be added to the role
072     *
073     * @throws CmsException if something goes wrong
074     */
075    public void addUserToRole(CmsObject cms, CmsRole role, String username) throws CmsException {
076
077        m_securityManager.addUserToGroup(cms.getRequestContext(), username, role.getGroupName(), true);
078    }
079
080    /**
081     * Checks if the user of this OpenCms context is a member of the given role
082     * for the given organizational unit.<p>
083     *
084     * The user must have the given role in at least one parent organizational unit.<p>
085     *
086     * @param cms the opencms context
087     * @param role the role to check
088     *
089     * @throws CmsRoleViolationException if the user does not have the required role permissions
090     */
091    public void checkRole(CmsObject cms, CmsRole role) throws CmsRoleViolationException {
092
093        m_securityManager.checkRole(cms.getRequestContext(), role);
094    }
095
096    /**
097     * Checks if the user of this OpenCms context is a member of the given role
098     * for the given resource.<p>
099     *
100     * The user must have the given role in at least one organizational unit to which this resource belongs.<p>
101     *
102     * @param cms the opencms context
103     * @param role the role to check
104     * @param resourceName the name of the resource to check the role for
105     *
106     * @throws CmsRoleViolationException if the user does not have the required role permissions
107     * @throws CmsException if something goes wrong, while reading the resource
108     */
109    public void checkRoleForResource(CmsObject cms, CmsRole role, String resourceName)
110    throws CmsException, CmsRoleViolationException {
111
112        CmsResource resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
113        m_securityManager.checkRoleForResource(cms.getRequestContext(), role, resource);
114    }
115
116    /**
117     * Returns all groups of organizational units for which the current user
118     * has the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
119     *
120     * @param cms the current cms context
121     * @param ouFqn the fully qualified name of the organizational unit
122     * @param includeSubOus if sub organizational units should be included in the search
123     *
124     * @return a list of {@link org.opencms.file.CmsGroup} objects
125     *
126     * @throws CmsException if something goes wrong
127     */
128    public List<CmsGroup> getManageableGroups(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
129
130        List<CmsGroup> groups = new ArrayList<CmsGroup>();
131        Iterator<CmsOrganizationalUnit> it = getOrgUnitsForRole(
132            cms,
133            CmsRole.ACCOUNT_MANAGER.forOrgUnit(ouFqn),
134            includeSubOus).iterator();
135        while (it.hasNext()) {
136            CmsOrganizationalUnit orgUnit = it.next();
137            groups.addAll(OpenCms.getOrgUnitManager().getGroups(cms, orgUnit.getName(), false));
138        }
139        return groups;
140    }
141
142    /**
143     * Returns a list of those organizational units whose members can be managed by the current user.<p>
144     *
145     * @param cms the current CMS context
146     * @param ouFqn the fully qualified name of the organizational unit
147     * @param includeSubOus if sub organizational units should be included in the search
148     * @param includeWebusers if webuser organizational units should be included in the search
149     *
150     * @return a list of organizational units
151     *
152     * @throws CmsException if something goes wrong
153     */
154    public List<CmsOrganizationalUnit> getManageableOrgUnits(
155        CmsObject cms,
156        String ouFqn,
157        boolean includeSubOus,
158        boolean includeWebusers)
159    throws CmsException {
160
161        List<CmsOrganizationalUnit> result = Lists.newArrayList();
162        List<CmsOrganizationalUnit> ous = getOrgUnitsForRole(
163            cms,
164            CmsRole.ACCOUNT_MANAGER.forOrgUnit(ouFqn),
165            includeSubOus);
166        for (CmsOrganizationalUnit ou : ous) {
167            if (includeWebusers || !ou.hasFlagWebuser()) {
168                result.add(ou);
169            }
170        }
171        return result;
172    }
173
174    /**
175     * Returns all resources of organizational units for which the current user has
176     * the given role role.<p>
177     *
178     * @param cms the current cms context
179     * @param role the role to check
180     *
181     * @return a list of {@link org.opencms.file.CmsResource} objects
182     *
183     * @throws CmsException if something goes wrong
184     */
185    public List<CmsResource> getManageableResources(CmsObject cms, CmsRole role) throws CmsException {
186
187        return m_securityManager.getManageableResources(cms.getRequestContext(), role);
188    }
189
190    /**
191     * Returns all users of organizational units for which the current user has
192     * the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
193     *
194     * @param cms the current cms context
195     * @param ouFqn the fully qualified name of the organizational unit
196     * @param includeSubOus if sub organizational units should be included in the search
197     *
198     * @return a list of {@link org.opencms.file.CmsUser} objects
199     *
200     * @throws CmsException if something goes wrong
201     */
202    public List<CmsUser> getManageableUsers(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
203
204        return getManageableUsers(cms, ouFqn, includeSubOus, false);
205    }
206
207    /**
208     * Returns all users of organizational units for which the current user has
209     * the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
210     *
211     * @param cms the current cms context
212     * @param ouFqn the fully qualified name of the organizational unit
213     * @param includeSubOus if sub organizational units should be included in the search
214     * @param includeWebusers if webuser organizational units should be included in the search
215     *
216     * @return a list of {@link org.opencms.file.CmsUser} objects
217     *
218     * @throws CmsException if something goes wrong
219     */
220    public List<CmsUser> getManageableUsers(CmsObject cms, String ouFqn, boolean includeSubOus, boolean includeWebusers)
221    throws CmsException {
222
223        List<CmsOrganizationalUnit> ous = getManageableOrgUnits(cms, ouFqn, includeSubOus, includeWebusers);
224        List<CmsUser> users = new ArrayList<CmsUser>();
225        Iterator<CmsOrganizationalUnit> it = ous.iterator();
226        while (it.hasNext()) {
227            CmsOrganizationalUnit orgUnit = it.next();
228            users.addAll(OpenCms.getOrgUnitManager().getUsers(cms, orgUnit.getName(), false));
229        }
230        return users;
231    }
232
233    /**
234     * Returns all the organizational units for which the current user has the given role.<p>
235     *
236     * @param cms the current cms context
237     * @param role the role to check
238     * @param includeSubOus if sub organizational units should be included in the search
239     *
240     * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects
241     *
242     * @throws CmsException if something goes wrong
243     */
244    public List<CmsOrganizationalUnit> getOrgUnitsForRole(CmsObject cms, CmsRole role, boolean includeSubOus)
245    throws CmsException {
246
247        return m_securityManager.getOrgUnitsForRole(cms.getRequestContext(), role, includeSubOus);
248    }
249
250    /**
251     * Returns the groups which constitute a given role, i.e. the set of groups such that a member of any of them
252     * has the given role.<p>
253     *
254     * @param cms the CMS context
255     * @param role the role
256     * @param directUsersOnly if true, only the role's direct group will be returned
257     *
258     * @return the groups constituting the given role
259     *
260     * @throws CmsException if something goes wrong
261     */
262    public Set<CmsGroup> getRoleGroups(CmsObject cms, CmsRole role, boolean directUsersOnly) throws CmsException {
263
264        return m_securityManager.getRoleGroups(cms.getRequestContext(), role, directUsersOnly);
265    }
266
267    /**
268     * Returns all roles, in the given organizational unit.<p>
269     *
270     * @param cms the opencms context
271     * @param ouFqn the fully qualified name of the organizational unit of the role
272     * @param includeSubOus include roles of child organizational units
273     *
274     * @return a list of all <code>{@link CmsRole}</code> objects
275     *
276     * @throws CmsException if operation was not successful
277     */
278    public List<CmsRole> getRoles(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
279
280        CmsOrganizationalUnit ou = OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, ouFqn);
281        List<CmsGroup> groups = m_securityManager.getGroups(cms.getRequestContext(), ou, includeSubOus, true);
282        List<CmsRole> roles = new ArrayList<CmsRole>(groups.size());
283        Iterator<CmsGroup> itGroups = groups.iterator();
284        while (itGroups.hasNext()) {
285            CmsGroup group = itGroups.next();
286            roles.add(CmsRole.valueOf(group));
287        }
288        return roles;
289    }
290
291    /**
292     * Returns all roles the given user has over the given resource.<p>
293     *
294     * @param cms the current cms context
295     * @param user the user
296     * @param resource the resource
297     *
298     * @return a list of {@link CmsRole} objects
299     *
300     * @throws CmsException if something goes wrong
301     */
302    public List<CmsRole> getRolesForResource(CmsObject cms, CmsUser user, CmsResource resource) throws CmsException {
303
304        return m_securityManager.getRolesForResource(cms.getRequestContext(), user, resource);
305    }
306
307    /**
308     * Returns all roles the given user has over the given resource.<p>
309     *
310     * @param cms the current cms context
311     * @param userFqn the user name to check
312     * @param resourceName the resource name
313     *
314     * @return a list of {@link CmsRole} objects
315     *
316     * @throws CmsException if something goes wrong
317     */
318    public List<CmsRole> getRolesForResource(CmsObject cms, String userFqn, String resourceName) throws CmsException {
319
320        CmsUser user = cms.readUser(userFqn);
321        CmsResource resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
322        return m_securityManager.getRolesForResource(cms.getRequestContext(), user, resource);
323    }
324
325    /**
326     * Returns all roles the given user belongs to, in the given organizational unit.<p>
327     *
328     * @param cms the opencms context
329     * @param username the name of the user to get all roles for
330     * @param ouFqn the fully qualified name of the organizational unit to restrict the search to
331     * @param includeChildOus include roles of child organizational units
332     * @param directRolesOnly if set only the direct assigned roles will be returned, if not also indirect roles
333     * @param recursive if this is set, also roles of higher organizational unit are considered
334     *
335     * @return a list of <code>{@link org.opencms.security.CmsRole}</code> objects
336     *
337     * @throws CmsException if operation was not successful
338     */
339    public List<CmsRole> getRolesOfUser(
340        CmsObject cms,
341        String username,
342        String ouFqn,
343        boolean includeChildOus,
344        boolean directRolesOnly,
345        boolean recursive)
346    throws CmsException {
347
348        List<CmsGroup> groups;
349        ouFqn = CmsOrganizationalUnit.removeLeadingSeparator(ouFqn);
350        if (!recursive) {
351            groups = m_securityManager.getGroupsOfUser(
352                cms.getRequestContext(),
353                username,
354                ouFqn,
355                includeChildOus,
356                true,
357                directRolesOnly,
358                cms.getRequestContext().getRemoteAddress());
359        } else {
360            groups = new ArrayList<CmsGroup>();
361            Iterator<CmsGroup> itAllGroups = m_securityManager.getGroupsOfUser(
362                cms.getRequestContext(),
363                username,
364                "",
365                true,
366                true,
367                directRolesOnly,
368                cms.getRequestContext().getRemoteAddress()).iterator();
369            while (itAllGroups.hasNext()) {
370                CmsGroup role = itAllGroups.next();
371                if (!includeChildOus && role.getOuFqn().equals(ouFqn)) {
372                    groups.add(role);
373                }
374                if (includeChildOus && role.getOuFqn().startsWith(ouFqn)) {
375                    groups.add(role);
376                }
377            }
378        }
379        List<CmsRole> roles = new ArrayList<CmsRole>(groups.size());
380        Iterator<CmsGroup> itGroups = groups.iterator();
381        while (itGroups.hasNext()) {
382            CmsGroup group = itGroups.next();
383            roles.add(CmsRole.valueOf(group));
384        }
385        return roles;
386    }
387
388    /**
389     * Returns all direct users of a given role, in the given organizational unit.<p>
390     *
391     * Users that are "indirectly" in the role are not returned in the result.<p>
392     *
393     * @param cms the opencms context
394     * @param role the role to get all users for
395     * @param includeOtherOuUsers include users of other organizational units
396     * @param directUsersOnly if set only the direct assigned users will be returned,
397     *                          if not also indirect users, ie. members of child groups
398     *
399     * @return all <code>{@link org.opencms.file.CmsUser}</code> objects in the group
400     *
401     * @throws CmsException if operation was not successful
402     */
403    public List<CmsUser> getUsersOfRole(
404        CmsObject cms,
405        CmsRole role,
406        boolean includeOtherOuUsers,
407        boolean directUsersOnly)
408    throws CmsException {
409
410        return m_securityManager.getUsersOfGroup(
411            cms.getRequestContext(),
412            role.getGroupName(),
413            includeOtherOuUsers,
414            directUsersOnly,
415            true);
416    }
417
418    /**
419     * Checks if the given context user has the given role in the given organizational unit.<p>
420     *
421     * @param cms the opencms context
422     * @param role the role to check
423     *
424     * @return <code>true</code> if the given context user has the given role in the given organizational unit
425     */
426    public boolean hasRole(CmsObject cms, CmsRole role) {
427
428        return m_securityManager.hasRole(cms.getRequestContext(), cms.getRequestContext().getCurrentUser(), role);
429    }
430
431    /**
432     * Checks if the given user has the given role in the given organizational unit.<p>
433     *
434     * @param cms the opencms context
435     * @param userName the name of the user to check the role for
436     * @param role the role to check
437     *
438     * @return <code>true</code> if the given user has the given role in the given organizational unit
439     */
440    public boolean hasRole(CmsObject cms, String userName, CmsRole role) {
441
442        CmsUser user;
443        try {
444            user = cms.readUser(userName);
445        } catch (CmsException e) {
446            // ignore
447            return false;
448        }
449        return m_securityManager.hasRole(cms.getRequestContext(), user, role);
450    }
451
452    /**
453     * Checks if the given context user has the given role for the given resource.<p>
454     *
455     * @param cms the opencms context
456     * @param role the role to check
457     * @param resource the resource to check
458     *
459     * @return <code>true</code> if the given context user has the given role for the given resource
460     */
461    public boolean hasRoleForResource(CmsObject cms, CmsRole role, CmsResource resource) {
462
463        return m_securityManager.hasRoleForResource(
464            cms.getRequestContext(),
465            cms.getRequestContext().getCurrentUser(),
466            role,
467            resource);
468    }
469
470    /**
471     * Checks if the given context user has the given role for the given resource.<p>
472     *
473     * @param cms the opencms context
474     * @param role the role to check
475     * @param resourceName the name of the resource to check
476     *
477     * @return <code>true</code> if the given context user has the given role for the given resource
478     */
479    public boolean hasRoleForResource(CmsObject cms, CmsRole role, String resourceName) {
480
481        CmsResource resource;
482        try {
483            resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
484        } catch (CmsException e) {
485            // ignore
486            return false;
487        }
488        return m_securityManager.hasRoleForResource(
489            cms.getRequestContext(),
490            cms.getRequestContext().getCurrentUser(),
491            role,
492            resource);
493    }
494
495    /**
496     * Checks if the given context user has the given role for the given resource.<p>
497     *
498     * @param cms the opencms context
499     * @param userName the name of the user to check the role for
500     * @param role the role to check
501     * @param resourceName the name of the resource to check
502     *
503     * @return <code>true</code> if the given context user has the given role for the given resource
504     */
505    public boolean hasRoleForResource(CmsObject cms, String userName, CmsRole role, String resourceName) {
506
507        CmsResource resource;
508        try {
509            resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
510        } catch (CmsException e) {
511            // ignore
512            return false;
513        }
514        CmsUser user;
515        try {
516            user = cms.readUser(userName);
517        } catch (CmsException e) {
518            // ignore
519            return false;
520        }
521        return m_securityManager.hasRoleForResource(cms.getRequestContext(), user, role, resource);
522    }
523
524    /**
525     * Removes a user from a role, in the given organizational unit.<p>
526     *
527     * @param cms the opencms context
528     * @param role the role to remove the user from
529     * @param username the name of the user that is to be removed from the group
530     *
531     * @throws CmsException if operation was not successful
532     */
533    public void removeUserFromRole(CmsObject cms, CmsRole role, String username) throws CmsException {
534
535        m_securityManager.removeUserFromGroup(cms.getRequestContext(), username, role.getGroupName(), true);
536    }
537
538}