001/*
002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thierry Delprat
018 *
019 */
020
021package org.nuxeo.ecm.platform.computedgroups;
022
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.List;
026import java.util.Map;
027import java.util.Set;
028
029import org.nuxeo.common.collections.ScopedMap;
030import org.nuxeo.ecm.core.api.DocumentModel;
031import org.nuxeo.ecm.core.api.DocumentModelList;
032import org.nuxeo.ecm.core.api.NuxeoGroup;
033import org.nuxeo.ecm.core.api.NuxeoPrincipal;
034import org.nuxeo.ecm.directory.BaseSession;
035import org.nuxeo.ecm.platform.usermanager.NuxeoPrincipalImpl;
036import org.nuxeo.ecm.platform.usermanager.UserManager;
037import org.nuxeo.ecm.platform.usermanager.UserManagerImpl;
038import org.nuxeo.runtime.api.Framework;
039
040/**
041 * {@link UserManager} implementation that is aware of {@link ComputedGroup}.
042 *
043 * @author Thierry Delprat
044 */
045public class UserManagerWithComputedGroups extends UserManagerImpl {
046
047    private static final long serialVersionUID = 1L;
048
049    protected static ComputedGroupsService cgs;
050
051    protected static Boolean useComputedGroup;
052
053    public static final String VIRTUAL_GROUP_MARKER = "__virtualGroup";
054
055    protected ComputedGroupsService getService() {
056        if (cgs == null) {
057            cgs = Framework.getLocalService(ComputedGroupsService.class);
058        }
059        return cgs;
060    }
061
062    protected boolean activateComputedGroup() {
063        // NXP-8133: recompute during tests, need to find a cleaner fix
064        if (useComputedGroup == null || Framework.isTestModeSet()) {
065            useComputedGroup = getService().activateComputedGroups();
066        }
067        return useComputedGroup;
068    }
069
070    @Override
071    protected NuxeoPrincipal makePrincipal(DocumentModel userEntry, boolean anonymous, List<String> groups)
072            {
073
074        NuxeoPrincipal principal = super.makePrincipal(userEntry, anonymous, groups);
075        if (activateComputedGroup() && principal instanceof NuxeoPrincipalImpl) {
076            NuxeoPrincipalImpl nuxPrincipal = (NuxeoPrincipalImpl) principal;
077
078            List<String> vGroups = getService().computeGroupsForUser(nuxPrincipal);
079
080            if (vGroups == null) {
081                vGroups = new ArrayList<String>();
082            }
083
084            List<String> origVGroups = nuxPrincipal.getVirtualGroups();
085            if (origVGroups == null) {
086                origVGroups = new ArrayList<String>();
087            }
088
089            // MERGE!
090            origVGroups.addAll(vGroups);
091
092            nuxPrincipal.setVirtualGroups(origVGroups);
093
094            // This a hack to work around the problem of running tests
095            if (!Framework.isTestModeSet()) {
096                nuxPrincipal.updateAllGroups();
097            } else {
098                List<String> allGroups = nuxPrincipal.getGroups();
099                for (String vGroup : vGroups) {
100                    if (!allGroups.contains(vGroup)) {
101                        allGroups.add(vGroup);
102                    }
103                }
104                nuxPrincipal.setGroups(allGroups);
105            }
106        }
107        return principal;
108    }
109
110    @Override
111    public NuxeoGroup getGroup(String groupName) {
112        NuxeoGroup grp = super.getGroup(groupName);
113        if (activateComputedGroup() && (grp == null || getService().allowGroupOverride())) {
114            NuxeoGroup computed = getService().getComputedGroup(groupName);
115            if (computed != null) {
116                grp = computed;
117            }
118        }
119        return grp;
120    }
121
122    @Override
123    public NuxeoGroup getGroup(String groupName, DocumentModel context) {
124        NuxeoGroup grp = super.getGroup(groupName, context);
125        if (activateComputedGroup() && (grp == null || getService().allowGroupOverride())) {
126            NuxeoGroup computed = getService().getComputedGroup(groupName);
127            if (computed != null) {
128                grp = computed;
129            }
130        }
131        return grp;
132    }
133
134    @Override
135    public List<String> getGroupIds() {
136        List<String> ids = super.getGroupIds();
137        if (activateComputedGroup()) {
138            List<String> vGroups = getService().computeGroupIds();
139            for (String vGroup : vGroups) {
140                if (!ids.contains(vGroup)) {
141                    ids.add(vGroup);
142                }
143            }
144        }
145        return ids;
146    }
147
148    @Override
149    public DocumentModel getGroupModel(String groupName) {
150        DocumentModel grpDoc = super.getGroupModel(groupName);
151        if (activateComputedGroup() && grpDoc == null) {
152            return getComputedGroupAsDocumentModel(groupName);
153        }
154        return grpDoc;
155    }
156
157    @Override
158    public DocumentModelList searchGroups(Map<String, Serializable> filter, Set<String> fulltext)
159            {
160        return searchGroups(filter, fulltext, null);
161    }
162
163    @Override
164    public DocumentModelList searchGroups(Map<String, Serializable> filter, Set<String> fulltext, DocumentModel context)
165            {
166
167        boolean searchInVirtualGroups = activateComputedGroup();
168        if (Boolean.FALSE.equals(filter.get(VIRTUAL_GROUP_MARKER))) {
169            searchInVirtualGroups = false;
170        }
171
172        removeVirtualFilters(filter);
173        DocumentModelList groups = super.searchGroups(filter, fulltext, context);
174
175        if (searchInVirtualGroups) {
176            for (String vGroupName : getService().searchComputedGroups(filter, fulltext)) {
177                DocumentModel vGroup = getComputedGroupAsDocumentModel(vGroupName);
178                if (vGroup != null) {
179                    if (!groups.contains(vGroup)) {
180                        groups.add(vGroup);
181                    }
182                }
183            }
184        }
185        return groups;
186    }
187
188    protected DocumentModel getComputedGroupAsDocumentModel(String grpName) {
189        NuxeoGroup grp = getService().getComputedGroup(grpName);
190        if (grp == null) {
191            return null;
192        }
193
194        String schemaName = getGroupSchemaName();
195        String id = getGroupIdField();
196        DocumentModel groupDoc = BaseSession.createEntryModel(null, schemaName, grpName, null);
197
198        groupDoc.setProperty(schemaName, getGroupMembersField(), grp.getMemberUsers());
199        groupDoc.setProperty(schemaName, id, grp.getName());
200        groupDoc.setProperty(schemaName, getGroupIdField(), grp.getName());
201
202        final ScopedMap contextData = groupDoc.getContextData();
203        contextData.putScopedValue("virtual", Boolean.TRUE);
204
205        return groupDoc;
206    }
207
208}