Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java (revision 1855908) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java (date 1553094061000) @@ -311,6 +311,7 @@ String oakPath = getOakPath(absPath); Util.checkValidPolicy(oakPath, policy); + Map principalMap = new HashMap<>(); if (policy instanceof PrincipalACL) { PrincipalACL principalAcl = (PrincipalACL) policy; for (ACE ace : principalAcl.getEntries()) { @@ -323,7 +324,7 @@ Iterator children = aclTree.getChildren().iterator(); while (children.hasNext()) { Tree child = children.next(); - if (ace.equals(createACE(path, child, principalAcl.rProvider))) { + if (ace.equals(createACE(path, child, principalAcl.rProvider, principalMap))) { child.remove(); } } @@ -469,9 +470,10 @@ } List entries = new ArrayList<>(); + Map principalMap = new HashMap<>(); for (Tree child : aclTree.getChildren()) { if (Util.isACE(child, ntMgr) && predicate.apply(child)) { - ACE ace = createACE(oakPath, child, restrictionProvider); + ACE ace = createACE(oakPath, child, restrictionProvider, principalMap); entries.add(ace); } } @@ -489,6 +491,7 @@ Result aceResult = searchAces(Collections.singleton(principal), root); RestrictionProvider restrProvider = new PrincipalRestrictionProvider(restrictionProvider); List entries = new ArrayList<>(); + Map principalMap = new HashMap<>(); for (ResultRow row : aceResult.getRows()) { Tree aceTree = root.getTree(row.getPath()); if (Util.isACE(aceTree, ntMgr)) { @@ -499,7 +502,7 @@ } else { path = Text.getRelativeParent(aclPath, 1); } - entries.add(createACE(path, aceTree, restrProvider)); + entries.add(createACE(path, aceTree, restrProvider, principalMap)); } } if (entries.isEmpty()) { @@ -513,11 +516,12 @@ @NotNull private ACE createACE(@Nullable String oakPath, @NotNull Tree aceTree, - @NotNull RestrictionProvider restrictionProvider) throws RepositoryException { + @NotNull RestrictionProvider restrictionProvider, + @NotNull Map principalMap) throws RepositoryException { boolean isAllow = NT_REP_GRANT_ACE.equals(TreeUtil.getPrimaryTypeName(aceTree)); Set restrictions = restrictionProvider.readRestrictions(oakPath, aceTree); Iterable privNames = checkNotNull(TreeUtil.getStrings(aceTree, REP_PRIVILEGES)); - return new Entry(getPrincipal(aceTree), bitsProvider.getBits(privNames), isAllow, restrictions, getNamePathMapper()); + return new Entry(getPrincipal(aceTree, principalMap), bitsProvider.getBits(privNames), isAllow, restrictions, getNamePathMapper()); } @NotNull @@ -554,9 +558,15 @@ } @NotNull - private Principal getPrincipal(@NotNull Tree aceTree) { + private Principal getPrincipal(@NotNull Tree aceTree, @NotNull Map principalMap) { String principalName = checkNotNull(TreeUtil.getString(aceTree, REP_PRINCIPAL_NAME)); - return new PrincipalImpl(principalName); + return principalMap.computeIfAbsent(principalName, pn -> { + Principal principal = principalManager.getPrincipal(pn); + if (principal == null) { + principal = new PrincipalImpl(pn); + } + return principal; + }); } private String getNodePath(ACE principalBasedAce) throws RepositoryException { Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java (revision 1855908) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java (date 1552987229000) @@ -27,6 +27,7 @@ import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager; import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy; import org.apache.jackrabbit.api.security.authorization.PrivilegeManager; +import org.apache.jackrabbit.api.security.principal.GroupPrincipal; import org.apache.jackrabbit.api.security.principal.PrincipalManager; import org.apache.jackrabbit.oak.AbstractSecurityTest; import org.apache.jackrabbit.oak.api.ContentSession; @@ -95,6 +96,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -1153,6 +1155,24 @@ } } + @Test + public void testGetPoliciesLimitsPrincipalLookup() throws Exception { + ACL policy = getApplicablePolicy(testPath); + policy.addAccessControlEntry(EveryonePrincipal.getInstance(), privilegesFromNames(PrivilegeConstants.JCR_READ)); + policy.addEntry(testPrincipal, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES, PrivilegeConstants.JCR_REMOVE_CHILD_NODES), true, ImmutableMap.of(REP_GLOB, getValueFactory(root).createValue(""))); + policy.addAccessControlEntry(testPrincipal, privilegesFromNames(PrivilegeConstants.JCR_REMOVE_NODE)); + acMgr.setPolicy(policy.getPath(), policy); + + // read policy again + policy = (ACL) acMgr.getPolicies(policy.getPath())[0]; + assertEquals(3, policy.size()); + AccessControlEntry[] entries = policy.getAccessControlEntries(); + // reading policies attempts to lookup principals (see OAK-xxx) + assertTrue(entries[0].getPrincipal() instanceof GroupPrincipal); + // reading policies must only lookup a given principal once + assertSame(entries[1].getPrincipal(), entries[2].getPrincipal()); + } + //---------------------------------------< getEffectivePolicies(String) >--- @Test public void testGetEffectivePoliciesNoPoliciesSet() throws Exception {