diff --git a/source/java/org/alfresco/repo/simple/permission/ACLImpl.java b/source/java/org/alfresco/repo/simple/permission/ACLImpl.java index 5cab211fc4..4cd732e4dd 100644 --- a/source/java/org/alfresco/repo/simple/permission/ACLImpl.java +++ b/source/java/org/alfresco/repo/simple/permission/ACLImpl.java @@ -37,154 +37,104 @@ import org.alfresco.service.simple.permission.ACL; import org.alfresco.service.simple.permission.CapabilityRegistry; /** - * Basic implementation of an ACL + * Basic implementation of a simple ACL. * @author britt */ public class ACLImpl implements ACL { - private static final long serialVersionUID = 5184311729355811095L; + private static final long serialVersionUID = -8720314753104805631L; + + /** + * Map of capabilities to authorities allowed. + */ + private Map> fAllowed; + + /** + * Map of capabilities to authorities denied. + */ + private Map> fDenied; /** - * The allowed entries for users. - */ - private Map> fUserAllows; - - /** - * The allowed entries for groups. - */ - private Map> fGroupAllows; - - /** - * The denied entries for users. - */ - private Map> fUserDenies; - - /** - * The denied entries for groups. - */ - private Map> fGroupDenies; - - /** - * Bit indicating whether a child (however that is defined) - * should inherit these permissions. + * Should this ACL be inherited. */ private boolean fInherit; + /** + * String (compact) representation of ACL. + */ + private String fStringRep; + + /** + * Reference to the authority service. + */ private transient AuthorityService fAuthorityService; + /** + * Reference to the capability registry. + */ private transient CapabilityRegistry fCapabilityRegistry; - private transient String fStringRep; - + /** + * Initialize a brand new one. + * @param inherit Should this ACL be inherited. + */ public ACLImpl(boolean inherit) { + fInherit = inherit; fAuthorityService = RawServices.Instance().getAuthorityService(); fCapabilityRegistry = RawServices.Instance().getCapabilityRegistry(); - fUserAllows = new HashMap>(); - fGroupAllows = new HashMap>(); - fUserDenies = new HashMap>(); - fGroupDenies = new HashMap>(); - fInherit = inherit; + fAllowed = new HashMap>(); + fDenied = new HashMap>(); fStringRep = null; } - public ACLImpl(String stringRep) + /** + * Initialize from an external string representation. + * @param rep + */ + public ACLImpl(String rep) { this(true); - fStringRep = stringRep; + fStringRep = rep; + } + + public ACLImpl(ACL other) + { + this(true); + fStringRep = other.getStringRepresentation(); } /* (non-Javadoc) * @see org.alfresco.service.simple.permission.ACL#allow(java.lang.String, java.lang.String[]) */ - public void allow(String agent, String... capabilities) + public void allow(String capability, String... authorities) { digest(); - AuthorityType type = AuthorityType.getAuthorityType(agent); - if (type == AuthorityType.ADMIN) + // First remove any explicit denies. + Set denied = fDenied.get(capability); + if (denied != null) { - return; - } - Set capDenied = null; - Set capAllowed = null; - switch (type) - { - case EVERYONE : - case GROUP : + for (String authority : authorities) { - capDenied = fGroupDenies.get(agent); - capAllowed = fGroupAllows.get(agent); - if (capAllowed == null) - { - capAllowed = new HashSet(); - fGroupAllows.put(agent, capAllowed); - } - break; - } - case ADMIN : - case USER : - case OWNER : - { - capDenied = fUserDenies.get(agent); - capAllowed = fUserAllows.get(agent); - if (capAllowed == null) - { - capAllowed = new HashSet(); - fUserAllows.put(agent, capAllowed); - } - break; - } - default : - { - // ignore. - return; + denied.remove(authority); } } - if (capDenied != null) + // Add the authorities to the allowed list. + Set allowed = fAllowed.get(capability); + if (allowed == null) { - for (String cap : capabilities) - { - capDenied.remove(cap); - capAllowed.add(cap); - } + allowed = new HashSet(); + fAllowed.put(capability, allowed); } - else + for (String authority : authorities) { - for (String cap : capabilities) - { - capAllowed.add(cap); - } + allowed.add(authority); } } - private void digestMap(String mapRep, Map> map) - { - String[] segments = mapRep.split(":"); - if (segments.length == 0 || segments[0].equals("")) - { - return; - } - for (String segment : segments) - { - String[] entrySeg = segment.split(";"); - if (entrySeg.length == 0 || entrySeg[0].equals("")) - { - continue; - } - Set caps = new HashSet(); - map.put(entrySeg[0], caps); - for (int i = 1; i < entrySeg.length; ++i) - { - String cap = fCapabilityRegistry.getCapabilityName(Integer.parseInt(entrySeg[i], 16)); - if (cap == null) - { - continue; - } - caps.add(cap); - } - } - } - + /** + * Helper to decode from the string representation. + */ private void digest() { if (fStringRep == null) @@ -192,186 +142,209 @@ public class ACLImpl implements ACL return; } String[] segments = fStringRep.split("\\|"); - fInherit = segments[0].equals("i") ? true : false; - digestMap(segments[1], fUserAllows); - digestMap(segments[2], fUserDenies); - digestMap(segments[3], fGroupAllows); - digestMap(segments[4], fGroupDenies); + fInherit = segments[0].equals("i"); + digestMap(segments[1], fAllowed); + digestMap(segments[2], fDenied); fStringRep = null; } - /* (non-Javadoc) - * @see org.alfresco.service.simple.permission.ACL#can(java.lang.String, java.lang.String) + /** + * Sub helper for decoding string representation. + * @param string The partial string representation. + * @param map The map to update. */ - public boolean can(String agent, String capability) + private void digestMap(String rep, Map> map) + { + String[] segments = rep.split(":"); + if (segments.length == 0 || segments[0].equals("")) + { + // This means there are no explicit entries. + return; + } + for (String entryRep : segments) + { + String[] entryRegs = entryRep.split(";"); + String capability = fCapabilityRegistry.getCapabilityName(Integer.parseInt(entryRegs[0], 16)); + Set authorities = new HashSet(); + map.put(capability, authorities); + for (int i = 1; i < entryRegs.length; ++i) + { + authorities.add(entryRegs[i]); + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.service.simple.permission.ACL#can(java.lang.String, boolean, java.lang.String) + */ + public boolean can(String authority, boolean isOwner, String capability) { digest(); - AuthorityType type = AuthorityType.getAuthorityType(agent); - // Admin trumps all. + AuthorityType type = AuthorityType.getAuthorityType(authority); + // Admin trumps. if (type == AuthorityType.ADMIN) { return true; } - // Next check for denied entries that apply. - Set denied = fUserDenies.get(agent); - if (denied == null) + // Look for denies first. + Set denied = fDenied.get(capability); + if (denied != null) { - denied = new HashSet(); - } - Set containing = fAuthorityService.getContainingAuthorities(null, agent, false); - Set found = fGroupDenies.get(agent); - if (found != null) - { - denied.addAll(found); - } - for (String container : containing) - { - found = fGroupDenies.get(container); - if (found != null) + if (denied.contains(authority)) { - denied.addAll(found); + return false; + } + for (String auth : denied) + { + if (fAuthorityService.getContainedAuthorities(null, auth, false).contains(authority)) + { + return false; + } } } - if (denied.contains(capability)) + // Now look for allows. + Set allowed = fAllowed.get(capability); + if (allowed != null) { - return false; - } - // Now go look for the alloweds. - Set allowed = fUserAllows.get(agent); - if (allowed == null) - { - allowed = new HashSet(); - } - found = fGroupAllows.get(agent); - if (found != null) - { - allowed.addAll(found); - } - for (String container : containing) - { - found = fGroupAllows.get(container); - if (found != null) + if (allowed.contains(authority)) { - allowed.addAll(found); + return true; + } + for (String auth : allowed) + { + if (fAuthorityService.getContainedAuthorities(null, auth, false).contains(authority)) + { + return true; + } } } - return allowed.contains(capability); + return false; } /* (non-Javadoc) * @see org.alfresco.service.simple.permission.ACL#deny(java.lang.String, java.lang.String[]) */ - public void deny(String agent, String ... capabilities) + public void deny(String capability, String ... authorities) { digest(); - AuthorityType type = AuthorityType.getAuthorityType(agent); - if (type == AuthorityType.ADMIN) - { - return; - } - Set allowed = fUserAllows.get(agent); + // Remove corresponding explicit allows. + Set allowed = fAllowed.get(capability); if (allowed != null) { - for (String cap : capabilities) + for (String authority : authorities) { - allowed.remove(cap); + allowed.remove(authority); } } - allowed = fGroupAllows.get(agent); - if (allowed != null) + // Now add denies. + Set denied = fDenied.get(capability); + if (denied == null) { - for (String cap : capabilities) - { - allowed.remove(cap); - } + denied = new HashSet(); + fDenied.put(capability, denied); } - Set denied = null; - switch (type) + for (String authority : authorities) { - case EVERYONE : - case GROUP : + if (AuthorityType.getAuthorityType(authority) == AuthorityType.ADMIN) { - denied = fGroupDenies.get(agent); - if (denied == null) - { - denied = new HashSet(); - fGroupDenies.put(agent, denied); - } - break; + continue; } - case OWNER : - case USER : - case GUEST : - { - denied = fUserDenies.get(agent); - if (denied == null) - { - denied = new HashSet(); - fUserDenies.put(agent, denied); - } - break; - } - default : - { - // Cop Out! - return; - } - } - for (String cap : capabilities) - { - denied.add(cap); + denied.add(authority); } } /* (non-Javadoc) - * @see org.alfresco.service.simple.permission.ACL#getCapabilities(java.lang.String) + * @see org.alfresco.service.simple.permission.ACL#getAllowed(java.lang.String) */ - public Set getCapabilities(String agent) + public Set getAllowed(String capability) { digest(); - AuthorityType type = AuthorityType.getAuthorityType(agent); + Set allowed = new HashSet(); + allowed.add(AuthorityType.ADMIN.getFixedString()); + // Add the explicitly allowed. + Set expAllowed = fAllowed.get(capability); + if (expAllowed == null) + { + return allowed; + } + allowed.addAll(expAllowed); + for (String authority : expAllowed) + { + allowed.addAll(fAuthorityService.getContainedAuthorities(null, authority, false)); + } + // Now remove based on denials. + Set denied = fDenied.get(capability); + if (denied == null) + { + return allowed; + } + allowed.removeAll(denied); + // Now those that are indirectly denied. + for (String authority : denied) + { + allowed.removeAll(fAuthorityService.getContainedAuthorities(null, authority, false)); + } + return allowed; + } + + /* (non-Javadoc) + * @see org.alfresco.service.simple.permission.ACL#getCapabilities(java.lang.String, boolean) + */ + public Set getCapabilities(String authority, boolean isOwner) + { + digest(); + AuthorityType type = AuthorityType.getAuthorityType(authority); if (type == AuthorityType.ADMIN) { return fCapabilityRegistry.getAll(); } - // First add in all the possible capabilities from the allow sets. Set capabilities = new HashSet(); - Set found = fUserAllows.get(agent); - if (found != null) + // First run through the allowed entries. + Set containers = null; + for (Map.Entry> entry : fAllowed.entrySet()) { - capabilities.addAll(found); - } - found = fGroupAllows.get(agent); - if (found != null) - { - capabilities.addAll(found); - } - Set containers = fAuthorityService.getContainingAuthorities(null, agent, false); - for (String container : containers) - { - found = fGroupAllows.get(container); - if (found != null) + if (entry.getValue().contains(authority)) { - capabilities.addAll(found); + capabilities.add(entry.getKey()); + continue; + } + if (containers == null) + { + containers = fAuthorityService.getContainingAuthorities(null, authority, false); + } + for (String auth : containers) + { + if (entry.getValue().contains(auth)) + { + capabilities.add(entry.getKey()); + break; + } } } - // Now remove everything that's denied. - found = fUserDenies.get(agent); - if (found != null) + // Now go through the denials. + for (Map.Entry> entry : fDenied.entrySet()) { - capabilities.removeAll(found); - } - found = fGroupDenies.get(agent); - if (found != null) - { - capabilities.removeAll(found); - } - for (String container : containers) - { - found = fGroupDenies.get(container); - if (found != null) + if (!capabilities.contains(entry.getKey())) { - capabilities.removeAll(found); + continue; + } + Set denied = entry.getValue(); + if (denied.contains(authority)) + { + capabilities.remove(entry.getKey()); + continue; + } + if (containers == null) + { + containers = fAuthorityService.getContainingAuthorities(null, authority, false); + } + for (String auth : containers) + { + if (denied.contains(auth)) + { + capabilities.remove(entry.getKey()); + break; + } } } return capabilities; @@ -390,72 +363,30 @@ public class ACLImpl implements ACL builder.append(fInherit ? 'i' : 'n'); builder.append('|'); int count = 0; - for (Map.Entry> entry : fUserAllows.entrySet()) + for (Map.Entry> entry : fAllowed.entrySet()) { - builder.append(entry.getKey()); - if (entry.getValue().size() != 0) + builder.append(Integer.toString(fCapabilityRegistry.getCapabilityID(entry.getKey()), 16)); + for (String authority : entry.getValue()) { - for (String cap : entry.getValue()) - { - builder.append(';'); - builder.append(Integer.toString(fCapabilityRegistry.getCapabilityID(cap), 16)); - } + builder.append(';'); + builder.append(authority); } - if (count++ < fUserAllows.size() - 1) + if (count++ < fAllowed.size() - 1) { builder.append(':'); } } builder.append('|'); count = 0; - for (Map.Entry> entry : fUserDenies.entrySet()) + for (Map.Entry> entry : fDenied.entrySet()) { - builder.append(entry.getKey()); - if (entry.getValue().size() != 0) + builder.append(Integer.toString(fCapabilityRegistry.getCapabilityID(entry.getKey()), 16)); + for (String authority : entry.getValue()) { - for (String cap : entry.getValue()) - { - builder.append(';'); - builder.append(Integer.toString(fCapabilityRegistry.getCapabilityID(cap), 16)); - } + builder.append(';'); + builder.append(authority); } - if (count++ < fUserDenies.size() - 1) - { - builder.append(':'); - } - } - builder.append('|'); - count = 0; - for (Map.Entry> entry : fGroupAllows.entrySet()) - { - builder.append(entry.getKey()); - if (entry.getValue().size() != 0) - { - for (String cap : entry.getValue()) - { - builder.append(';'); - builder.append(Integer.toString(fCapabilityRegistry.getCapabilityID(cap), 16)); - } - } - if (count++ < fGroupAllows.size() - 1) - { - builder.append(':'); - } - } - builder.append('|'); - count = 0; - for (Map.Entry> entry : fGroupDenies.entrySet()) - { - builder.append(entry.getKey()); - if (entry.getValue().size() != 0) - { - for (String cap : entry.getValue()) - { - builder.append(';'); - builder.append(Integer.toString(fCapabilityRegistry.getCapabilityID(cap), 16)); - } - } - if (count++ < fGroupDenies.size() - 1) + if (count++ < fDenied.size() - 1) { builder.append(':'); } @@ -468,15 +399,7 @@ public class ACLImpl implements ACL */ public boolean inherits() { + digest(); return fInherit; } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - return "[" + getStringRepresentation() + "]"; - } } diff --git a/source/java/org/alfresco/repo/simple/permission/ACLTest.java b/source/java/org/alfresco/repo/simple/permission/ACLTest.java index 14b62aae28..d27cf93a37 100644 --- a/source/java/org/alfresco/repo/simple/permission/ACLTest.java +++ b/source/java/org/alfresco/repo/simple/permission/ACLTest.java @@ -116,24 +116,25 @@ public class ACLTest extends TestCase { System.out.println(fCapabilityRegistry.getAll()); ACL acl = new ACLImpl(true); - acl.allow("GROUP_Scoobies", "read", "write", "delete", "shimmy"); - acl.deny("Xander", "delete"); - acl.allow("Tara", "shake"); - acl.allow("GROUP_vampires", "read", "write", "delete", "shimmy", "shake"); - acl.deny("Spike", "shake"); - acl.deny("GROUP_soulless", "delete"); - System.out.println(acl.getCapabilities("Spike")); - System.out.println(acl.getCapabilities("Tara")); - System.out.println(acl.getCapabilities("Xander")); - System.out.println(acl.getCapabilities("Buffy")); + acl.allow("read", "GROUP_Scoobies", "GROUP_vampires"); + acl.allow("write", "GROUP_Scoobies", "GROUP_vampires"); + acl.allow("delete", "GROUP_Scoobies", "GROUP_vampires"); + acl.allow("shimmy", "GROUP_Scoobies", "GROUP_vampires"); + acl.allow("shake", "GROUP_vampires", "Tara"); + acl.deny("delete", "Xander", "GROUP_soulless"); + acl.deny("shake", "Spike"); + System.out.println(acl.getCapabilities("Spike", false)); + System.out.println(acl.getCapabilities("Tara", false)); + System.out.println(acl.getCapabilities("Xander", false)); + System.out.println(acl.getCapabilities("Buffy", false)); String stringRep = acl.getStringRepresentation(); System.out.println(stringRep); ACL acl2 = new ACLImpl(stringRep); System.out.println(acl2.getStringRepresentation()); - System.out.println(acl2.getCapabilities("Spike")); - System.out.println(acl2.getCapabilities("Tara")); - System.out.println(acl2.getCapabilities("Xander")); - System.out.println(acl2.getCapabilities("Buffy")); + System.out.println(acl2.getCapabilities("Spike", false)); + System.out.println(acl2.getCapabilities("Tara", false)); + System.out.println(acl2.getCapabilities("Xander", false)); + System.out.println(acl2.getCapabilities("Buffy", false)); System.out.println(acl2.getStringRepresentation()); } catch (Exception e) diff --git a/source/java/org/alfresco/repo/simple/permission/CapabilityRegistryImpl.java b/source/java/org/alfresco/repo/simple/permission/CapabilityRegistryImpl.java index 60e56cb057..27ee8f0762 100644 --- a/source/java/org/alfresco/repo/simple/permission/CapabilityRegistryImpl.java +++ b/source/java/org/alfresco/repo/simple/permission/CapabilityRegistryImpl.java @@ -26,6 +26,7 @@ package org.alfresco.repo.simple.permission; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -61,7 +62,7 @@ public class CapabilityRegistryImpl implements CapabilityRegistry /* (non-Javadoc) * @see org.alfresco.service.simple.permission.CapabilityRegistry#addCapability(java.lang.String) */ - public void addCapability(String capability) + public synchronized void addCapability(String capability) { // TODO Make this do something in the future. } @@ -69,15 +70,15 @@ public class CapabilityRegistryImpl implements CapabilityRegistry /* (non-Javadoc) * @see org.alfresco.service.simple.permission.CapabilityRegistry#getAll() */ - public Set getAll() + public synchronized Set getAll() { - return fCapabilityToID.keySet(); + return new HashSet(fCapabilityToID.keySet()); } /* (non-Javadoc) * @see org.alfresco.service.simple.permission.CapabilityRegistry#getCapabilityID(java.lang.String) */ - public int getCapabilityID(String capability) + public synchronized int getCapabilityID(String capability) { Integer id = fCapabilityToID.get(capability); if (id == null) @@ -90,7 +91,7 @@ public class CapabilityRegistryImpl implements CapabilityRegistry /* (non-Javadoc) * @see org.alfresco.service.simple.permission.CapabilityRegistry#getCapabilityName(int) */ - public String getCapabilityName(int id) + public synchronized String getCapabilityName(int id) { return fIDToCapability.get(id); } @@ -98,7 +99,7 @@ public class CapabilityRegistryImpl implements CapabilityRegistry /* (non-Javadoc) * @see org.alfresco.service.simple.permission.CapabilityRegistry#removeCapability(java.lang.String) */ - public void removeCapability(String capability) + public synchronized void removeCapability(String capability) { // TODO Make this persistent. Integer removed = fCapabilityToID.remove(capability); diff --git a/source/java/org/alfresco/service/simple/permission/ACL.java b/source/java/org/alfresco/service/simple/permission/ACL.java index bfe6f2c2e7..f8a7da7daf 100644 --- a/source/java/org/alfresco/service/simple/permission/ACL.java +++ b/source/java/org/alfresco/service/simple/permission/ACL.java @@ -26,12 +26,11 @@ package org.alfresco.service.simple.permission; import java.io.Serializable; -import java.util.List; import java.util.Set; /** * Interface for ACLs. ACLs express the capabilities granted to - * different agents (users, groups, or roles (one hopes that roles can go away as they are + * different authorities (users, groups, or roles (one hopes that roles can go away as they are * operationally just another name for a group)). ACLs contain explicit entries made of * a capability and a list of agents plus an indication of whether the entry denies or allows * the capability. Entries that deny override any entries that allow. @@ -40,35 +39,44 @@ import java.util.Set; public interface ACL extends Serializable { /** - * Insert an allow entry for the agent, capabilities combination. - * Removes a denials explicitly for the agent and capabilities given. - * @param agent The agent, (user, group, role) - * @param capabilities The capabilities being granted. + * Insert an allow entry. + * Removes any denials explicitly for the authorities and capability given. + * @param capability The capability to grant. + * @param authorities The authorities granted the capability. */ - public void allow(String agent, String ... capabilities); + public void allow(String capability, String ... authorities); /** - * Insert a deny entry for the agent, capabilities combination. - * Removes an allow explicitly for the agent and capabilities given. - * @param agent The agent, (user, group, role) - * @param capabilities + * Insert a deny entry. + * Removes any allows explicitly for the authorities and capability given. + * @param capability The capability to deny. + * @param authorities The authorities to deny. */ - public void deny(String agent, String ... capabilities); + public void deny(String capability, String ... authorities); /** - * Does the given agent have the given capability - * @param agent The agent (user) + * Does the given authority have the given capability + * @param authority The authority (user) + * @param isOwner Is the authority the owner of the controlled entity. * @param capability The capability. - * @return Whether the agent can. + * @return Whether the authority can. */ - public boolean can(String agent, String capability); + public boolean can(String authority, boolean isOwner, String capability); /** - * Get the capabilities for the given agent. - * @param agent The agent. + * Get the capabilities for the given authority. + * @param authority The authority. + * @param isOwner is the authority the owner of the controlled entity. * @return A set of capabilities. */ - public Set getCapabilities(String agent); + public Set getCapabilities(String authority, boolean isOwner); + + /** + * Get the authorities with the given capability. + * @param capability The capability under consideration. + * @return The set of authorities. + */ + public Set getAllowed(String capability); /** * Get a string representation of this ACL, suitable for persistence.