001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Thierry Delprat
016 *
017 */
018
019package org.nuxeo.ecm.platform.computedgroups;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import org.nuxeo.common.collections.ScopedMap;
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.api.DocumentModelList;
030import org.nuxeo.ecm.core.api.NuxeoGroup;
031import org.nuxeo.ecm.core.api.NuxeoPrincipal;
032import org.nuxeo.ecm.directory.BaseSession;
033import org.nuxeo.ecm.platform.usermanager.NuxeoPrincipalImpl;
034import org.nuxeo.ecm.platform.usermanager.UserManager;
035import org.nuxeo.ecm.platform.usermanager.UserManagerImpl;
036import org.nuxeo.runtime.api.Framework;
037
038/**
039 * {@link UserManager} implementation that is aware of {@link ComputedGroup}.
040 *
041 * @author Thierry Delprat
042 */
043public class UserManagerWithComputedGroups extends UserManagerImpl {
044
045    private static final long serialVersionUID = 1L;
046
047    protected static ComputedGroupsService cgs;
048
049    protected static Boolean useComputedGroup;
050
051    public static final String VIRTUAL_GROUP_MARKER = "__virtualGroup";
052
053    protected ComputedGroupsService getService() {
054        if (cgs == null) {
055            cgs = Framework.getLocalService(ComputedGroupsService.class);
056        }
057        return cgs;
058    }
059
060    protected boolean activateComputedGroup() {
061        // NXP-8133: recompute during tests, need to find a cleaner fix
062        if (useComputedGroup == null || Framework.isTestModeSet()) {
063            useComputedGroup = getService().activateComputedGroups();
064        }
065        return useComputedGroup;
066    }
067
068    @Override
069    protected NuxeoPrincipal makePrincipal(DocumentModel userEntry, boolean anonymous, List<String> groups)
070            {
071
072        NuxeoPrincipal principal = super.makePrincipal(userEntry, anonymous, groups);
073        if (activateComputedGroup() && principal instanceof NuxeoPrincipalImpl) {
074            NuxeoPrincipalImpl nuxPrincipal = (NuxeoPrincipalImpl) principal;
075
076            List<String> vGroups = getService().computeGroupsForUser(nuxPrincipal);
077
078            if (vGroups == null) {
079                vGroups = new ArrayList<String>();
080            }
081
082            List<String> origVGroups = nuxPrincipal.getVirtualGroups();
083            if (origVGroups == null) {
084                origVGroups = new ArrayList<String>();
085            }
086
087            // MERGE!
088            origVGroups.addAll(vGroups);
089
090            nuxPrincipal.setVirtualGroups(origVGroups);
091
092            // This a hack to work around the problem of running tests
093            if (!Framework.isTestModeSet()) {
094                nuxPrincipal.updateAllGroups();
095            } else {
096                List<String> allGroups = nuxPrincipal.getGroups();
097                for (String vGroup : vGroups) {
098                    if (!allGroups.contains(vGroup)) {
099                        allGroups.add(vGroup);
100                    }
101                }
102                nuxPrincipal.setGroups(allGroups);
103            }
104        }
105        return principal;
106    }
107
108    @Override
109    public NuxeoGroup getGroup(String groupName) {
110        NuxeoGroup grp = super.getGroup(groupName);
111        if (activateComputedGroup() && (grp == null || getService().allowGroupOverride())) {
112            NuxeoGroup computed = getService().getComputedGroup(groupName);
113            if (computed != null) {
114                grp = computed;
115            }
116        }
117        return grp;
118    }
119
120    @Override
121    public List<String> getGroupIds() {
122        List<String> ids = super.getGroupIds();
123        if (activateComputedGroup()) {
124            List<String> vGroups = getService().computeGroupIds();
125            for (String vGroup : vGroups) {
126                if (!ids.contains(vGroup)) {
127                    ids.add(vGroup);
128                }
129            }
130        }
131        return ids;
132    }
133
134    @Override
135    public DocumentModel getGroupModel(String groupName) {
136        DocumentModel grpDoc = super.getGroupModel(groupName);
137        if (activateComputedGroup() && grpDoc == null) {
138            return getComputedGroupAsDocumentModel(groupName);
139        }
140        return grpDoc;
141    }
142
143    @Override
144    public DocumentModelList searchGroups(Map<String, Serializable> filter, Set<String> fulltext)
145            {
146        return searchGroups(filter, fulltext, null);
147    }
148
149    @Override
150    public DocumentModelList searchGroups(Map<String, Serializable> filter, Set<String> fulltext, DocumentModel context)
151            {
152
153        boolean searchInVirtualGroups = activateComputedGroup();
154        if (Boolean.FALSE.equals(filter.get(VIRTUAL_GROUP_MARKER))) {
155            searchInVirtualGroups = false;
156        }
157
158        removeVirtualFilters(filter);
159        DocumentModelList groups = super.searchGroups(filter, fulltext, context);
160
161        if (searchInVirtualGroups) {
162            for (String vGroupName : getService().searchComputedGroups(filter, fulltext)) {
163                DocumentModel vGroup = getComputedGroupAsDocumentModel(vGroupName);
164                if (vGroup != null) {
165                    if (!groups.contains(vGroup)) {
166                        groups.add(vGroup);
167                    }
168                }
169            }
170        }
171        return groups;
172    }
173
174    protected DocumentModel getComputedGroupAsDocumentModel(String grpName) {
175        NuxeoGroup grp = getService().getComputedGroup(grpName);
176        if (grp == null) {
177            return null;
178        }
179
180        String schemaName = getGroupSchemaName();
181        String id = getGroupIdField();
182        DocumentModel groupDoc = BaseSession.createEntryModel(null, schemaName, grpName, null);
183
184        groupDoc.setProperty(schemaName, getGroupMembersField(), grp.getMemberUsers());
185        groupDoc.setProperty(schemaName, id, grp.getName());
186        groupDoc.setProperty(schemaName, getGroupIdField(), grp.getName());
187
188        final ScopedMap contextData = groupDoc.getContextData();
189        contextData.putScopedValue("virtual", Boolean.TRUE);
190
191        return groupDoc;
192    }
193
194}