001/* 002 * (C) Copyright 2006-2018 Nuxeo (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 * bstefanescu 018 */ 019package org.nuxeo.ecm.automation.features; 020 021import java.util.HashSet; 022import java.util.Set; 023 024import org.apache.commons.lang3.StringUtils; 025import org.nuxeo.ecm.core.api.DocumentModel; 026import org.nuxeo.ecm.core.api.NuxeoGroup; 027import org.nuxeo.ecm.core.api.NuxeoPrincipal; 028import org.nuxeo.ecm.core.api.security.ACE; 029import org.nuxeo.ecm.core.api.security.ACL; 030import org.nuxeo.ecm.core.api.security.ACP; 031import org.nuxeo.ecm.core.api.security.PermissionProvider; 032import org.nuxeo.ecm.core.api.security.SecurityConstants; 033import org.nuxeo.ecm.platform.usermanager.UserManager; 034 035/** 036 * Provides helper methods to find extract permissions/principals info from documents. 037 * 038 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 039 * @author Anahide Tchertchian 040 */ 041public class PrincipalHelper { 042 043 protected UserManager userManager; 044 045 protected PermissionProvider permissionProvider; 046 047 public PrincipalHelper(UserManager userManager, PermissionProvider permissionProvider) { 048 this.userManager = userManager; 049 this.permissionProvider = permissionProvider; 050 } 051 052 @SuppressWarnings("unchecked") 053 public Set<String> getEmailsForPermission(DocumentModel input, String permission, boolean ignoreGroups) { 054 return (Set<String>) collectObjectsMatchingPermission(input, permission, ignoreGroups, true, 055 new EmailCollector(userManager.getUserSchemaName(), userManager.getUserEmailField())); 056 } 057 058 /** 059 * Resolves the list of identifiers for users and groups who have the given permission on given document. 060 * 061 * @param input document model to resolve users and groups on. 062 * @param permission the permission to check 063 * @param ignoreGroups if true, will ignore groups in resolution of ids 064 * @param resolveGroups if true, will resolve user members, iterating in the hierarchy of groups 065 * @param prefixIds if true, will prefix identifiers with {@link NuxeoPrincipal#PREFIX} and 066 * {@link NuxeoGroup#PREFIX} 067 */ 068 @SuppressWarnings("unchecked") 069 public Set<String> getUserAndGroupIdsForPermission(DocumentModel input, String permission, boolean ignoreGroups, 070 boolean resolveGroups, boolean prefixIds) { 071 return (Set<String>) collectObjectsMatchingPermission(input, permission, ignoreGroups, resolveGroups, 072 new IdCollector(prefixIds)); 073 } 074 075 @SuppressWarnings("unchecked") 076 public Set<NuxeoPrincipal> getPrincipalsForPermission(DocumentModel input, String permission, boolean ignoreGroups, 077 boolean resolveGroups) { 078 return (Set<NuxeoPrincipal>) collectObjectsMatchingPermission(input, permission, ignoreGroups, resolveGroups, 079 new PrincipalCollector()); 080 } 081 082 public Set<String> getEmailsFromGroup(String groupId, boolean resolveGroups) { 083 EmailCollector collector = new EmailCollector(userManager.getUserSchemaName(), userManager.getUserEmailField()); 084 collectObjectsFromGroup(groupId, resolveGroups, collector); 085 return collector.getResult(); 086 } 087 088 public Set<NuxeoPrincipal> getPrincipalsFromGroup(String groupId, boolean resolveGroups) { 089 PrincipalCollector collector = new PrincipalCollector(); 090 collectObjectsFromGroup(groupId, resolveGroups, collector); 091 return collector.getResult(); 092 } 093 094 public Set<String> getUserNamesFromGroup(String groupId, boolean resolveGroups, boolean prefixIds) { 095 IdCollector collector = new IdCollector(prefixIds); 096 collectObjectsFromGroup(groupId, resolveGroups, collector); 097 return collector.getResult(); 098 } 099 100 public void collectObjectsFromGroup(String groupId, boolean resolveGroups, Collector<?> collector) { 101 NuxeoGroup group = userManager.getGroup(groupId); 102 if (group == null) { 103 userManager.getPrincipal(groupId); 104 } else { 105 for (String u : group.getMemberUsers()) { 106 NuxeoPrincipal principal = userManager.getPrincipal(u); 107 if (principal != null) { 108 collector.collect(principal); 109 } 110 } 111 if (resolveGroups) { 112 for (String g : group.getMemberGroups()) { 113 collectObjectsFromGroup(g, resolveGroups, collector); 114 } 115 } 116 } 117 } 118 119 public HashSet<?> collectObjectsMatchingPermission(DocumentModel input, String permission, boolean ignoreGroups, 120 boolean resolveGroups, Collector<?> collector) { 121 String[] perms = getPermissionsToCheck(permission); 122 ACP acp = input.getACP(); 123 for (ACL acl : acp.getACLs()) { 124 for (ACE ace : acl.getACEs()) { 125 if (ace.isGranted() && permissionMatch(perms, ace.getPermission())) { 126 NuxeoGroup group = userManager.getGroup(ace.getUsername()); 127 if (group == null) { 128 // this may be a user 129 collector.collect(userManager.getPrincipal(ace.getUsername())); 130 } else if (!ignoreGroups) { 131 if (resolveGroups) { 132 resolveGroups(group, collector); 133 } else { 134 collector.collect(group); 135 } 136 } 137 } 138 } 139 } 140 return collector.getResult(); 141 } 142 143 public void resolveGroups(NuxeoGroup group, Collector<?> collector) { 144 if (group != null) { 145 for (String memberUser : group.getMemberUsers()) { 146 collector.collect(userManager.getPrincipal(memberUser)); 147 } 148 for (String subGroup : group.getMemberGroups()) { 149 resolveGroups(userManager.getGroup(subGroup), collector); 150 } 151 } 152 } 153 154 public String[] getPermissionsToCheck(String permission) { 155 String[] groups = permissionProvider.getPermissionGroups(permission); 156 if (groups == null) { 157 return new String[] { permission, SecurityConstants.EVERYTHING }; 158 } else { 159 String[] perms = new String[groups.length + 2]; 160 perms[0] = permission; 161 System.arraycopy(groups, 0, perms, 1, groups.length); 162 perms[groups.length + 1] = SecurityConstants.EVERYTHING; 163 return perms; 164 } 165 } 166 167 public boolean permissionMatch(String[] perms, String perm) { 168 for (String p : perms) { 169 if (p.equals(perm)) { 170 return true; 171 } 172 } 173 return false; 174 } 175 176 interface Collector<T> { 177 178 void collect(NuxeoPrincipal principal); 179 180 void collect(NuxeoGroup group); 181 182 HashSet<T> getResult(); 183 } 184 185 public static class EmailCollector implements Collector<String> { 186 187 protected final String userSchemaName; 188 189 protected final String userEmailFieldName; 190 191 protected HashSet<String> result = new HashSet<>(); 192 193 EmailCollector(String userSchemaName, String userEmailFieldName) { 194 this.userSchemaName = userSchemaName; 195 this.userEmailFieldName = userEmailFieldName; 196 } 197 198 @Override 199 public void collect(NuxeoPrincipal principal) { 200 if (principal == null) { 201 return; 202 } 203 DocumentModel userEntry = principal.getModel(); 204 String email = (String) userEntry.getProperty(userSchemaName, userEmailFieldName); 205 if (!StringUtils.isEmpty(email)) { 206 result.add(email); 207 } 208 } 209 210 @Override 211 public void collect(NuxeoGroup group) { 212 // do nothing 213 } 214 215 @Override 216 public HashSet<String> getResult() { 217 return result; 218 } 219 } 220 221 static class PrincipalCollector implements Collector<NuxeoPrincipal> { 222 223 protected HashSet<NuxeoPrincipal> result = new HashSet<>(); 224 225 @Override 226 public void collect(NuxeoPrincipal principal) { 227 if (principal == null) { 228 return; 229 } 230 result.add(principal); 231 } 232 233 @Override 234 public void collect(NuxeoGroup group) { 235 // do nothing 236 } 237 238 @Override 239 public HashSet<NuxeoPrincipal> getResult() { 240 return result; 241 } 242 } 243 244 static class IdCollector implements Collector<String> { 245 246 protected final boolean prefixIds; 247 248 protected HashSet<String> result = new HashSet<>(); 249 250 IdCollector(boolean prefixIds) { 251 this.prefixIds = prefixIds; 252 } 253 254 @Override 255 public void collect(NuxeoPrincipal principal) { 256 if (principal != null) { 257 String name = principal.getName(); 258 if (name != null) { 259 if (prefixIds) { 260 result.add(NuxeoPrincipal.PREFIX + name); 261 } else { 262 result.add(name); 263 } 264 } 265 } 266 } 267 268 @Override 269 public void collect(NuxeoGroup group) { 270 if (group != null) { 271 String name = group.getName(); 272 if (name != null) { 273 if (prefixIds) { 274 result.add(NuxeoGroup.PREFIX + name); 275 } else { 276 result.add(name); 277 } 278 } 279 } 280 } 281 282 @Override 283 public HashSet<String> getResult() { 284 return result; 285 } 286 287 } 288 289}