You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by an...@apache.org on 2021/05/05 12:56:49 UTC

[sling-org-apache-sling-jcr-repoinit] branch SLING-10299 created (now c1ccb1a)

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

angela pushed a change to branch SLING-10299
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git.


      at c1ccb1a  SLING-10299 : Allow for removal of access control policies (not just individual entries)

This branch includes the following new commits:

     new c1ccb1a  SLING-10299 : Allow for removal of access control policies (not just individual entries)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[sling-org-apache-sling-jcr-repoinit] 01/01: SLING-10299 : Allow for removal of access control policies (not just individual entries)

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c1ccb1a2c4c23771c6b2099d38ce6fc6d85287c1
Author: angela <an...@adobe.com>
AuthorDate: Wed May 5 14:55:36 2021 +0200

    SLING-10299 : Allow for removal of access control policies (not just individual entries)
---
 pom.xml                                            |   2 +-
 .../apache/sling/jcr/repoinit/impl/AclUtil.java    |  82 +++++++++-
 .../apache/sling/jcr/repoinit/impl/AclVisitor.java |  37 +++++
 .../sling/jcr/repoinit/impl/DoNothingVisitor.java  |  15 ++
 .../sling/jcr/repoinit/PrincipalBasedAclTest.java  | 120 +++++++++++---
 .../apache/sling/jcr/repoinit/RemoveAclTest.java   | 174 +++++++++++++++++++++
 6 files changed, 404 insertions(+), 26 deletions(-)

diff --git a/pom.xml b/pom.xml
index 6c5e80d..3733564 100644
--- a/pom.xml
+++ b/pom.xml
@@ -219,7 +219,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.repoinit.parser</artifactId>
-            <version>1.6.7-SNAPSHOT</version>
+            <version>1.6.9-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
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 cde2e34..7264163 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
@@ -40,9 +40,11 @@ import javax.jcr.security.Privilege;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
 import org.apache.jackrabbit.api.security.authorization.PrincipalAccessControlList;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.util.Text;
 import org.apache.sling.repoinit.parser.operations.AclLine;
 import org.apache.sling.repoinit.parser.operations.RestrictionClause;
@@ -166,6 +168,51 @@ public class AclUtil {
         setAcl(session, principals, (String)null, privileges, isAllow, restrictionClauses);
     }
 
+    /**
+     * Remove resource-based access control setup for the principal with the given name.
+     * 
+     * @param session
+     * @param principalName
+     * @throws RepositoryException
+     */
+    public static void removeAcl(@NotNull Session session, @NotNull final String principalName) throws RepositoryException {
+        Principal principal = AccessControlUtils.getPrincipal(session, principalName);
+        if (principal == null) {
+            LOG.info("Principal {} does not exist.", principalName);
+            // using PrincipalImpl will prevent 'removePolicy' from failing with AccessControlException
+            // in case import-behavior is configured to be ABORT.
+            principal = new PrincipalImpl(principalName);
+        }
+        
+        JackrabbitAccessControlManager acMgr = getJACM(session);
+        for (JackrabbitAccessControlPolicy policy : acMgr.getPolicies(principal)) {
+            // make sure not to remove the principal-based access control list but instead only drop
+            // resource-based access control content for the given principal
+            if (policy instanceof JackrabbitAccessControlList && !(policy instanceof PrincipalAccessControlList)) {
+                acMgr.removePolicy(policy.getPath(), policy);
+            }
+        }
+    }
+
+    /**
+     * Remove resource-based access control setup defined for the specified paths.
+     * 
+     * @param session
+     * @param paths
+     * @throws RepositoryException
+     */
+    public static void removeAcl(@NotNull Session session, @NotNull List<String> paths) throws RepositoryException {
+        for (String jcrPath : getJcrPaths(session, paths)) {
+            LOG.info("Removing access control policy on {}", jcrPath);
+            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(session, jcrPath);
+            if (acl == null) {
+                LOG.info("No ACL to remove at path {}", jcrPath);
+            } else {
+                session.getAccessControlManager().removePolicy(jcrPath, acl);
+            }
+        }
+    }
+    
     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)) {
@@ -202,7 +249,7 @@ public class AclUtil {
             checkState(principal != null, "Principal not found: " + principalName);
         }
 
-        final PrincipalAccessControlList acl = getPrincipalAccessControlList(acMgr, principal);
+        final PrincipalAccessControlList acl = getPrincipalAccessControlList(acMgr, principal, true);
         boolean modified = false;
         for (AclLine line : lines) {
             AclLine.Action action = line.getAction();
@@ -244,16 +291,41 @@ public class AclUtil {
         }
     }
 
-    private static PrincipalAccessControlList getPrincipalAccessControlList(JackrabbitAccessControlManager acMgr, Principal principal) throws RepositoryException {
+    /**
+     * Remove principal-based access control setup for the principal with the given name. 
+     *
+     * @param session
+     * @param principalName
+     * @throws RepositoryException
+     */
+    public static void removePrincipalAcl(@NotNull Session session, @NotNull String principalName) throws RepositoryException {
+        Principal principal = AccessControlUtils.getPrincipal(session, principalName);
+        if (principal == null) {
+            LOG.info("Cannot remove principal-based ACL. Principal {} does not exist.", principalName);
+            return;
+        }
+
+        JackrabbitAccessControlManager acMgr = getJACM(session);
+        PrincipalAccessControlList acl = getPrincipalAccessControlList(acMgr, principal, false);
+        if (acl == null) {
+            LOG.info("Cannot remove principal-based ACL for principal {}. No such policy exists.", principalName);
+        } else {
+            acMgr.removePolicy(acl.getPath(), acl);
+        }
+    }
+
+    @Nullable
+    private static PrincipalAccessControlList getPrincipalAccessControlList(@NotNull JackrabbitAccessControlManager acMgr, 
+                                                                            @NotNull Principal principal, boolean includeApplicable) throws RepositoryException {
         PrincipalAccessControlList acl = null;
-        for (AccessControlPolicy policy : acMgr.getPolicies(principal)) {
+        for (JackrabbitAccessControlPolicy policy : acMgr.getPolicies(principal)) {
             if (policy instanceof PrincipalAccessControlList) {
                 acl = (PrincipalAccessControlList) policy;
                 break;
             }
         }
-        if (acl == null) {
-            for (AccessControlPolicy policy : acMgr.getApplicablePolicies(principal)) {
+        if (acl == null && includeApplicable) {
+            for (JackrabbitAccessControlPolicy policy : acMgr.getApplicablePolicies(principal)) {
                 if (policy instanceof PrincipalAccessControlList) {
                     acl = (PrincipalAccessControlList) policy;
                     break;
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 965bd80..a071a91 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
@@ -24,11 +24,15 @@ import java.util.Collections;
 import java.util.List;
 
 import javax.jcr.Node;
+import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
 import org.apache.sling.repoinit.parser.operations.AclLine;
 import org.apache.sling.repoinit.parser.operations.CreatePath;
 import org.apache.sling.repoinit.parser.operations.PathSegmentDefinition;
+import org.apache.sling.repoinit.parser.operations.RemoveAclPaths;
+import org.apache.sling.repoinit.parser.operations.RemoveAclPrincipalBased;
+import org.apache.sling.repoinit.parser.operations.RemoveAclPrincipals;
 import org.apache.sling.repoinit.parser.operations.RestrictionClause;
 import org.apache.sling.repoinit.parser.operations.SetAclPaths;
 import org.apache.sling.repoinit.parser.operations.SetAclPrincipalBased;
@@ -154,4 +158,37 @@ class AclVisitor extends DoNothingVisitor {
             throw new RuntimeException("Session.save failed: "+ e, e);
         }
     }
+    
+    @Override
+    public void visitRemoveAclPrincipals(RemoveAclPrincipals s) {
+        for (String principalName : s.getPrincipals()) {
+            try {
+                log.info("Removing access control policy for {}", principalName);
+                AclUtil.removeAcl(session, principalName);
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Failed to remove ACL ("+e.getMessage()+")");
+            }
+        }
+    }
+
+    @Override
+    public void visitRemoveAclPaths(RemoveAclPaths s) {
+        try {
+            AclUtil.removeAcl(session, s.getPaths());
+        } catch (RepositoryException e) {
+            throw new RuntimeException("Failed to remove ACL ("+e.getMessage()+")");
+        }
+    }
+
+    @Override
+    public void visitRemoveAclPrincipalBased(RemoveAclPrincipalBased s) {
+        for (String principalName : s.getPrincipals()) {
+            try {
+                log.info("Removing principal-based access control policy for {}", principalName);
+                AclUtil.removePrincipalAcl(session, principalName);
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Failed to remove principal-based ACL ("+e.getMessage()+")");
+            }
+        }
+    }
 }
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java
index c2ae6ed..424e978 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/DoNothingVisitor.java
@@ -31,6 +31,9 @@ import org.apache.sling.repoinit.parser.operations.OperationVisitor;
 import org.apache.sling.repoinit.parser.operations.RegisterNamespace;
 import org.apache.sling.repoinit.parser.operations.RegisterNodetypes;
 import org.apache.sling.repoinit.parser.operations.RegisterPrivilege;
+import org.apache.sling.repoinit.parser.operations.RemoveAclPaths;
+import org.apache.sling.repoinit.parser.operations.RemoveAclPrincipalBased;
+import org.apache.sling.repoinit.parser.operations.RemoveAclPrincipals;
 import org.apache.sling.repoinit.parser.operations.RemoveGroupMembers;
 import org.apache.sling.repoinit.parser.operations.SetAclPaths;
 import org.apache.sling.repoinit.parser.operations.SetAclPrincipalBased;
@@ -97,6 +100,18 @@ class DoNothingVisitor implements OperationVisitor {
     }
 
     @Override
+    public void visitRemoveAclPrincipals(RemoveAclPrincipals s) {
+    }
+
+    @Override
+    public void visitRemoveAclPaths(RemoveAclPaths s) {
+    }
+
+    @Override
+    public void visitRemoveAclPrincipalBased(RemoveAclPrincipalBased s) {
+    }
+
+    @Override
     public void visitCreatePath(CreatePath cp) {
     }
 
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 b0a9a84..bc95b9f 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/PrincipalBasedAclTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/PrincipalBasedAclTest.java
@@ -83,6 +83,7 @@ public class PrincipalBasedAclTest {
 
     private Repository repository;
     private JackrabbitSession adminSession;
+    private JackrabbitAccessControlManager acMgr;
 
     private TestUtil U;
 
@@ -99,6 +100,7 @@ public class PrincipalBasedAclTest {
 
         String uid = sp.getParameters(UserConfiguration.NAME).getConfigValue(UserConstants.PARAM_ADMIN_ID, UserConstants.DEFAULT_ADMIN_ID);
         adminSession = (JackrabbitSession) repository.login(new SimpleCredentials(uid, uid.toCharArray()), null);
+        acMgr = AclUtil.getJACM(adminSession);
         U = new TestUtil(adminSession);
 
         Node tmp = adminSession.getRootNode().addNode("tmp_" + U.id);
@@ -180,6 +182,20 @@ public class PrincipalBasedAclTest {
         assertTrue("Expecting '" +  shouldMatch + "'' to match " + regex, shouldMatch.matches(regex));
     }
 
+    private Authorizable getServiceUser(@NotNull String uid) throws RepositoryException {
+        UserManager uMgr = adminSession.getUserManager();
+        Authorizable a = uMgr.getAuthorizable(uid);
+        if (a != null) {
+            return a;
+        } else {
+            throw new RepositoryException("Expected service user " + uid + " to exist.");
+        }
+    }
+    
+    private Principal getPrincipal(@NotNull String serviceUserId) throws RepositoryException {
+        return getServiceUser(serviceUserId).getPrincipal();
+    }
+
     @Test
     public void readGranted() throws Exception {
         String setup =
@@ -595,7 +611,7 @@ public class PrincipalBasedAclTest {
                     + "end";
             U.parseAndExecute(setup);
 
-            Principal principal = adminSession.getUserManager().getAuthorizable("otherSystemPrincipal").getPrincipal();
+            Principal principal = getPrincipal("otherSystemPrincipal");
             for (AccessControlPolicy policy : acMgr.getPolicies(principal)) {
                 assertFalse(policy instanceof PrincipalAccessControlList);
             }
@@ -606,7 +622,7 @@ public class PrincipalBasedAclTest {
 
     @Test
     public void testHomePath() throws Exception {
-        Authorizable su = getServiceUser(U.adminSession, U.username);
+        Authorizable su = getServiceUser(U.username);
         Principal principal = su.getPrincipal();
 
         assertNull(getAcl(principal, U.adminSession));
@@ -728,7 +744,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        assertNull(getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession));
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
     }
 
     @Test(expected = RuntimeException.class)
@@ -752,7 +768,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        PrincipalAccessControlList acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertTrue(acl.isEmpty());
     }
@@ -765,7 +781,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        PrincipalAccessControlList acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertEquals(2, acl.size());
 
@@ -774,7 +790,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertEquals(1, acl.size());
     }
@@ -787,7 +803,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        PrincipalAccessControlList acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertEquals(2, acl.size());
 
@@ -796,7 +812,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertEquals(1, acl.size());
     }
@@ -809,7 +825,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        PrincipalAccessControlList acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertEquals(2, acl.size());
 
@@ -818,7 +834,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertTrue(acl.isEmpty());
     }
@@ -836,7 +852,7 @@ public class PrincipalBasedAclTest {
                 + "end";
         U.parseAndExecute(setup);
 
-        PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+        PrincipalAccessControlList acl = getAcl(getPrincipal(U.username), U.adminSession);
         assertNotNull(acl);
         assertEquals(2, acl.size());
     }
@@ -870,20 +886,84 @@ public class PrincipalBasedAclTest {
         );
 
         {
-            PrincipalAccessControlList acl = getAcl(getServiceUser(U.adminSession, U.username).getPrincipal(), U.adminSession);
+            PrincipalAccessControlList acl = getAcl(getPrincipal(U.username), U.adminSession);
             assertNotNull(acl);
             assertEquals(0, acl.size());
         }
-}
+    }
 
-    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.");
+    @Test
+    public void testAddAndRemoveAcl() throws Exception {
+        U.parseAndExecute(""
+                + "set principal ACL for " + U.username + "\n"
+                + "allow jcr:write on "+path+"\n"
+                + "end\n"
+                + "remove principal ACL for " + U.username + "\n"
+        );
+
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
+    }
+
+    @Test
+    public void testRemoveAcl() throws Exception {
+        PrincipalAccessControlList acl = getApplicableAcl(getPrincipal(U.username), U.adminSession);
+        acl.addEntry("/content", AccessControlUtils.privilegesFromNames(U.adminSession, Privilege.JCR_READ));
+        U.adminSession.getAccessControlManager().setPolicy(acl.getPath(), acl);
+        U.adminSession.save();
+
+        assertNotNull(getAcl(getPrincipal(U.username), U.adminSession));
+        U.parseAndExecute("remove principal ACL for " + U.username + "\n");
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
+    }
+
+    @Test
+    public void testRemoveNonExistingAcl() throws Exception {
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
+        // removing non-existing policy must not fail
+        U.parseAndExecute("remove principal ACL for " + U.username + "\n");
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
+    }
+
+    @Test
+    public void testRemoveAclNonExistingPrincipal() throws Exception {
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
+        // removing policy for non-existing principal must not fail
+        U.parseAndExecute("remove principal ACL for non-existing-service-user\n");
+        assertNull(getAcl(getPrincipal(U.username), U.adminSession));
+    }
+
+    @Test
+    public void testRemoveResourceBasedAclByPrincipal() throws Exception {
+        U.parseAndExecute(""
+                + "create path (nt:unstructured) /var\n"
+                + "set ACL for " + U.username + "\n"
+                + "allow jcr:read on /var\n"
+                + "end\n"
+                + "set principal ACL for " + U.username + "\n"
+                + "allow jcr:read on /var\n"
+                + "end\n");
+
+        assertEquals(1, acMgr.getPolicies("/var").length);
+
+        U.parseAndExecute("remove ACL for "+U.username+"\n");
+        // resource-based acl at /var must be removed as it only contains a single entry for U.userName
+        assertEquals(0, acMgr.getPolicies("/var").length);
+
+        // removing resource-based ac-setup by principal must not delete any principal-based ac setup.
+        Principal p = getPrincipal(U.username);
+        AccessControlPolicy[] policies = acMgr.getPolicies(p);
+        assertEquals(1, policies.length);
+        assertTrue(policies[0] instanceof PrincipalAccessControlList);
+    }
+
+    @Nullable
+    private static PrincipalAccessControlList getApplicableAcl(@NotNull Principal principal, @NotNull Session session) throws RepositoryException {
+        for (AccessControlPolicy policy : AclUtil.getJACM(session).getApplicablePolicies(principal)) {
+            if (policy instanceof PrincipalAccessControlList) {
+                return (PrincipalAccessControlList) policy;
+            }
         }
+        return null;
     }
 
     @Nullable
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/RemoveAclTest.java b/src/test/java/org/apache/sling/jcr/repoinit/RemoveAclTest.java
new file mode 100644
index 0000000..aaa9fad
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/repoinit/RemoveAclTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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 com.google.common.collect.Lists;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
+import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
+import org.apache.sling.jcr.repoinit.impl.AclUtil;
+import org.apache.sling.jcr.repoinit.impl.TestUtil;
+import org.apache.sling.repoinit.parser.RepoInitParsingException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.security.AccessControlPolicy;
+import java.security.Principal;
+import java.util.Collection;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(Parameterized.class)
+public class RemoveAclTest {
+    
+    @Parameterized.Parameters(name = "ImportBehavior={0}")
+    public static Collection<Object[]> parameters() {
+        return Lists.newArrayList(
+                new Object[] {ImportBehavior.NAME_IGNORE},
+                new Object[] {ImportBehavior.NAME_BESTEFFORT},
+                new Object[] {ImportBehavior.NAME_ABORT}
+        );
+    }
+
+    private final String importBehaviorName;
+    
+    private Repository repository;
+    private Session adminSession;
+    private JackrabbitAccessControlManager acMgr;
+    
+    private TestUtil U;
+    private String userA;
+
+    public RemoveAclTest(String name) {
+        this.importBehaviorName = name;
+    }
+    
+    @Before
+    public void setup() throws RepositoryException, RepoInitParsingException {
+        SecurityProvider sp = createSecurityProvider();
+        repository = new Jcr().with(sp).createRepository();
+
+        String uid = sp.getParameters(UserConfiguration.NAME).getConfigValue(UserConstants.PARAM_ADMIN_ID, UserConstants.DEFAULT_ADMIN_ID);
+        adminSession = repository.login(new SimpleCredentials(uid, uid.toCharArray()), null);
+        acMgr = AclUtil.getJACM(adminSession);
+        U = new TestUtil(adminSession);
+        
+        userA = "userA_" + U.id;
+
+        U.parseAndExecute("create service user " + U.username);
+        U.parseAndExecute("create service user " + userA);
+        U.parseAndExecute(""
+                + "create path (nt:unstructured) /content\n"
+                + "create path (nt:unstructured) /var\n"
+                + "set ACL for " + U.username + "\n"
+                + "allow jcr:read on /content, /var, home("+userA+")\n"
+                + "allow jcr:namespaceManagement on :repository\n"
+                + "end\n"
+                + "set ACL for " + userA + "\n"
+                + "allow jcr:read on /content, /var\n"
+                + "end\n");
+    }
+
+    private SecurityProvider createSecurityProvider() { 
+        return SecurityProviderBuilder.newBuilder().with(ConfigurationParameters.of(AuthorizationConfiguration.NAME, ConfigurationParameters.of(ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR, importBehaviorName))).build();
+    }
+
+    @After
+    public void after() throws Exception {
+        try {
+            adminSession.removeItem("/content");
+            adminSession.removeItem("/var");
+            adminSession.save();
+            U.cleanupUser();
+            U.cleanupServiceUser(userA);
+        } finally {
+            adminSession.logout();
+            if (repository instanceof JackrabbitRepository) {
+                ((JackrabbitRepository) repository).shutdown();
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveAcl() throws Exception {
+        U.parseAndExecute("remove ACL on /content, :repository\n");
+
+        assertArrayEquals(new AccessControlPolicy[0], acMgr.getPolicies("/content"));
+        assertArrayEquals(new AccessControlPolicy[0], acMgr.getPolicies((String) null));
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testRemoveAclNonExistingPath() throws Exception {
+        U.parseAndExecute("remove ACL on /nonExisting\n");
+    }
+
+    @Test
+    public void testRemoveAclByPrincipal() throws Exception {
+        U.parseAndExecute("remove ACL for "+userA+"\n");
+
+        // removing resource-based ac setup by principal must leave entries for other principals intact
+        for (String path : new String[] {"/content", "/var"}) {
+            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(adminSession, path);
+            assertNotNull(acl);
+            assertEquals(1, acl.size()); // entry for U.username must not have been removed
+            assertEquals(U.username, acl.getAccessControlEntries()[0].getPrincipal().getName());
+        }
+    }
+    
+    @Test
+    public void testRemoveAclByNonExistingPrincipal() throws Exception {
+        Principal p = new PrincipalImpl("non-existing-service-user");
+        assertEquals(0,  acMgr.getPolicies(p).length);
+        
+        // execution for non-existing principal must not fail
+        U.parseAndExecute("remove ACL for non-existing-service-user\n");
+        
+        assertEquals(0,  acMgr.getPolicies(p).length);
+    }
+
+    @Test
+    public void testRemoveUserAndAcl() throws Exception {
+        Principal p = new PrincipalImpl(userA);
+        assertEquals(1, acMgr.getPolicies(p).length);
+        
+        U.parseAndExecute("delete service user "+userA+"\n");
+        assertEquals(1, acMgr.getPolicies(p).length);
+
+        U.parseAndExecute("remove ACL for "+userA+"\n");
+        assertEquals(0, acMgr.getPolicies(p).length);
+    }
+}
\ No newline at end of file