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.CmsProject;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.CmsUser;
037import org.opencms.file.CmsUserSearchParameters;
038import org.opencms.main.CmsException;
039import org.opencms.main.CmsInitException;
040import org.opencms.main.CmsLog;
041import org.opencms.main.OpenCms;
042
043import java.util.ArrayList;
044import java.util.List;
045
046import org.apache.commons.logging.Log;
047
048/**
049 * This manager provide access to the organizational unit related operations.<p>
050 *
051 * @since 6.5.6
052 */
053public class CmsOrgUnitManager {
054
055    /** Logger instance for this class. */
056    private static final Log LOG = CmsLog.getLog(CmsOrgUnitManager.class);
057
058    /** The security manager. */
059    private final CmsSecurityManager m_securityManager;
060
061    /**
062     * Default constructor.<p>
063     *
064     * @param securityManager the security manager
065     */
066    public CmsOrgUnitManager(CmsSecurityManager securityManager) {
067
068        m_securityManager = securityManager;
069    }
070
071    /**
072     * Adds a resource to the given organizational unit.<p>
073     *
074     * @param cms the opencms context
075     * @param ouFqn the full qualified name of the organizational unit to add the resource to
076     * @param resourceName the name of the resource that is to be added to the organizational unit
077     *
078     * @throws CmsException if something goes wrong
079     */
080    public void addResourceToOrgUnit(CmsObject cms, String ouFqn, String resourceName) throws CmsException {
081
082        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
083        CmsResource resource = cms.readResource(resourceName);
084        m_securityManager.addResourceToOrgUnit(cms.getRequestContext(), orgUnit, resource);
085    }
086
087    /**
088     * Counts the users which fit the given search criteria.<p>
089     *
090     * @param cms the current CMS context
091     * @param params the user search parameters
092     *
093     * @return the total number of users which fit the given search parameters
094     *
095     * @throws CmsException if something goes wrong
096     */
097    public long countUsers(CmsObject cms, CmsUserSearchParameters params) throws CmsException {
098
099        return m_securityManager.countUsers(cms.getRequestContext(), params);
100    }
101
102    /**
103     * Creates a new organizational unit.<p>
104     *
105     * The parent structure must exist.<p>
106     *
107     * @param cms the opencms context
108     * @param ouFqn the fully qualified name of the new organizational unit
109     * @param description the description of the new organizational unit
110     * @param flags the flags for the new organizational unit
111     * @param resourceName the first associated resource
112     *
113     * @return a <code>{@link CmsOrganizationalUnit}</code> object representing
114     *          the newly created organizational unit
115     *
116     * @throws CmsException if operation was not successful
117     */
118    public CmsOrganizationalUnit createOrganizationalUnit(
119        CmsObject cms,
120        String ouFqn,
121        String description,
122        int flags,
123        String resourceName)
124    throws CmsException {
125
126        CmsResource resource = null;
127        if (((flags & CmsOrganizationalUnit.FLAG_WEBUSERS) == 0) || (resourceName != null)) {
128            // only normal OUs have to have at least one resource
129            resource = cms.readResource(resourceName);
130        }
131        return m_securityManager.createOrganizationalUnit(cms.getRequestContext(), ouFqn, description, flags, resource);
132    }
133
134    /**
135     * Deletes an organizational unit.<p>
136     *
137     * Only organizational units that contain no sub units can be deleted.<p>
138     *
139     * The organizational unit can not be delete if it is used in the request context,
140     * or if the current user belongs to it.<p>
141     *
142     * All users and groups in the given organizational unit will be deleted.<p>
143     *
144     * @param cms the opencms context
145     * @param ouFqn the fully qualified name of the organizational unit to delete
146     *
147     * @throws CmsException if operation was not successful
148     */
149    public void deleteOrganizationalUnit(CmsObject cms, String ouFqn) throws CmsException {
150
151        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
152        m_securityManager.deleteOrganizationalUnit(cms.getRequestContext(), orgUnit);
153    }
154
155    /**
156     * Returns all accessible projects of the given organizational unit.
157     *
158     * That is all projects which are owned by the current user or which are
159     * accessible for the group of the user.<p>
160     *
161     * @param cms the opencms context
162     * @param ouFqn the fully qualified name of the organizational unit to get projects for
163     * @param includeSubOus if all projects of sub-organizational units should be retrieved too
164     *
165     * @return all <code>{@link org.opencms.file.CmsProject}</code> objects in the organizational unit
166     *
167     * @throws CmsException if operation was not successful
168     */
169    public List<CmsProject> getAllAccessibleProjects(CmsObject cms, String ouFqn, boolean includeSubOus)
170    throws CmsException {
171
172        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
173        return (m_securityManager.getAllAccessibleProjects(cms.getRequestContext(), orgUnit, includeSubOus));
174    }
175
176    /**
177     * Returns all manageable projects of the given organizational unit.<p>
178     *
179     * That is all projects which are owned by the current user or which are manageable
180     * for the group of the user.<p>
181     *
182     * @param cms the opencms context
183     * @param ouFqn the fully qualified name of the organizational unit to get projects for
184     * @param includeSubOus if all projects of sub-organizational units should be retrieved too
185     *
186     * @return all <code>{@link org.opencms.file.CmsProject}</code> objects in the organizational unit
187     *
188     * @throws CmsException if operation was not successful
189     */
190    public List<CmsProject> getAllManageableProjects(CmsObject cms, String ouFqn, boolean includeSubOus)
191    throws CmsException {
192
193        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
194        return (m_securityManager.getAllManageableProjects(cms.getRequestContext(), orgUnit, includeSubOus));
195    }
196
197    /**
198     * Returns all groups of the given organizational unit.<p>
199     *
200     * @param cms the opencms context
201     * @param ouFqn the fully qualified name of the organizational unit to get all principals for
202     * @param includeSubOus if all groups of sub-organizational units should be retrieved too
203     *
204     * @return all <code>{@link org.opencms.file.CmsGroup}</code> objects in the organizational unit
205     *
206     * @throws CmsException if operation was not successful
207     */
208    public List<CmsGroup> getGroups(CmsObject cms, String ouFqn, boolean includeSubOus) throws CmsException {
209
210        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
211        return (m_securityManager.getGroups(cms.getRequestContext(), orgUnit, includeSubOus, false));
212    }
213
214    /**
215     * Returns all child organizational units of the given parent organizational unit including
216     * hierarchical deeper organization units if needed.<p>
217     *
218     * @param cms the opencms context
219     * @param ouFqn the fully qualified name of the parent organizational unit
220     * @param includeChildren if hierarchical deeper organization units should also be returned
221     *
222     * @return a list of <code>{@link CmsOrganizationalUnit}</code> objects
223     *
224     * @throws CmsException if operation was not successful
225     */
226    public List<CmsOrganizationalUnit> getOrganizationalUnits(CmsObject cms, String ouFqn, boolean includeChildren)
227    throws CmsException {
228
229        CmsOrganizationalUnit parent = readOrganizationalUnit(cms, ouFqn);
230        return m_securityManager.getOrganizationalUnits(cms.getRequestContext(), parent, includeChildren);
231    }
232
233    /**
234     * Gets all organizational units x such that x and all of its ancestor org. units, up to the root
235     * organizational unit contain a given path.
236     *
237     * @param cms the CMS context
238     * @param rootPath the root path of a resource
239     * @return the list of organizational units containing the path
240     * @throws CmsException if something goes wrong
241     */
242    public List<CmsOrganizationalUnit> getOrgUnitsForResource(CmsObject cms, String rootPath) throws CmsException {
243
244        CmsOrganizationalUnit rootOU = OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, "/");
245        List<CmsOrganizationalUnit> result = new ArrayList<>();
246        collectOrgUnitsForResource(cms, rootPath, rootOU, result);
247        return result;
248    }
249
250    /**
251     * Returns all resources of the given organizational unit.<p>
252     *
253     * @param cms the opencms context
254     * @param ouFqn the fully qualified name of the organizational unit to get all resources for
255     *
256     * @return all <code>{@link CmsResource}</code> objects in the organizational unit
257     *
258     * @throws CmsException if operation was not successful
259     */
260    public List<CmsResource> getResourcesForOrganizationalUnit(CmsObject cms, String ouFqn) throws CmsException {
261
262        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
263        return m_securityManager.getResourcesForOrganizationalUnit(cms.getRequestContext(), orgUnit);
264    }
265
266    /**
267     * Returns all users of the given organizational unit.<p>
268     *
269     * @param cms the opencms context
270     * @param ouFqn the fully qualified name of the organizational unit to get all principals for
271     * @param recursive if all users of sub-organizational units should be retrieved too
272     *
273     * @return all <code>{@link org.opencms.file.CmsUser}</code> objects in the organizational unit
274     *
275     * @throws CmsException if operation was not successful
276     */
277    public List<CmsUser> getUsers(CmsObject cms, String ouFqn, boolean recursive) throws CmsException {
278
279        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
280        return m_securityManager.getUsers(cms.getRequestContext(), orgUnit, recursive);
281    }
282
283    /**
284     * Returns all users of the given organizational unit, without their additional info.<p>
285     *
286     * @param cms the opencms context
287     * @param ouFqn the fully qualified name of the organizational unit to get all principals for
288     * @param recursive if all users of sub-organizational units should be retrieved too
289     *
290     * @return all <code>{@link org.opencms.file.CmsUser}</code> objects in the organizational unit
291     *
292     * @throws CmsException if operation was not successful
293     */
294    public List<CmsUser> getUsersWithoutAdditionalInfo(CmsObject cms, String ouFqn, boolean recursive)
295    throws CmsException {
296
297        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
298        return m_securityManager.getUsersWithoutAdditionalInfo(cms.getRequestContext(), orgUnit, recursive);
299    }
300
301    /**
302     * Initializes the organizational units.<p>
303     *
304     * @param cms the admin CMS context
305     *
306     * @throws CmsException if something goes wrong
307     */
308    public void initialize(CmsObject cms) throws CmsException {
309
310        List<CmsOrganizationalUnit> ous = getOrganizationalUnits(cms, "", true);
311        for (CmsOrganizationalUnit ou : ous) {
312            try {
313                m_securityManager.initializeOrgUnit(cms.getRequestContext(), ou);
314            } catch (CmsInitException e) {
315                LOG.error("Error while initializing OU " + ou.getName() + ": " + e.getLocalizedMessage(), e);
316            }
317        }
318    }
319
320    /**
321     * Reads an organizational Unit based on its fully qualified name.<p>
322     *
323     * @param cms the opencms context
324     * @param ouFqn the fully qualified name of the organizational Unit to be read
325     *
326     * @return the organizational Unit with the provided fully qualified name
327     *
328     * @throws CmsException if something goes wrong
329     */
330    public CmsOrganizationalUnit readOrganizationalUnit(CmsObject cms, String ouFqn) throws CmsException {
331
332        return m_securityManager.readOrganizationalUnit(cms.getRequestContext(), ouFqn);
333    }
334
335    /**
336     * Removes a resource from the given organizational unit.<p>
337     *
338     * @param cms the opencms context
339     * @param ouFqn the fully qualified name of the organizational unit to remove the resource from
340     * @param resourceName the name of the resource that is to be removed from the organizational unit
341     *
342     * @throws CmsException if something goes wrong
343     */
344    public void removeResourceFromOrgUnit(CmsObject cms, String ouFqn, String resourceName) throws CmsException {
345
346        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
347        CmsResource resource = cms.readResource(resourceName, CmsResourceFilter.ALL);
348
349        m_securityManager.removeResourceFromOrgUnit(cms.getRequestContext(), orgUnit, resource);
350    }
351
352    /**
353     * Searches users which fit the given search parameters.<p>
354     *
355     * @param cms the current CMS context
356     * @param params the user search parameters
357     *
358     * @return the users which fit the given search criteria
359     *
360     * @throws CmsException if something goes wrong
361     */
362    public List<CmsUser> searchUsers(CmsObject cms, CmsUserSearchParameters params) throws CmsException {
363
364        return m_securityManager.searchUsers(cms.getRequestContext(), params);
365    }
366
367    /**
368     * Moves an user to the given organizational unit.<p>
369     *
370     * @param cms the opencms context
371     * @param ouFqn the full qualified name of the organizational unit to add the user to
372     * @param userName the name of the user that is to be added to the organizational unit
373     *
374     * @throws CmsException if something goes wrong
375     */
376    public void setUsersOrganizationalUnit(CmsObject cms, String ouFqn, String userName) throws CmsException {
377
378        CmsOrganizationalUnit orgUnit = readOrganizationalUnit(cms, ouFqn);
379        CmsUser user = cms.readUser(userName);
380        m_securityManager.setUsersOrganizationalUnit(cms.getRequestContext(), orgUnit, user);
381    }
382
383    /**
384     * Writes an already existing organizational unit.<p>
385     *
386     * The organizational unit has to be a valid OpenCms organizational unit.<br>
387     *
388     * The organizational unit will be completely overridden by the given data.<p>
389     *
390     * @param cms the opencms context
391     * @param organizationalUnit the organizational unit that should be written
392     *
393     * @throws CmsException if operation was not successful
394     */
395    public void writeOrganizationalUnit(CmsObject cms, CmsOrganizationalUnit organizationalUnit) throws CmsException {
396
397        m_securityManager.writeOrganizationalUnit(cms.getRequestContext(), organizationalUnit);
398    }
399
400    /**
401     * Helper method for collecting all organizational units such that they and their ancestors all contain a given resource.
402     *
403     * @param cms the CMS context
404     * @param resourceRootPath the resource root path to check for
405     * @param parentOU the current OU
406     * @param ous the list of results
407     *
408     * @throws CmsException if something goes wrong
409     */
410    void collectOrgUnitsForResource(
411        CmsObject cms,
412        String resourceRootPath,
413        CmsOrganizationalUnit parentOU,
414        List<CmsOrganizationalUnit> ous)
415    throws CmsException {
416
417        List<CmsResource> resources = OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(
418            cms,
419            parentOU.getName());
420        boolean insideOU = false;
421
422        for (CmsResource res : resources) {
423            if (resourceRootPath.startsWith(res.getRootPath())) {
424                insideOU = true;
425                break;
426            }
427        }
428        if (insideOU) {
429            for (CmsOrganizationalUnit ou : OpenCms.getOrgUnitManager().getOrganizationalUnits(
430                cms,
431                parentOU.getName(),
432                false)) {
433                try {
434                    collectOrgUnitsForResource(cms, resourceRootPath, ou, ous);
435                } catch (CmsException e) {
436                    // ignore
437                }
438            }
439            ous.add(parentOU);
440        }
441    }
442}