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.Collections; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029 030import org.nuxeo.ecm.core.api.DocumentModel; 031import org.nuxeo.ecm.core.api.DocumentModelList; 032import org.nuxeo.ecm.core.api.NuxeoException; 033import org.nuxeo.ecm.core.api.NuxeoGroup; 034import org.nuxeo.ecm.core.api.NuxeoPrincipal; 035import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; 036import org.nuxeo.ecm.core.query.sql.model.QueryBuilder; 037import org.nuxeo.ecm.directory.BaseSession; 038import org.nuxeo.ecm.directory.Directory; 039import org.nuxeo.ecm.directory.Session; 040import org.nuxeo.ecm.platform.usermanager.NuxeoPrincipalImpl; 041import org.nuxeo.ecm.platform.usermanager.UserManager; 042import org.nuxeo.ecm.platform.usermanager.UserManagerImpl; 043import org.nuxeo.runtime.api.Framework; 044 045/** 046 * {@link UserManager} implementation that is aware of {@link ComputedGroup}. 047 * 048 * @author Thierry Delprat 049 */ 050public class UserManagerWithComputedGroups extends UserManagerImpl { 051 052 private static final long serialVersionUID = 1L; 053 054 protected static ComputedGroupsService cgs; 055 056 protected static Boolean useComputedGroup; 057 058 public static final String VIRTUAL_GROUP_MARKER = "__virtualGroup"; 059 060 protected ComputedGroupsService getService() { 061 if (cgs == null) { 062 cgs = Framework.getService(ComputedGroupsService.class); 063 } 064 return cgs; 065 } 066 067 protected boolean activateComputedGroup() { 068 // NXP-8133: recompute during tests, need to find a cleaner fix 069 if (useComputedGroup == null || Framework.isTestModeSet()) { 070 useComputedGroup = getService().activateComputedGroups(); 071 } 072 return useComputedGroup; 073 } 074 075 @Override 076 protected NuxeoPrincipal makePrincipal(DocumentModel userEntry, boolean anonymous, List<String> groups) 077 { 078 079 NuxeoPrincipal principal = super.makePrincipal(userEntry, anonymous, groups); 080 if (activateComputedGroup() && principal instanceof NuxeoPrincipalImpl) { 081 NuxeoPrincipalImpl nuxPrincipal = (NuxeoPrincipalImpl) principal; 082 083 List<String> vGroups = getService().computeGroupsForUser(nuxPrincipal); 084 085 if (vGroups == null) { 086 vGroups = new ArrayList<String>(); 087 } 088 089 List<String> origVGroups = nuxPrincipal.getVirtualGroups(); 090 if (origVGroups == null) { 091 origVGroups = new ArrayList<String>(); 092 } 093 094 // MERGE! 095 origVGroups.addAll(vGroups); 096 097 nuxPrincipal.setVirtualGroups(origVGroups); 098 099 // This a hack to work around the problem of running tests 100 if (!Framework.isTestModeSet()) { 101 nuxPrincipal.updateAllGroups(); 102 } else { 103 List<String> allGroups = nuxPrincipal.getGroups(); 104 for (String vGroup : vGroups) { 105 if (!allGroups.contains(vGroup)) { 106 allGroups.add(vGroup); 107 } 108 } 109 nuxPrincipal.setGroups(allGroups); 110 } 111 } 112 return principal; 113 } 114 115 @Override 116 public NuxeoGroup getGroup(String groupName) { 117 NuxeoGroup grp = super.getGroup(groupName); 118 if (activateComputedGroup() && (grp == null || getService().allowGroupOverride())) { 119 NuxeoGroup computed = getService().getComputedGroup(groupName, groupConfig); 120 if (computed != null) { 121 grp = computed; 122 } 123 } 124 return grp; 125 } 126 127 @Override 128 public NuxeoGroup getGroup(String groupName, DocumentModel context) { 129 NuxeoGroup grp = super.getGroup(groupName, context); 130 if (activateComputedGroup() && (grp == null || getService().allowGroupOverride())) { 131 NuxeoGroup computed = getService().getComputedGroup(groupName, groupConfig); 132 if (computed != null) { 133 grp = computed; 134 } 135 } 136 return grp; 137 } 138 139 @Override 140 public List<String> getGroupIds() { 141 List<String> ids = super.getGroupIds(); 142 if (activateComputedGroup()) { 143 List<String> vGroups = getService().computeGroupIds(); 144 for (String vGroup : vGroups) { 145 if (!ids.contains(vGroup)) { 146 ids.add(vGroup); 147 } 148 } 149 } 150 return ids; 151 } 152 153 @Override 154 public DocumentModel getGroupModel(String groupName) { 155 DocumentModel grpDoc = super.getGroupModel(groupName); 156 if (activateComputedGroup() && grpDoc == null) { 157 return getComputedGroupAsDocumentModel(groupName); 158 } 159 return grpDoc; 160 } 161 162 @Override 163 public DocumentModelList searchGroups(Map<String, Serializable> filter, Set<String> fulltext) 164 { 165 return searchGroups(filter, fulltext, null); 166 } 167 168 @Override 169 public DocumentModelList searchGroups(Map<String, Serializable> filter, Set<String> fulltext, DocumentModel context) 170 { 171 172 boolean searchInVirtualGroups = activateComputedGroup(); 173 if (Boolean.FALSE.equals(filter.get(VIRTUAL_GROUP_MARKER))) { 174 searchInVirtualGroups = false; 175 } 176 177 removeVirtualFilters(filter); 178 DocumentModelList groups = super.searchGroups(filter, fulltext, context); 179 180 if (searchInVirtualGroups) { 181 for (String vGroupName : getService().searchComputedGroups(filter, fulltext)) { 182 DocumentModel vGroup = getComputedGroupAsDocumentModel(vGroupName); 183 if (vGroup != null) { 184 if (!groups.contains(vGroup)) { 185 groups.add(vGroup); 186 } 187 } 188 } 189 } 190 return groups; 191 } 192 193 @Override 194 public DocumentModelList searchGroups(QueryBuilder queryBuilder) { 195 return searchGroups(queryBuilder, null); 196 } 197 198 @Override 199 public DocumentModelList searchGroups(QueryBuilder queryBuilder, DocumentModel context) { 200 // TODO find a way to pass a flag to allow callers do disable searching in virtual groups 201 DocumentModelList virtualEntries = new DocumentModelListImpl(); 202 for (String groupName : getService().searchComputedGroups(queryBuilder)) { 203 DocumentModel entry = getComputedGroupAsDocumentModel(groupName); 204 if (entry != null && !virtualEntries.contains(entry)) { 205 virtualEntries.add(entry); 206 } 207 } 208 if (virtualEntries.isEmpty()) { 209 // no computed groups match 210 return super.searchGroups(queryBuilder, context); 211 } else { 212 // we have some computed groups to add, we'll need to do limit/offset/order by post-filtering 213 queryBuilder = multiTenantManagement.groupQueryTransformer(this, queryBuilder, context); 214 try (Session session = dirService.open(groupDirectoryName, context)) { 215 return queryWithVirtualEntries(session, queryBuilder, virtualEntries); 216 } 217 } 218 } 219 220 protected DocumentModel getComputedGroupAsDocumentModel(String grpName) { 221 NuxeoGroup grp = getService().getComputedGroup(grpName, groupConfig); 222 if (grp == null) { 223 return null; 224 } 225 226 String schemaName = getGroupSchemaName(); 227 String id = getGroupIdField(); 228 DocumentModel groupDoc = BaseSession.createEntryModel(null, schemaName, grpName, null); 229 230 groupDoc.setProperty(schemaName, getGroupMembersField(), grp.getMemberUsers()); 231 groupDoc.setProperty(schemaName, id, grp.getName()); 232 groupDoc.setProperty(schemaName, getGroupIdField(), grp.getName()); 233 234 groupDoc.putContextData("virtual", Boolean.TRUE); 235 236 return groupDoc; 237 } 238 239 @Override 240 public DocumentModel createGroup(DocumentModel groupModel, DocumentModel context) { 241 if (activateComputedGroup()) { 242 String groupName = (String) groupModel.getProperty(groupConfig.schemaName, groupConfig.idField); 243 NuxeoGroup computed = getService().getComputedGroup(groupName, groupConfig); 244 if (computed != null) { 245 throw new NuxeoException("Cannot create a computed group"); 246 } 247 } 248 return super.createGroup(groupModel, context); 249 } 250 251 @Override 252 public void updateGroup(DocumentModel groupModel, DocumentModel context) { 253 if (activateComputedGroup()) { 254 String groupName = (String) groupModel.getProperty(groupConfig.schemaName, groupConfig.idField); 255 NuxeoGroup computed = getService().getComputedGroup(groupName, groupConfig); 256 if (computed != null) { 257 throw new NuxeoException("Cannot update a computed group"); 258 } 259 } 260 super.updateGroup(groupModel, context); 261 } 262 263 @Override 264 public void deleteGroup(String groupId, DocumentModel context) { 265 if (activateComputedGroup()) { 266 NuxeoGroup computed = getService().getComputedGroup(groupId, groupConfig); 267 if (computed != null) { 268 throw new NuxeoException("Cannot delete a computed group"); 269 } 270 } 271 super.deleteGroup(groupId, context); 272 } 273}