001/* 002 * (C) Copyright 2013 Nuxeo SA (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-2.1.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 * Martin Pernollet 016 */ 017 018package org.nuxeo.ecm.platform.groups.audit.service.acl.data; 019 020import java.util.HashSet; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024import org.nuxeo.ecm.core.api.DocumentModel; 025import org.nuxeo.ecm.core.api.security.ACE; 026import org.nuxeo.ecm.core.api.security.ACL; 027import org.nuxeo.ecm.core.api.security.ACP; 028import org.nuxeo.ecm.core.api.security.SecurityConstants; 029import org.nuxeo.ecm.platform.groups.audit.service.acl.Pair; 030import org.nuxeo.ecm.platform.groups.audit.service.acl.filter.IContentFilter; 031 032import com.google.common.collect.HashMultimap; 033import com.google.common.collect.Multimap; 034 035import static org.nuxeo.ecm.core.api.security.ACL.LOCAL_ACL; 036 037public class AclSummaryExtractor { 038 private static final Log log = LogFactory.getLog(AclSummaryExtractor.class); 039 040 protected IContentFilter filter; 041 042 public AclSummaryExtractor(IContentFilter filter) { 043 this.filter = filter; 044 } 045 046 /** 047 * Return a compact version of a document ACLs, e.g.: 048 * <ul> 049 * <li>user1 -> [(READ,true), (WRITE,false), (ADD_CHILDREN,false), ...] 050 * <li>user2 -> [(READ,true), (WRITE,true), (ADD_CHILDREN,true), ...] 051 * <li> 052 * </ul> 053 * Remark: content might be ignored according to the policy implemented by {@link IContentFilter}. 054 * 055 * @param doc 056 * @return 057 */ 058 public Multimap<String, Pair<String, Boolean>> getAllAclByUser(DocumentModel doc) { 059 ACP acp = doc.getACP(); 060 ACL[] acls = acp.getACLs(); 061 return getAclByUser(acls); 062 } 063 064 public Multimap<String, Pair<String, Boolean>> getAclLocalByUser(DocumentModel doc) { 065 ACP acp = doc.getACP(); 066 ACL acl = acp.getACL(LOCAL_ACL); 067 return getAclByUser(acl); 068 } 069 070 public Multimap<String, Pair<String, Boolean>> getAclInheritedByUser(DocumentModel doc) { 071 ACP acp = doc.getACP(); 072 ACL acl = acp.getACL(ACL.INHERITED_ACL); 073 return getAclByUser(acl); 074 } 075 076 public Multimap<String, Pair<String, Boolean>> getAclByUser(ACL[] acls) { 077 Multimap<String, Pair<String, Boolean>> aclByUser = HashMultimap.create(); 078 079 for (ACL acl : acls) { 080 fillAceByUser(aclByUser, acl); 081 } 082 return aclByUser; 083 } 084 085 public Multimap<String, Pair<String, Boolean>> getAclByUser(ACL acl) { 086 Multimap<String, Pair<String, Boolean>> aclByUser = HashMultimap.create(); 087 fillAceByUser(aclByUser, acl); 088 return aclByUser; 089 } 090 091 protected void fillAceByUser(Multimap<String, Pair<String, Boolean>> aclByUser, ACL acl) { 092 if (acl == null) 093 return; 094 for (ACE ace : acl.getACEs()) { 095 if (filter.acceptsUserOrGroup(ace.getUsername())) { 096 String userOrGroup = ace.getUsername(); 097 String permission = ace.getPermission(); 098 boolean allow = ace.isGranted(); 099 Pair<String, Boolean> pair = Pair.of(permission, allow); 100 aclByUser.put(userOrGroup, pair); 101 102 if (ace.isGranted() && ace.isDenied()) 103 log.warn("stupid state: ace granted and denied at the same time. Considered granted"); 104 } 105 } 106 } 107 108 /** 109 * Returns true if this document owns an ACE locking inheritance Remark: content might be ignored according to the 110 * policy implemented by {@link IContentFilter}. 111 * 112 * @see isLockInheritance(ACE) 113 * @param doc 114 * @return 115 */ 116 public boolean hasLockInheritanceACE(DocumentModel doc) { 117 // Fetch only local ACL to prevent from having blocking inheritance on 118 // all child. 119 ACL acl = doc.getACP().getOrCreateACL(LOCAL_ACL); 120 121 for (ACE ace : acl.getACEs()) { 122 if (filter.acceptsUserOrGroup(ace.getUsername())) { 123 if (isLockInheritance(ace)) 124 return true; 125 } 126 } 127 return false; 128 } 129 130 public boolean hasLockInheritanceACE(Multimap<String, Pair<String, Boolean>> acls) { 131 for (String user : acls.keySet()) { 132 for (Pair<String, Boolean> ace : acls.get(user)) { 133 if (SecurityConstants.EVERYONE.equals(user)) { 134 if (filter.acceptsUserOrGroup(user)) { 135 if (SecurityConstants.EVERYTHING.equals(ace.a) && !ace.b) 136 return true; 137 } 138 } 139 } 140 } 141 return false; 142 } 143 144 /** 145 * Return true if this ACE locks inheritance, in other word: 146 * <ul> 147 * <li>EVERYONE 148 * <li>EVERYTHING 149 * <li>deny 150 * </ul> 151 */ 152 public boolean isLockInheritance(ACE ace) { 153 return (SecurityConstants.EVERYONE.equals(ace.getUsername()) 154 && SecurityConstants.EVERYTHING.equals(ace.getPermission()) && ace.isDenied()); 155 } 156 157 public boolean isLockInheritance(String user, Pair<String, Boolean> ace) { 158 return (SecurityConstants.EVERYONE.equals(user) && SecurityConstants.EVERYTHING.equals(ace.a) && !ace.b); 159 } 160 161 /** 162 * Return the set of users and permissions mentionned in this document's ACLs. Remark: content might be ignored 163 * according to the policy implemented by {@link IContentFilter}. 164 * 165 * @param doc 166 * @return 167 */ 168 public Pair<HashSet<String>, HashSet<String>> getAclSummary(DocumentModel doc) { 169 Pair<HashSet<String>, HashSet<String>> summary = newSummary(); 170 ACP acp = doc.getACP(); 171 ACL[] acls = acp.getACLs(); 172 173 for (ACL acl : acls) { 174 for (ACE ace : acl.getACEs()) { 175 String userOrGroup = ace.getUsername(); 176 if (filter.acceptsUserOrGroup(userOrGroup)) { 177 String permission = ace.getPermission(); 178 summary.a.add(userOrGroup); 179 summary.b.add(permission); 180 } 181 } 182 } 183 return summary; 184 } 185 186 protected Pair<HashSet<String>, HashSet<String>> newSummary() { 187 return Pair.of(new HashSet<String>(), new HashSet<String>()); 188 } 189 190 public void printAce(DocumentModel doc) { 191 ACP acp = doc.getACP(); 192 ACL[] acls = acp.getACLs(); 193 194 for (ACL acl : acls) { 195 for (ACE ace : acl.getACEs()) { 196 System.out.println(ace); 197 } 198 } 199 } 200}