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     * 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);
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) throws CmsException {
159
160        List<CmsOrganizationalUnit> result = Lists.newArrayList();
161        List<CmsOrganizationalUnit> ous = getOrgUnitsForRole(
162            cms,
163            CmsRole.ACCOUNT_MANAGER.forOrgUnit(ouFqn),
164            includeSubOus);
165        for (CmsOrganizationalUnit ou : ous) {
166            if (includeWebusers || !ou.hasFlagWebuser()) {
167                result.add(ou);
168            }
169        }
170        return result;
171    }
172
173    /**
174     * Returns all resources of organizational units for which the current user has
175     * the given role role.<p>
176     *
177     * @param cms the current cms context
178     * @param role the role to check
179     *
180     * @return a list of {@link org.opencms.file.CmsResource} objects
181     *
182     * @throws CmsException if something goes wrong
183     */
184    public List<CmsResource> getManageableResources(CmsObject cms, CmsRole role) throws CmsException {
185
186        return m_securityManager.getManageableResources(cms.getRequestContext(), role);
187    }
188
189    /**
190     * Returns all users of organizational units for which the current user has
191     * the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
192     *
193     * @param cms the current cms context
194     * @param ouFqn the fully qualified name of the organizational unit
195     * @param includeSubOus if sub organizational units should be included in the search
196     *
197     * @return a list of {@link org.opencms.file.CmsUser} objects
198     *
199     * @throws CmsException if something goes wrong
200     */
201    public List<CmsUser> getManageableUsers(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
202
203        return getManageableUsers(cms, ouFqn, includeSubOus, false);
204    }
205
206    /**
207     * Returns all users of organizational units for which the current user has
208     * the {@link CmsRole#ACCOUNT_MANAGER} role.<p>
209     *
210     * @param cms the current cms context
211     * @param ouFqn the fully qualified name of the organizational unit
212     * @param includeSubOus if sub organizational units should be included in the search
213     * @param includeWebusers if webuser organizational units should be included in the search
214     *
215     * @return a list of {@link org.opencms.file.CmsUser} objects
216     *
217     * @throws CmsException if something goes wrong
218     */
219    public List<CmsUser> getManageableUsers(CmsObject cms, String ouFqn, boolean includeSubOus, boolean includeWebusers)
220    throws CmsException {
221
222        List<CmsOrganizationalUnit> ous = getManageableOrgUnits(cms, ouFqn, includeSubOus, includeWebusers);
223        List<CmsUser> users = new ArrayList<CmsUser>();
224        Iterator<CmsOrganizationalUnit> it = ous.iterator();
225        while (it.hasNext()) {
226            CmsOrganizationalUnit orgUnit = it.next();
227            users.addAll(OpenCms.getOrgUnitManager().getUsers(cms, orgUnit.getName(), false));
228        }
229        return users;
230    }
231
232    /**
233     * Returns all the organizational units for which the current user has the given role.<p>
234     *
235     * @param cms the current cms context
236     * @param role the role to check
237     * @param includeSubOus if sub organizational units should be included in the search
238     *
239     * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects
240     *
241     * @throws CmsException if something goes wrong
242     */
243    public List<CmsOrganizationalUnit> getOrgUnitsForRole(CmsObject cms, CmsRole role, boolean includeSubOus)
244    throws CmsException {
245
246        return m_securityManager.getOrgUnitsForRole(cms.getRequestContext(), role, includeSubOus);
247    }
248
249    /**
250     * Returns the groups which constitute a given role, i.e. the set of groups such that a member of any of them
251     * has the given role.<p>
252     *
253     * @param cms the CMS context
254     * @param role the role
255     * @param directUsersOnly if true, only the role's direct group will be returned
256     *
257     * @return the groups constituting the given role
258     *
259     * @throws CmsException if something goes wrong
260     */
261    public Set<CmsGroup> getRoleGroups(CmsObject cms, CmsRole role, boolean directUsersOnly) throws CmsException {
262
263        return m_securityManager.getRoleGroups(cms.getRequestContext(), role, directUsersOnly);
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 user the user
295     * @param resource the resource
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, CmsUser user, CmsResource resource) throws CmsException {
302
303        return m_securityManager.getRolesForResource(cms.getRequestContext(), user, resource);
304    }
305
306    /**
307     * Returns all roles the given user has over the given resource.<p>
308     *
309     * @param cms the current cms context
310     * @param userFqn the user name to check
311     * @param resourceName the resource name
312     *
313     * @return a list of {@link CmsRole} objects
314     *
315     * @throws CmsException if something goes wrong
316     */
317    public List<CmsRole> getRolesForResource(CmsObject cms, String userFqn, String resourceName) throws CmsException {
318
319        CmsUser user = cms.readUser(userFqn);
320        CmsResource resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
321        return m_securityManager.getRolesForResource(cms.getRequestContext(), user, resource);
322    }
323
324    /**
325     * Returns all roles the given user belongs to, in the given organizational unit.<p>
326     *
327     * @param cms the opencms context
328     * @param username the name of the user to get all roles for
329     * @param ouFqn the fully qualified name of the organizational unit to restrict the search to
330     * @param includeChildOus include roles of child organizational units
331     * @param directRolesOnly if set only the direct assigned roles will be returned, if not also indirect roles
332     * @param recursive if this is set, also roles of higher organizational unit are considered
333     *
334     * @return a list of <code>{@link org.opencms.security.CmsRole}</code> objects
335     *
336     * @throws CmsException if operation was not successful
337     */
338    public List<CmsRole> getRolesOfUser(
339        CmsObject cms,
340        String username,
341        String ouFqn,
342        boolean includeChildOus,
343        boolean directRolesOnly,
344        boolean recursive) throws CmsException {
345
346        List<CmsGroup> groups;
347        ouFqn = CmsOrganizationalUnit.removeLeadingSeparator(ouFqn);
348        if (!recursive) {
349            groups = m_securityManager.getGroupsOfUser(
350                cms.getRequestContext(),
351                username,
352                ouFqn,
353                includeChildOus,
354                true,
355                directRolesOnly,
356                cms.getRequestContext().getRemoteAddress());
357        } else {
358            groups = new ArrayList<CmsGroup>();
359            Iterator<CmsGroup> itAllGroups = m_securityManager.getGroupsOfUser(
360                cms.getRequestContext(),
361                username,
362                "",
363                true,
364                true,
365                directRolesOnly,
366                cms.getRequestContext().getRemoteAddress()).iterator();
367            while (itAllGroups.hasNext()) {
368                CmsGroup role = itAllGroups.next();
369                if (!includeChildOus && role.getOuFqn().equals(ouFqn)) {
370                    groups.add(role);
371                }
372                if (includeChildOus && role.getOuFqn().startsWith(ouFqn)) {
373                    groups.add(role);
374                }
375            }
376        }
377        List<CmsRole> roles = new ArrayList<CmsRole>(groups.size());
378        Iterator<CmsGroup> itGroups = groups.iterator();
379        while (itGroups.hasNext()) {
380            CmsGroup group = itGroups.next();
381            roles.add(CmsRole.valueOf(group));
382        }
383        return roles;
384    }
385
386    /**
387     * Returns all direct users of a given role, in the given organizational unit.<p>
388     *
389     * Users that are "indirectly" in the role are not returned in the result.<p>
390     *
391     * @param cms the opencms context
392     * @param role the role to get all users for
393     * @param includeOtherOuUsers include users of other organizational units
394     * @param directUsersOnly if set only the direct assigned users will be returned,
395     *                          if not also indirect users, ie. members of child groups
396     *
397     * @return all <code>{@link org.opencms.file.CmsUser}</code> objects in the group
398     *
399     * @throws CmsException if operation was not successful
400     */
401    public List<CmsUser> getUsersOfRole(
402        CmsObject cms,
403        CmsRole role,
404        boolean includeOtherOuUsers,
405        boolean directUsersOnly) throws CmsException {
406
407        return m_securityManager.getUsersOfGroup(
408            cms.getRequestContext(),
409            role.getGroupName(),
410            includeOtherOuUsers,
411            directUsersOnly,
412            true);
413    }
414
415    /**
416     * Checks if the given context user has the given role in the given organizational unit.<p>
417     *
418     * @param cms the opencms context
419     * @param role the role to check
420     *
421     * @return <code>true</code> if the given context user has the given role in the given organizational unit
422     */
423    public boolean hasRole(CmsObject cms, CmsRole role) {
424
425        return m_securityManager.hasRole(cms.getRequestContext(), cms.getRequestContext().getCurrentUser(), role);
426    }
427
428    /**
429     * Checks if the given user has the given role in the given organizational unit.<p>
430     *
431     * @param cms the opencms context
432     * @param userName the name of the user to check the role for
433     * @param role the role to check
434     *
435     * @return <code>true</code> if the given user has the given role in the given organizational unit
436     */
437    public boolean hasRole(CmsObject cms, String userName, CmsRole role) {
438
439        CmsUser user;
440        try {
441            user = cms.readUser(userName);
442        } catch (CmsException e) {
443            // ignore
444            return false;
445        }
446        return m_securityManager.hasRole(cms.getRequestContext(), user, role);
447    }
448
449    /**
450     * Checks if the given context user has the given role for the given resource.<p>
451     *
452     * @param cms the opencms context
453     * @param role the role to check
454     * @param resourceName the name of the resource to check
455     *
456     * @return <code>true</code> if the given context user has the given role for the given resource
457     */
458    public boolean hasRoleForResource(CmsObject cms, CmsRole role, String resourceName) {
459
460        CmsResource resource;
461        try {
462            resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
463        } catch (CmsException e) {
464            // ignore
465            return false;
466        }
467        return m_securityManager.hasRoleForResource(
468            cms.getRequestContext(),
469            cms.getRequestContext().getCurrentUser(),
470            role,
471            resource);
472    }
473
474    /**
475     * Checks if the given context user has the given role for the given resource.<p>
476     *
477     * @param cms the opencms context
478     * @param userName the name of the user to check the role for
479     * @param role the role to check
480     * @param resourceName the name of the resource to check
481     *
482     * @return <code>true</code> if the given context user has the given role for the given resource
483     */
484    public boolean hasRoleForResource(CmsObject cms, String userName, CmsRole role, String resourceName) {
485
486        CmsResource resource;
487        try {
488            resource = cms.readResource(resourceName);
489        } catch (CmsException e) {
490            // ignore
491            return false;
492        }
493        CmsUser user;
494        try {
495            user = cms.readUser(userName);
496        } catch (CmsException e) {
497            // ignore
498            return false;
499        }
500        return m_securityManager.hasRoleForResource(cms.getRequestContext(), user, role, resource);
501    }
502
503    /**
504     * Removes a user from a role, in the given organizational unit.<p>
505     *
506     * @param cms the opencms context
507     * @param role the role to remove the user from
508     * @param username the name of the user that is to be removed from the group
509     *
510     * @throws CmsException if operation was not successful
511     */
512    public void removeUserFromRole(CmsObject cms, CmsRole role, String username) throws CmsException {
513
514        m_securityManager.removeUserFromGroup(cms.getRequestContext(), username, role.getGroupName(), true);
515    }
516
517}