This is an automated email from the ASF dual-hosted git repository.

bdelacretaz pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git


The following commit(s) were added to refs/heads/master by this push:
     new bd3e865  SLING-9090 - apply patch provided by angela, with minor 
changes, thanks!
bd3e865 is described below

commit bd3e865442ffbf02722a5f36020ca75dab4906f6
Author: Bertrand Delacretaz <[email protected]>
AuthorDate: Fri Feb 12 14:08:32 2021 +0100

    SLING-9090 - apply patch provided by angela, with minor changes, thanks!
---
 .../apache/sling/jcr/repoinit/impl/AclUtil.java    |  90 ++++++--
 .../apache/sling/jcr/repoinit/impl/AclVisitor.java |  44 ++--
 .../apache/sling/jcr/repoinit/GeneralAclTest.java  |   3 +-
 .../sling/jcr/repoinit/PrincipalBasedAclTest.java  | 256 +++++++++++++++++++--
 .../org/apache/sling/jcr/repoinit/RemoveTest.java  | 173 ++++++++++++++
 5 files changed, 505 insertions(+), 61 deletions(-)

diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java 
b/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java
index a57a042..90d1bfe 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java
@@ -47,6 +47,7 @@ import org.apache.jackrabbit.util.Text;
 import org.apache.sling.repoinit.parser.operations.AclLine;
 import org.apache.sling.repoinit.parser.operations.RestrictionClause;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -165,8 +166,33 @@ public class AclUtil {
         setAcl(session, principals, (String)null, privileges, isAllow, 
restrictionClauses);
     }
 
+    public static void removeEntries(@NotNull Session session, @NotNull 
List<String> principals, @NotNull List<String> paths) throws 
RepositoryException {
+        Set<String> principalNames = new HashSet<>(principals);
+        for (String jcrPath : getJcrPaths(session, paths)) {
+            if (jcrPath != null && !session.nodeExists(jcrPath)) {
+                LOG.info("Cannot remove access control entries on non-existent 
path {}", jcrPath);
+            } else {
+                JackrabbitAccessControlList acl = 
AccessControlUtils.getAccessControlList(session, jcrPath);
+                if (acl != null) {
+                    boolean modified = false;
+                    for (AccessControlEntry ace : 
acl.getAccessControlEntries()) {
+                        if 
(principalNames.contains(ace.getPrincipal().getName())) {
+                            acl.removeAccessControlEntry(ace);
+                            modified = true;
+                        }
+                    }
+                    if (modified) {
+                        session.getAccessControlManager().setPolicy(jcrPath, 
acl);
+                    }
+                } else {
+                    LOG.info("Cannot remove access control entries for 
principal(s) {}. No ACL at {}", principalNames, jcrPath);
+                }
+            }
+        }
+    }
+
     public static void setPrincipalAcl(Session session, String principalName, 
Collection<AclLine> lines) throws RepositoryException {
-        JackrabbitAccessControlManager acMgr = getJACM(session);
+        final JackrabbitAccessControlManager acMgr = getJACM(session);
         Principal principal = AccessControlUtils.getPrincipal(session, 
principalName);
         if (principal == null) {
             // due to transient nature of the repo-init the principal lookup 
may not succeed if completed through query
@@ -176,29 +202,35 @@ public class AclUtil {
             checkState(principal != null, "Principal not found: " + 
principalName);
         }
 
-        PrincipalAccessControlList acl = getPrincipalAccessControlList(acMgr, 
principal);
+        final PrincipalAccessControlList acl = 
getPrincipalAccessControlList(acMgr, principal);
         boolean modified = false;
         for (AclLine line : lines) {
-            if (line.getAction() == AclLine.Action.DENY) {
+            AclLine.Action action = line.getAction();
+            if (action == AclLine.Action.DENY) {
                 throw new AccessControlException("PrincipalAccessControlList 
doesn't support 'deny' entries.");
-            }
-            Privilege[] privileges = 
AccessControlUtils.privilegesFromNames(session, 
line.getProperty(PROP_PRIVILEGES).toArray(new String[0]));
-            for (String effectivePath : getJcrPaths(session, 
line.getProperty(PROP_PATHS))) {
-                if (acl == null) {
-                    // no PrincipalAccessControlList available: don't fail if 
an equivalent path-based entry with the same definition exists
-                    // or if there exists no node at the effective path 
(unable to evaluate path-based entries).
-                    LOG.info("No PrincipalAccessControlList available for 
principal {}", principal);
-                    if (!containsEquivalentEntry(session, effectivePath, 
principal, privileges, true, line.getRestrictions())) {
-                        LOG.warn("No equivalent path-based entry exists for 
principal {} and effective path {} ", principal.getName(), effectivePath);
-                        return;
-                    }
-                } else {
-                    LocalRestrictions restrictions = 
createLocalRestrictions(line.getRestrictions(), acl, session);
-                    boolean added = acl.addEntry(effectivePath, privileges, 
restrictions.getRestrictions(), restrictions.getMVRestrictions());
-                    if (!added) {
-                        LOG.info("Equivalent principal-based entry already 
exists for principal {} and effective path {} ", principalName, effectivePath);
+            } else if (action == AclLine.Action.REMOVE) {
+                throw new RuntimeException(AclLine.Action.REMOVE + " is not 
supported");
+            } else if (action == AclLine.Action.REMOVE_ALL) {
+                modified = removePrincipalEntries(acl, principalName, 
getJcrPaths(session, line.getProperty(PROP_PATHS)));
+            } else {
+                final Privilege[] privileges = 
AccessControlUtils.privilegesFromNames(session, 
line.getProperty(PROP_PRIVILEGES).toArray(new String[0]));
+                for (String effectivePath : getJcrPaths(session, 
line.getProperty(PROP_PATHS))) {
+                    if (acl == null) {
+                        // no PrincipalAccessControlList available: don't fail 
if an equivalent path-based entry with the same definition exists
+                        // or if there exists no node at the effective path 
(unable to evaluate path-based entries).
+                        LOG.info("No PrincipalAccessControlList available for 
principal {}", principal);
+                        if (!containsEquivalentEntry(session, effectivePath, 
principal, privileges, true, line.getRestrictions())) {
+                            LOG.warn("No equivalent path-based entry exists 
for principal {} and effective path {} ", principal.getName(), effectivePath);
+                            return;
+                        }
                     } else {
-                        modified = true;
+                        final LocalRestrictions restrictions = 
createLocalRestrictions(line.getRestrictions(), acl, session);
+                        final boolean added = acl.addEntry(effectivePath, 
privileges, restrictions.getRestrictions(), restrictions.getMVRestrictions());
+                        if (!added) {
+                            LOG.info("Equivalent principal-based entry already 
exists for principal {} and effective path {} ", principalName, effectivePath);
+                        } else {
+                            modified = true;
+                        }
                     }
                 }
             }
@@ -227,6 +259,24 @@ public class AclUtil {
         return acl;
     }
 
+    private static boolean removePrincipalEntries(@Nullable 
PrincipalAccessControlList acl, @NotNull String principalName, @NotNull 
List<String> paths) throws RepositoryException {
+        boolean modified = false;
+        if (acl == null) {
+            LOG.info("Cannot remove entries for paths(s) {}. No 
principal-based ACL for {}", paths, principalName);
+        } else {
+            for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+                if (ace instanceof PrincipalAccessControlList.Entry) {
+                    PrincipalAccessControlList.Entry entry = 
(PrincipalAccessControlList.Entry) ace;
+                    if (paths.contains(entry.getEffectivePath())) {
+                        acl.removeAccessControlEntry(ace);
+                        modified = true;
+                    }
+                }
+            }
+        }
+        return modified;
+    }
+
     @NotNull
     private static List<String> getJcrPaths(@NotNull Session session, @NotNull 
List<String> paths) throws RepositoryException {
         List<String> jcrPaths = new ArrayList<>(paths.size());
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java 
b/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
index b1a0c57..965bd80 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
@@ -20,6 +20,7 @@ import static 
org.apache.sling.repoinit.parser.operations.AclLine.PROP_PATHS;
 import static 
org.apache.sling.repoinit.parser.operations.AclLine.PROP_PRINCIPALS;
 import static 
org.apache.sling.repoinit.parser.operations.AclLine.PROP_PRIVILEGES;
 
+import java.util.Collections;
 import java.util.List;
 
 import javax.jcr.Node;
@@ -55,21 +56,35 @@ class AclVisitor extends DoNothingVisitor {
         return result;
     }
 
-    private void setAcl(AclLine line, Session s, List<String> principals, 
List<String> paths, List<String> privileges, boolean isAllow) {
+    private void setAcl(AclLine line, Session s, List<String> principals, 
List<String> paths, List<String> privileges, AclLine.Action action) {
         try {
-            log.info("Adding ACL '{}' entry '{}' for {} on {}", isAllow ? 
"allow" : "deny", privileges, principals, paths);
-            List<RestrictionClause> restrictions = line.getRestrictions();
-            AclUtil.setAcl(s, principals, paths, privileges, isAllow, 
restrictions);
+            if (action == AclLine.Action.REMOVE) {
+                throw new RuntimeException("remove not supported");
+            } else if (action == AclLine.Action.REMOVE_ALL) {
+                AclUtil.removeEntries(s, principals, paths);
+            } else {
+                final boolean isAllow = 
line.getAction().equals(AclLine.Action.ALLOW);
+                log.info("Adding ACL '{}' entry '{}' for {} on {}", isAllow ? 
"allow" : "deny", privileges, principals, paths);
+                List<RestrictionClause> restrictions = line.getRestrictions();
+                AclUtil.setAcl(s, principals, paths, privileges, isAllow, 
restrictions);
+            }
         } catch(Exception e) {
             throw new RuntimeException("Failed to set ACL (" + e.toString() + 
") " + line, e);
         }
     }
 
-    private void setRepositoryAcl(AclLine line, Session s, List<String> 
principals, List<String> privileges, boolean isAllow) {
+    private void setRepositoryAcl(AclLine line, Session s, List<String> 
principals, List<String> privileges, AclLine.Action action) {
         try {
-            log.info("Adding repository level ACL '{}' entry '{}' for {}", 
isAllow ? "allow" : "deny", privileges, principals);
-            List<RestrictionClause> restrictions = line.getRestrictions();
-            AclUtil.setRepositoryAcl(s, principals, privileges, isAllow, 
restrictions);
+            if (action == AclLine.Action.REMOVE) {
+                throw new RuntimeException("remove not supported");
+            } else if (action == AclLine.Action.REMOVE_ALL) {
+                AclUtil.removeEntries(s, principals, 
Collections.singletonList(null));
+            } else {
+                final boolean isAllow = 
line.getAction().equals(AclLine.Action.ALLOW);
+                log.info("Adding repository level ACL '{}' entry '{}' for {}", 
isAllow ? "allow" : "deny", privileges, principals);
+                List<RestrictionClause> restrictions = line.getRestrictions();
+                AclUtil.setRepositoryAcl(s, principals, privileges, isAllow, 
restrictions);
+            }
         } catch(Exception e) {
             throw new RuntimeException("Failed to set repository level ACL (" 
+ e.toString() + ") " + line, e);
         }
@@ -78,24 +93,21 @@ class AclVisitor extends DoNothingVisitor {
     @Override
     public void visitSetAclPrincipal(SetAclPrincipals s) {
         final List<String> principals = s.getPrincipals();
-        for(AclLine line : s.getLines()) {
-            final boolean isAllow = 
line.getAction().equals(AclLine.Action.ALLOW);
+        for (AclLine line : s.getLines()) {
             final List<String> paths = line.getProperty(PROP_PATHS);
             if (paths != null && ! paths.isEmpty()) {
-                setAcl(line, session, principals, paths, require(line, 
PROP_PRIVILEGES), isAllow);
+                setAcl(line, session, principals, paths, require(line, 
PROP_PRIVILEGES), line.getAction());
             } else {
-                setRepositoryAcl(line, session, principals, require(line, 
PROP_PRIVILEGES), isAllow);
+                setRepositoryAcl(line, session, principals, require(line, 
PROP_PRIVILEGES), line.getAction());
             }
-
         }
      }
 
     @Override
     public void visitSetAclPaths(SetAclPaths s) {
         final List<String> paths = s.getPaths();
-        for(AclLine line : s.getLines()) {
-            final boolean isAllow = 
line.getAction().equals(AclLine.Action.ALLOW);
-            setAcl(line, session, require(line, PROP_PRINCIPALS), paths, 
require(line, PROP_PRIVILEGES), isAllow);
+        for (AclLine line : s.getLines()) {
+            setAcl(line, session, require(line, PROP_PRINCIPALS), paths, 
require(line, PROP_PRIVILEGES), line.getAction());
         }
     }
 
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java 
b/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java
index c395f81..090fbfb 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java
@@ -135,7 +135,6 @@ public class GeneralAclTest {
             + "allow jcr:all on /\n"
             + "end"
             ;
-
         U.parseAndExecute(aclSetup);
         try {
             assertFalse(s.itemExists(path));
@@ -342,7 +341,7 @@ public class GeneralAclTest {
     /**
      * Verifies success/failure of adding a properties
      * @param userSession
-     * @param nodeName
+     * @param relativePath
      * @param propertyName
      * @param successExpected
      * @throws RepositoryException
diff --git 
a/src/test/java/org/apache/sling/jcr/repoinit/PrincipalBasedAclTest.java 
b/src/test/java/org/apache/sling/jcr/repoinit/PrincipalBasedAclTest.java
index 751a420..56921f7 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/PrincipalBasedAclTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/PrincipalBasedAclTest.java
@@ -71,10 +71,12 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class PrincipalBasedAclTest {
 
     private static final String PRINCIPAL_BASED_SUBTREE = "principalbased";
+    private static final String REMOVE_NOT_SUPPORTED_REGEX = ".*REMOVE[a-zA-Z 
]+not supported.*";
 
     @Rule
     public final OsgiContext context = new OsgiContext();
@@ -165,25 +167,19 @@ public class PrincipalBasedAclTest {
      * @throws Exception If the repository login fails.
      */
     private Session loginSystemUserPrincipal(final String 
systemUserPrincipalName) throws Exception {
-        SystemUserPrincipal principal = new SystemUserPrincipal() {
-            @Override
-            public String getName() {
-                return systemUserPrincipalName;
-            }
-        };
+        SystemUserPrincipal principal = () -> systemUserPrincipalName;
         Subject subject = new Subject(true, Collections.singleton(principal), 
Collections.emptySet(), Collections.emptySet());
-        return Subject.doAs(subject, new PrivilegedExceptionAction<Session>() {
-            @Override
-            public Session run() throws Exception {
-                return repository.login(null, null);
-            }
-        });
+        return Subject.doAs(subject, (PrivilegedExceptionAction<Session>) () 
-> repository.login(null, null));
     }
 
     private static void assertPermission(Session userSession, String 
absolutePath, String actions, boolean successExpected) throws 
RepositoryException {
         assertEquals("Expecting "+actions+" for path " + absolutePath + " to 
be " + (successExpected ? "granted" : "denied"), successExpected, 
userSession.hasPermission(absolutePath, actions));
     }
 
+    private static void assertRegex(String regex, String shouldMatch) {
+        assertTrue("Expecting '" +  shouldMatch + "'' to match " + regex, 
shouldMatch.matches(regex));
+    }
+
     @Test
     public void readGranted() throws Exception {
         String setup =
@@ -610,12 +606,10 @@ public class PrincipalBasedAclTest {
 
     @Test
     public void testHomePath() throws Exception {
-        UserManager uMgr = ((JackrabbitSession) 
U.adminSession).getUserManager();
-        Authorizable a = uMgr.getAuthorizable(U.username);
-        Principal principal = a.getPrincipal();
+        Authorizable su = getServiceUser(U.adminSession, U.username);
+        Principal principal = su.getPrincipal();
 
-        JackrabbitAccessControlManager accessControlManager = 
AclUtil.getJACM(U.adminSession);
-        assertNull(getAcl(principal, accessControlManager));
+        assertNull(getAcl(principal, U.adminSession));
 
         AclLine line = new AclLine(AclLine.Action.ALLOW);
         line.setProperty(AclLine.PROP_PRINCIPALS, 
Collections.singletonList(principal.getName()));
@@ -623,12 +617,12 @@ public class PrincipalBasedAclTest {
         line.setProperty(AclLine.PROP_PATHS, 
Collections.singletonList(":home:"+U.username+"#"));
         AclUtil.setPrincipalAcl(U.adminSession, U.username, 
Collections.singletonList(line));
 
-        PrincipalAccessControlList acl = getAcl(principal, 
accessControlManager);
+        PrincipalAccessControlList acl = getAcl(principal, U.adminSession);
         assertNotNull(acl);
         assertEquals(1, acl.size());
         PrincipalAccessControlList.Entry entry = 
(PrincipalAccessControlList.Entry) acl.getAccessControlEntries()[0];
-        
assertArrayEquals(AccessControlUtils.privilegesFromNames(accessControlManager, 
Privilege.JCR_READ), entry.getPrivileges());
-        assertEquals(a.getPath(), entry.getEffectivePath());
+        
assertArrayEquals(AccessControlUtils.privilegesFromNames(AclUtil.getJACM(U.adminSession),
 Privilege.JCR_READ), entry.getPrivileges());
+        assertEquals(su.getPath(), entry.getEffectivePath());
     }
 
     @Test
@@ -642,7 +636,7 @@ public class PrincipalBasedAclTest {
                     + "end";
             U.parseAndExecute(setup);
 
-            PrincipalAccessControlList acl = getAcl(su.getPrincipal(), 
AclUtil.getJACM(U.adminSession));
+            PrincipalAccessControlList acl = getAcl(su.getPrincipal(), 
U.adminSession);
             assertNotNull(acl);
             assertEquals(1, acl.size());
         } finally {
@@ -655,9 +649,225 @@ public class PrincipalBasedAclTest {
         }
     }
 
+    @Test(expected = RuntimeException.class)
+    public void testRemoveNoExistingPolicy() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "remove jcr:read on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+    }
+
+    @Test
+    public void testRemoveMatchingEntry() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove jcr:write on " + path + "\n"
+                + "end";
+
+        try {
+            U.parseAndExecute(setup);
+            fail("Expecting REMOVE to fail");
+        } catch(RuntimeException rex) {
+            assertRegex(REMOVE_NOT_SUPPORTED_REGEX, rex.getMessage());
+        }
+    }
+
+    @Test
+    public void testRemoveNoMatchingEntry() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove jcr:read on " + path + "\n"
+                + "end";
+        try {
+            U.parseAndExecute(setup);
+            fail("Expecting REMOVE to fail");
+        } catch(RuntimeException rex) {
+            assertRegex(REMOVE_NOT_SUPPORTED_REGEX, rex.getMessage());
+        }      
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testRemoveNonExistingPrincipal() throws Exception {
+        String setup = "set principal ACL for nonExistingPrincipal\n"
+                + "remove jcr:write on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+    }
+
+    @Test
+    public void testRemovePrincipalMismatch() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+        U.parseAndExecute("create service user otherSystemPrincipal");
+
+        try {
+            setup = "set principal ACL for otherSystemPrincipal\n"
+            + "remove jcr:write on " + path + "\n"
+            + "end";
+            U.parseAndExecute(setup);
+            fail("Expecting REMOVE to fail");
+        } catch(RuntimeException rex) {
+            assertRegex(REMOVE_NOT_SUPPORTED_REGEX, rex.getMessage());
+        }
+    }
+
+    @Test
+    public void testRemoveAllNoExistingPolicy() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "remove * on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        assertNull(getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession));
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testAllRemoveNonExistingPrincipal() throws Exception {
+        String setup = "set principal ACL for nonExistingPrincipal\n"
+                + "remove * on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+    }
+
+    @Test
+    public void testRemoveAll() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "allow jcr:read on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove * on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertTrue(acl.isEmpty());
+    }
+
+    @Test
+    public void testRemoveAllRepositoryPath() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "allow jcr:namespaceManagement on :repository\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertEquals(2, acl.size());
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove * on :repository\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertEquals(1, acl.size());
+    }
+
+    @Test
+    public void testRemoveAllPartialPathMatch() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "allow jcr:write on /another/path\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertEquals(2, acl.size());
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove * on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertEquals(1, acl.size());
+    }
+
+    @Test
+    public void testRemoveAllMultiplePaths() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "allow jcr:write on home("+U.username+")\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertEquals(2, acl.size());
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove * on " + path + ", home("+U.username+")\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertTrue(acl.isEmpty());
+    }
+
+    @Test
+    public void testRemoveAllPathMismatch() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "allow jcr:read on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        setup = "set principal ACL for " + U.username + "\n"
+                + "remove * on /another/path\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, 
U.username).getPrincipal(), U.adminSession);
+        assertNotNull(acl);
+        assertEquals(2, acl.size());
+    }
+
+    @Test
+    public void testRemoveAllPrincipalMismatch() throws Exception {
+        String setup = "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+        U.parseAndExecute("create service user otherSystemPrincipal");
+
+        setup = "set principal ACL for otherSystemPrincipal\n"
+                + "remove * on " + path + "\n"
+                + "end";
+        U.parseAndExecute(setup);
+    }
+
+    private static Authorizable getServiceUser(@NotNull Session session, 
@NotNull String uid) throws RepositoryException {
+        UserManager uMgr = ((JackrabbitSession) session).getUserManager();
+        Authorizable a = uMgr.getAuthorizable(uid);
+        if (a != null) {
+            return a;
+        } else {
+            throw new RepositoryException("Expected service user " + uid + " 
to exist.");
+        }
+    }
+
     @Nullable
-    private static PrincipalAccessControlList getAcl(@NotNull Principal 
principal, @NotNull JackrabbitAccessControlManager jacm) throws 
RepositoryException {
-        for (AccessControlPolicy policy : jacm.getPolicies(principal)) {
+    private static PrincipalAccessControlList getAcl(@NotNull Principal 
principal, @NotNull Session session) throws RepositoryException {
+        for (AccessControlPolicy policy : 
AclUtil.getJACM(session).getPolicies(principal)) {
             if (policy instanceof PrincipalAccessControlList) {
                 return (PrincipalAccessControlList) policy;
             }
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/RemoveTest.java 
b/src/test/java/org/apache/sling/jcr/repoinit/RemoveTest.java
new file mode 100644
index 0000000..e3c87af
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/repoinit/RemoveTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jcr.repoinit;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.jcr.repoinit.impl.AclUtil;
+import org.apache.sling.jcr.repoinit.impl.TestUtil;
+import org.apache.sling.jcr.repoinit.impl.UserUtil;
+import org.apache.sling.repoinit.parser.RepoInitParsingException;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlPolicy;
+
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class RemoveTest {
+
+    @Rule
+    public final SlingContext context = new 
SlingContext(ResourceResolverType.JCR_OAK);
+
+    private TestUtil U;
+    private String path;
+    private String userHomePath;
+    private String groupId;
+    private String groupPrincipalName;
+
+    @Before
+    public void before() throws RepositoryException, RepoInitParsingException {
+        U = new TestUtil(context);
+        U.parseAndExecute("create service user " + U.username);
+
+        Node n = U.adminSession.getRootNode().addNode("tmp_" + U.id);
+        path = n.getPath();
+
+        UserManager uMgr = UserUtil.getUserManager(U.adminSession);
+        Group gr = uMgr.createGroup("group_"+UUID.randomUUID().toString());
+        groupId = gr.getID();
+        groupPrincipalName = gr.getPrincipal().getName();
+
+        U.adminSession.save();
+
+        String setup = "set ACL for " + U.username + "\n"
+                + "deny jcr:read on "+path+"\n"
+                + "deny jcr:all on :repository\n"
+                + "allow jcr:read on home(" + U.username + ")\n"
+                + "end\n"
+                + "\n"
+                + "set ACL for " + groupPrincipalName + "\n"
+                + "allow jcr:read on "+path+"\n"
+                + "allow jcr:namespaceManagement on :repository\n"
+                + "allow jcr:read on home(" + U.username + ")\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        userHomePath = uMgr.getAuthorizable(U.username).getPath();
+        assertPolicy(path, U.adminSession, 2);
+        assertPolicy(null, U.adminSession, 2);
+        assertPolicy(userHomePath, U.adminSession, 2);
+
+    }
+
+    @After
+    public void after() throws RepositoryException, RepoInitParsingException {
+        try {
+            U.adminSession.removeItem(path);
+            
UserUtil.getUserManager(U.adminSession).getAuthorizable(groupId).remove();
+            U.adminSession.save();
+        } finally {
+            U.cleanupUser();
+        }
+    }
+
+    private static void assertPolicy(@Nullable String path, @NotNull Session 
session, int expectedSize) throws RepositoryException {
+        AccessControlPolicy[] policies = 
session.getAccessControlManager().getPolicies(path);
+        for (AccessControlPolicy policy : policies) {
+            if (policy instanceof AccessControlList) {
+                assertEquals(expectedSize, ((AccessControlList) 
policy).getAccessControlEntries().length);
+                return;
+            }
+        }
+        fail("No access control list found at " + path);
+    }
+
+    @Test
+    public void testRemoveAllByPath() throws RepoInitParsingException, 
RepositoryException {
+        String setup = "set ACL for " + U.username + "\n"
+                + "remove * on "+path+",:repository, home("+U.username+")\n"
+                + "end";
+        U.parseAndExecute(setup);
+
+        assertPolicy(path, U.adminSession, 1);
+        assertPolicy(null, U.adminSession, 1);
+        assertPolicy(userHomePath, U.adminSession, 1);
+    }
+
+    @Test
+    public void testRemoveAllByPrincipal() throws RepoInitParsingException, 
RepositoryException {
+        String setup = "set ACL on "+path+", home("+U.username+"), 
:repository\n"
+                + "remove * for "+U.username+"\n" +
+                "end";
+        U.parseAndExecute(setup);
+
+        assertPolicy(path, U.adminSession, 1);
+        assertPolicy(null, U.adminSession, 1);
+        assertPolicy(userHomePath, U.adminSession, 1);
+    }
+
+    @Test
+    public void testRemoveAllByMultiplePrincipals() throws 
RepoInitParsingException, RepositoryException {
+        String setup = "set ACL on "+path+"\n"
+                + "remove * for "+U.username+", "+groupPrincipalName+"\n" +
+                "end";
+        U.parseAndExecute(setup);
+
+        assertPolicy(path, U.adminSession, 0);
+        assertPolicy(null, U.adminSession, 2);
+        assertPolicy(userHomePath, U.adminSession, 2);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testRemoveByPath() throws RepoInitParsingException, 
RepositoryException {
+        String setup = "set ACL for " + U.username + "\n"
+                + "remove jcr:read on "+path+"\n"
+                + "end";
+        U.parseAndExecute(setup);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testRemoveByPath2() throws RepoInitParsingException, 
RepositoryException {
+        String setup = "set ACL for " + groupPrincipalName + "\n"
+                + "remove jcr:versionManagement on :repository\n"
+                + "end";
+        U.parseAndExecute(setup);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testRemoveByPrincipal() throws RepoInitParsingException, 
RepositoryException {
+        String setup = "set ACL on home("+U.username+")\n"
+                + "remove jcr:all for "+U.username+"\n" +
+                "end";
+        U.parseAndExecute(setup);
+    }
+}
\ No newline at end of file

Reply via email to