You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by pa...@apache.org on 2021/01/14 17:29:02 UTC

[sling-org-apache-sling-feature-cpconverter] branch master updated: SLING-9953: ACEs on/below user nodes are ignored upon conversion (#51)

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

pauls pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git


The following commit(s) were added to refs/heads/master by this push:
     new ea7983d  SLING-9953: ACEs on/below user nodes are ignored upon conversion (#51)
ea7983d is described below

commit ea7983dd26b561b4fddb92b449610d8538d073ba
Author: Karl Pauls <pa...@apache.org>
AuthorDate: Thu Jan 14 18:28:52 2021 +0100

    SLING-9953: ACEs on/below user nodes are ignored upon conversion (#51)
    
    * SLING-9953: ACEs on/below user nodes are ignored upon conversion
    
    Co-authored-by: angela <an...@adobe.com>
---
 .../{SystemUser.java => AbstractUser.java}         |   9 +-
 .../cpconverter/accesscontrol/AclManager.java      |   6 +-
 .../accesscontrol/DefaultAclManager.java           | 153 ++++++++++-------
 .../accesscontrol/{AclManager.java => Group.java}  |  31 ++--
 .../cpconverter/accesscontrol/MixinParser.java     |   9 +-
 .../accesscontrol/PrimaryTypeParser.java           |  11 +-
 .../cpconverter/accesscontrol/SystemUser.java      |  54 +-----
 .../accesscontrol/{AclManager.java => User.java}   |  31 ++--
 .../features/DefaultFeaturesManager.java           |   2 +-
 .../handlers/AbstractUserEntryHandler.java         |  54 ++++++
 .../cpconverter/handlers/AbstractUserParser.java   |  63 +++++++
 .../cpconverter/handlers/GroupEntryHandler.java    |  54 ++++++
 .../handlers/SystemUsersEntryHandler.java          |  95 ----------
 .../cpconverter/handlers/UsersEntryHandler.java    |  61 +++++++
 .../cpconverter/shared/AbstractJcrNodeParser.java  |  18 +-
 .../vltpkg/RecollectorVaultPackageScanner.java     |   4 +-
 ...sling.feature.cpconverter.handlers.EntryHandler |   2 +
 .../cpconverter/accesscontrol/AclManagerTest.java  | 159 ++++++++++++++++-
 .../handlers/RepPolicyEntryHandlerTest.java        | 191 +++++++++++++--------
 .../feature/cpconverter/handlers/TestUtils.java    |   9 +
 ...HandlerTest.java => UsersEntryHandlerTest.java} |  16 +-
 .../handlers/jcr_root/home/groups/g/.content.xml   |  20 +++
 .../groups/g/HjDnfdMCjekaF4jhhUvO/.content.xml     |  23 +++
 .../groups/g/HjDnfdMCjekaF4jhhUvO/_rep_policy.xml  |  32 ++++
 .../groups/g/V084LLw1ypl2l9G0e28c/.content.xml     |  22 +++
 .../groups/g/V084LLw1ypl2l9G0e28c/_rep_policy.xml  |  26 +++
 .../jcr_root/home/groups/g/_rep_policy.xml         |  25 +++
 .../groups/g/ouStmkrzT9wCEhtMD9sT/.content.xml     |  22 +++
 .../g/ouStmkrzT9wCEhtMD9sT/profile/.content.xml    |  21 +++
 .../g/ouStmkrzT9wCEhtMD9sT/profile/_rep_policy.xml |  32 ++++
 .../jcr_root/home/users/a/author/.content.xml      |  23 +++
 .../jcr_root/home/users/a/author/_rep_policy.xml   |  25 +++
 .../home/users/a/author/profile/.content.xml       |  21 +++
 .../users/system/services/random1/.content.xml     |  22 +++
 .../users/system/services/random2/.content.xml     |  22 +++
 .../users/system/services/random3/.content.xml     |  22 +++
 .../users/system/services/random4/.content.xml     |  22 +++
 37 files changed, 1046 insertions(+), 366 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AbstractUser.java
similarity index 89%
copy from src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java
copy to src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AbstractUser.java
index 6cce9f4..93c93c1 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AbstractUser.java
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.Objects;
 
-public class SystemUser {
+abstract class AbstractUser {
 
     private final String id;
 
@@ -33,7 +33,7 @@ public class SystemUser {
      * @param path - the original repository path of the user in the content-package.
      * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
      */
-    public SystemUser(@NotNull String id, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
+    protected AbstractUser(@NotNull String id, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
         this.id = id;
         this.path = path;
         this.intermediatePath = intermediatePath;
@@ -70,13 +70,12 @@ public class SystemUser {
             return false;
         }
 
-        SystemUser other = (SystemUser) obj;
+        AbstractUser other = (AbstractUser) obj;
         return Objects.equals(id, other.getId()) && Objects.equals(path, other.getPath());
     }
 
     @Override
     public String toString() {
-        return "SystemUser [id=" + id + ", path=" + path + "]";
+        return getClass().getSimpleName() + " [id=" + id + ", path=" + path + "]";
     }
-
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
index 1bc0664..0aa5eae 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
@@ -28,7 +28,11 @@ import org.jetbrains.annotations.NotNull;
  */
 public interface AclManager {
 
-    boolean addSystemUser(SystemUser systemUser);
+    boolean addUser(@NotNull User user);
+
+    boolean addGroup(@NotNull Group group);
+
+    boolean addSystemUser(@NotNull SystemUser systemUser);
 
     boolean addAcl(String systemUser, AccessControlEntry acl);
 
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java
index 900923b..90c2277 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java
@@ -34,30 +34,26 @@ import java.io.FileInputStream;
 import java.util.Optional;
 import java.util.Formatter;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.Collection;
-import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.Map.Entry;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public final class DefaultAclManager implements AclManager {
 
     private static final String CONTENT_XML_FILE_NAME = ".content.xml";
 
-    private static final String DEFAULT_TYPE = "sling:Folder";
-
-    private final Set<RepoPath> preProvidedSystemPaths = new HashSet<>();
-
-    private final Set<RepoPath> preProvidedPaths = new HashSet<>();
-
     private final Set<SystemUser> systemUsers = new LinkedHashSet<>();
+    private final Set<Group> groups = new LinkedHashSet<>();
+    private final Set<User> users = new LinkedHashSet<>();
 
     private final Map<String, List<AccessControlEntry>> acls = new HashMap<>();
 
@@ -65,6 +61,15 @@ public final class DefaultAclManager implements AclManager {
 
     private volatile PrivilegeDefinitions privilegeDefinitions;
 
+    @Override
+    public boolean addUser(@NotNull User user) {
+        return users.add(user);
+    }
+
+    public boolean addGroup(@NotNull Group group) {
+        return groups.add(group);
+    }
+
     public boolean addSystemUser(@NotNull SystemUser systemUser) {
         return systemUsers.add(systemUser);
     }
@@ -77,17 +82,6 @@ public final class DefaultAclManager implements AclManager {
         return false;
     }
 
-    private void addPath(@NotNull RepoPath path, @NotNull Set<RepoPath> paths) {
-        if (preProvidedPaths.add(path)) {
-            paths.add(path);
-        }
-
-        RepoPath parent = path.getParent();
-        if (parent != null && parent.getSegmentCount() > 0) {
-            addPath(parent, paths);
-        }
-    }
-
     public void addRepoinitExtension(@NotNull List<VaultPackageAssembler> packageAssemblers, @NotNull FeaturesManager featureManager) {
         try (Formatter formatter = new Formatter()) {
 
@@ -104,17 +98,38 @@ public final class DefaultAclManager implements AclManager {
             for (SystemUser systemUser : systemUsers) {
                 // make sure all users are created first
                 formatter.format("create service user %s with path %s%n", systemUser.getId(), systemUser.getIntermediatePath());
+                if (aclIsBelow(systemUser.getPath())) {
+                    throw new IllegalStateException("Detected policy on subpath of system-user: " + systemUser);
+                }
+            }
+
+            for (Group group : groups) {
+                if (aclStartsWith(group.getPath())) {
+                    formatter.format("create group %s with path %s%n", group.getId(), group.getIntermediatePath());
+                }
+                if (aclIsBelow(group.getPath())) {
+                    throw new IllegalStateException("Detected policy on subpath of group: " + group);
+                }
+            }
+
+            for (User user : users) {
+                if (aclStartsWith(user.getPath())) {
+                    throw new IllegalStateException("Detected policy on user: " + user);
+                }
             }
 
             Set<RepoPath> paths = acls.entrySet().stream()
                     .filter(entry -> getSystemUser(entry.getKey()).isPresent())
                     .map(Entry::getValue)
                     .flatMap(Collection::stream)
-                    .map(AccessControlEntry::getRepositoryPath).collect(Collectors.toSet());
+                    .map(AccessControlEntry::getRepositoryPath)
+                    .collect(Collectors.toSet());
 
             paths.stream()
                     .filter(path -> !paths.stream().anyMatch(other -> !other.equals(path) && other.startsWith(path)))
                     .filter(((Predicate<RepoPath>)RepoPath::isRepositoryPath).negate())
+                    .filter(path -> Stream.of(systemUsers, users, groups).flatMap(Collection::stream)
+                            .noneMatch(user -> user.getPath().startsWith(path)))
                     .map(path -> computePathWithTypes(path, packageAssemblers))
                     .filter(Objects::nonNull)
                     .forEach(
@@ -135,22 +150,46 @@ public final class DefaultAclManager implements AclManager {
         }
     }
 
+    private boolean aclStartsWith(RepoPath path) {
+        return acls.values().stream().flatMap(List::stream).anyMatch(acl -> acl.getRepositoryPath().startsWith(path));
+    }
+
+    private boolean aclIsBelow(RepoPath path) {
+        return acls.values().stream().flatMap(List::stream).anyMatch(acl -> acl.getRepositoryPath().startsWith(path) && !acl.getRepositoryPath().equals(path));
+    }
+
     private void addStatements(@NotNull SystemUser systemUser,
                                @NotNull List<AccessControlEntry> authorizations,
                                @NotNull List<VaultPackageAssembler> packageAssemblers,
                                @NotNull Formatter formatter) {
-        // clean the unneeded ACLs, see SLING-8561
-        Iterator<AccessControlEntry> authorizationsIterator = authorizations.iterator();
-        while (authorizationsIterator.hasNext()) {
-            AccessControlEntry acl = authorizationsIterator.next();
+        if (authorizations.isEmpty()) {
+            return;
+        }
 
-            if (acl.getRepositoryPath().startsWith(systemUser.getIntermediatePath())) {
-                authorizationsIterator.remove();
+        Map<AccessControlEntry, String> entries = new LinkedHashMap<>();
+        authorizations.forEach(entry -> {
+            String path = getRepoInitPath(entry.getRepositoryPath(), systemUser);
+            if (path != null) {
+                entries.put(entry, path);
             }
-        }
-        // finally add ACLs
+        });
+        if (!entries.isEmpty()) {
+            formatter.format("set ACL for %s%n", systemUser.getId());
+            entries.forEach((entry, path) -> {
+                formatter.format("%s %s on %s",
+                        entry.getOperation(),
+                        entry.getPrivileges(),
+                        path);
+
+                if (!entry.getRestrictions().isEmpty()) {
+                    formatter.format(" restriction(%s)",
+                            String.join(",", entry.getRestrictions()));
+                }
 
-        addAclStatement(formatter, systemUser, authorizations);
+                formatter.format("%n");
+            });
+            formatter.format("end%n");
+        }
     }
 
     private @NotNull Optional<SystemUser> getSystemUser(@NotNull String id) {
@@ -215,44 +254,40 @@ public final class DefaultAclManager implements AclManager {
         return type ? new RepoPath(current).toString() : null;
     }
 
-    private static void addAclStatement(@NotNull Formatter formatter, @NotNull SystemUser systemUser, @NotNull List<AccessControlEntry> authorizations) {
-        if (authorizations.isEmpty()) {
-            return;
+    @Nullable
+    private String getRepoInitPath(@NotNull RepoPath path, @NotNull SystemUser systemUser) {
+        if (path.isRepositoryPath()) {
+            return ":repository";
+        } else if (isHomePath(path, systemUser.getPath())) {
+            return getHomePath(path, systemUser);
+        } else {
+            AbstractUser other = getOtherUser(path, Stream.of(systemUsers, groups).flatMap(Collection::stream));
+            if (other != null) {
+                return getHomePath(path, other);
+            }
+            // not a special path
+            return path.toString();
         }
-
-        writeAccessControl(authorizations, "set ACL for %s%n", systemUser, formatter);
     }
 
-    private static void writeAccessControl(@NotNull List<AccessControlEntry> accessControlEntries, @NotNull String statement, @NotNull SystemUser systemUser, @NotNull Formatter formatter) {
-        formatter.format(statement, systemUser.getId());
-        writeEntries(accessControlEntries, systemUser, formatter);
-        formatter.format("end%n");
+    private static boolean isHomePath(@NotNull RepoPath path, @NotNull RepoPath systemUserPath) {
+        return path.startsWith(systemUserPath);
     }
 
-    private static void writeEntries(@NotNull List<AccessControlEntry> accessControlEntries, @NotNull SystemUser systemUser, @NotNull Formatter formatter) {
-        for (AccessControlEntry entry : accessControlEntries) {
-            formatter.format("%s %s on %s",
-                    entry.getOperation(),
-                    entry.getPrivileges(),
-                    getRepoInitPath(entry.getRepositoryPath(), systemUser));
-
-            if (!entry.getRestrictions().isEmpty()) {
-                formatter.format(" restriction(%s)",
-                        String.join(",", entry.getRestrictions()));
-            }
+    @Nullable
+    private static AbstractUser getOtherUser(@NotNull RepoPath path, @NotNull Stream<? extends AbstractUser> abstractUsers) {
+        return abstractUsers.filter(au -> path.startsWith(au.getPath())).findFirst().orElse(null);
+    }
 
-            formatter.format("%n");
-        }
+    @NotNull
+    private static String getHomePath(@NotNull RepoPath path, @NotNull AbstractUser abstractUser) {
+        return getHomePath(path, abstractUser.getPath(), abstractUser.getId());
     }
 
     @NotNull
-    private static String getRepoInitPath(@NotNull RepoPath path, @NotNull SystemUser systemUser) {
-        // FIXME SLING-9953 : add special handing for path pointing to the system-user home or some other user/group home
-        if (path.isRepositoryPath()) {
-            return ":repository";
-        } else {
-            return path.toString();
-        }
+    private static String getHomePath(@NotNull RepoPath path, @NotNull RepoPath userPath, @NotNull String id) {
+        String subpath = (path.equals(userPath) ? "" : path.toString().substring(userPath.toString().length()));
+        return "home("+id+")"+subpath;
     }
 
     private static void registerPrivileges(@NotNull PrivilegeDefinitions definitions, @NotNull Formatter formatter) {
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/Group.java
similarity index 54%
copy from src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
copy to src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/Group.java
index 1bc0664..686fdd7 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/Group.java
@@ -16,28 +16,17 @@
  */
 package org.apache.sling.feature.cpconverter.accesscontrol;
 
-import java.util.List;
-
-import org.apache.jackrabbit.vault.fs.spi.PrivilegeDefinitions;
-import org.apache.sling.feature.cpconverter.features.FeaturesManager;
-import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.jetbrains.annotations.NotNull;
 
-/**
- * The Manager able to collect and build System Users and related ACL policies.
- */
-public interface AclManager {
-
-    boolean addSystemUser(SystemUser systemUser);
-
-    boolean addAcl(String systemUser, AccessControlEntry acl);
-
-    void addRepoinitExtension(List<VaultPackageAssembler> packageAssemblers, FeaturesManager featureManager);
-
-    void addNodetypeRegistrationSentence(String nodetypeRegistrationSentence);
-
-    void addPrivilegeDefinitions(@NotNull PrivilegeDefinitions privilegeDefinitions);
-
-    void reset();
+public class Group extends AbstractUser {
 
+    /**
+     * @param id               - the authorizableId to use.
+     * @param path             - the original repository path of the user in the content-package.
+     * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
+     */
+    public Group(@NotNull String id, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
+        super(id, path, intermediatePath);
+    }
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/MixinParser.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/MixinParser.java
index 5371fff..b447493 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/MixinParser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/MixinParser.java
@@ -18,7 +18,6 @@ package org.apache.sling.feature.cpconverter.accesscontrol;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.sling.feature.cpconverter.shared.AbstractJcrNodeParser;
-import org.jetbrains.annotations.NotNull;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
@@ -26,15 +25,11 @@ final class MixinParser extends AbstractJcrNodeParser<String> {
     private String mixins;
 
     public MixinParser() {
-        this("sling:Folder");
-    }
-    public MixinParser(@NotNull String primaryType) {
-        super(primaryType);
+        super();
     }
 
     @Override
-    protected void onJcrRootNode(String uri, String localName, String qName, Attributes attributes, String primaryType)
-            throws SAXException {
+    protected void onJcrRootNode(String uri, String localName, String qName, Attributes attributes, String primaryType) {
         mixins = attributes.getValue(JcrConstants.JCR_MIXINTYPES);
     }
 
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/PrimaryTypeParser.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/PrimaryTypeParser.java
index 27f769f..ffed8fc 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/PrimaryTypeParser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/PrimaryTypeParser.java
@@ -17,20 +17,13 @@
 package org.apache.sling.feature.cpconverter.accesscontrol;
 
 import org.apache.sling.feature.cpconverter.shared.AbstractJcrNodeParser;
-import org.jetbrains.annotations.NotNull;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
 final class PrimaryTypeParser extends AbstractJcrNodeParser<String> {
 
-    private String detectedPrimaryType;
-
     public PrimaryTypeParser() {
-        this("sling:Folder");
-    }
-
-    public PrimaryTypeParser(@NotNull String primaryType) {
-        super(primaryType);
+        super();
     }
 
     @Override
@@ -47,7 +40,7 @@ final class PrimaryTypeParser extends AbstractJcrNodeParser<String> {
 
     @Override
     protected String getParsingResult() {
-        return detectedPrimaryType != null ? detectedPrimaryType : getPrimaryType();
+        return detectedPrimaryType;
     }
 
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java
index 6cce9f4..e03eda1 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/SystemUser.java
@@ -19,14 +19,7 @@ package org.apache.sling.feature.cpconverter.accesscontrol;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.Objects;
-
-public class SystemUser {
-
-    private final String id;
-
-    private final RepoPath path;
-    private final RepoPath intermediatePath;
+public class SystemUser extends AbstractUser {
 
     /**
      * @param id - the authorizableId to use.
@@ -34,49 +27,6 @@ public class SystemUser {
      * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
      */
     public SystemUser(@NotNull String id, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
-        this.id = id;
-        this.path = path;
-        this.intermediatePath = intermediatePath;
-    }
-
-    public @NotNull String getId() {
-        return id;
-    }
-
-    public @NotNull RepoPath getPath() {
-        return path;
-    }
-
-    public @NotNull RepoPath getIntermediatePath() {
-        return intermediatePath;
+        super(id, path, intermediatePath);
     }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + Objects.hash(id);
-        result = prime * result + Objects.hash(path);
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-
-        SystemUser other = (SystemUser) obj;
-        return Objects.equals(id, other.getId()) && Objects.equals(path, other.getPath());
-    }
-
-    @Override
-    public String toString() {
-        return "SystemUser [id=" + id + ", path=" + path + "]";
-    }
-
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/User.java
similarity index 54%
copy from src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
copy to src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/User.java
index 1bc0664..cad22bb 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/User.java
@@ -16,28 +16,17 @@
  */
 package org.apache.sling.feature.cpconverter.accesscontrol;
 
-import java.util.List;
-
-import org.apache.jackrabbit.vault.fs.spi.PrivilegeDefinitions;
-import org.apache.sling.feature.cpconverter.features.FeaturesManager;
-import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.jetbrains.annotations.NotNull;
 
-/**
- * The Manager able to collect and build System Users and related ACL policies.
- */
-public interface AclManager {
-
-    boolean addSystemUser(SystemUser systemUser);
-
-    boolean addAcl(String systemUser, AccessControlEntry acl);
-
-    void addRepoinitExtension(List<VaultPackageAssembler> packageAssemblers, FeaturesManager featureManager);
-
-    void addNodetypeRegistrationSentence(String nodetypeRegistrationSentence);
-
-    void addPrivilegeDefinitions(@NotNull PrivilegeDefinitions privilegeDefinitions);
-
-    void reset();
+public class User extends AbstractUser {
 
+    /**
+     * @param id               - the authorizableId to use.
+     * @param path             - the original repository path of the user in the content-package.
+     * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
+     */
+    public User(@NotNull String id, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
+        super(id, path, intermediatePath);
+    }
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java b/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java
index 86fa637..ab4ea25 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java
@@ -88,7 +88,7 @@ public class DefaultFeaturesManager implements FeaturesManager {
     private Feature targetFeature = null;
 
     DefaultFeaturesManager() {
-        this(null);
+        this(new File(""));
     }
 
     public DefaultFeaturesManager(@NotNull File tempDir) {
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
new file mode 100644
index 0000000..26e6a4d
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
@@ -0,0 +1,54 @@
+/*
+ * 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.feature.cpconverter.handlers;
+
+import org.apache.jackrabbit.vault.fs.io.Archive;
+import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
+import org.apache.jackrabbit.vault.util.PlatformNameFormat;
+import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.InputStream;
+import java.util.regex.Matcher;
+
+abstract class AbstractUserEntryHandler extends AbstractRegexEntryHandler {
+
+    AbstractUserEntryHandler(@NotNull String rexex) {
+        super(rexex);
+    }
+
+    @Override
+    public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
+            throws Exception {
+        Matcher matcher = getPattern().matcher(path);
+        if (matcher.matches()) {
+            path = matcher.group(1);
+        }
+
+        RepoPath originalPath = new RepoPath(PlatformNameFormat.getRepositoryPath(path));
+        RepoPath intermediatePath = originalPath.getParent();
+
+        AbstractUserParser parser = createParser(converter, originalPath, intermediatePath);
+        try (InputStream input = archive.openInputStream(entry)) {
+            parser.parse(input);
+        }
+    }
+
+    abstract AbstractUserParser createParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath originalPath, @NotNull RepoPath intermediatePath);
+
+}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java
new file mode 100644
index 0000000..3d360c5
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java
@@ -0,0 +1,63 @@
+/*
+ * 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.feature.cpconverter.handlers;
+
+import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.shared.AbstractJcrNodeParser;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.jetbrains.annotations.NotNull;
+import org.xml.sax.Attributes;
+
+abstract class AbstractUserParser extends AbstractJcrNodeParser<Void> {
+
+    private static final String REP_AUTHORIZABLE_ID = "rep:authorizableId";
+
+    final ContentPackage2FeatureModelConverter converter;
+
+    final RepoPath path;
+
+    final RepoPath intermediatePath;
+
+    /**
+     * @param converter - the converter to use.
+     * @param path - the original repository path of the user in the content-package.
+     * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
+     * @param primaryTypes - the primary type of the user/group nodes to be parsed
+     */
+    protected AbstractUserParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath path, @NotNull RepoPath intermediatePath, @NotNull String... primaryTypes) {
+        super(primaryTypes);
+        this.converter = converter;
+        this.path = path;
+        this.intermediatePath = intermediatePath;
+    }
+
+    @Override
+    protected void onJcrRootElement(String uri, String localName, String qName, Attributes attributes) {
+        String authorizableId = attributes.getValue(REP_AUTHORIZABLE_ID);
+        if (authorizableId != null && !authorizableId.isEmpty()) {
+            handleUser(authorizableId);
+        }
+    }
+
+    @Override
+    protected Void getParsingResult() {
+        return null;
+    }
+
+    abstract void handleUser(@NotNull String id);
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/GroupEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/GroupEntryHandler.java
new file mode 100644
index 0000000..afea198
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/GroupEntryHandler.java
@@ -0,0 +1,54 @@
+/*
+ * 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.feature.cpconverter.handlers;
+
+import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.accesscontrol.Group;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.jetbrains.annotations.NotNull;
+
+public final class GroupEntryHandler extends AbstractUserEntryHandler {
+
+    public GroupEntryHandler() {
+        // FIXME: SLING-9969
+        super("/jcr_root(/home/groups.*/)\\.content.xml");
+    }
+
+    @Override
+    AbstractUserParser createParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath originalPath, @NotNull RepoPath intermediatePath) {
+        return new GroupParser(converter, originalPath, intermediatePath);
+    }
+
+    private static final class GroupParser extends AbstractUserParser {
+
+        private static final String REP_GROUP = "rep:Group";
+
+        /**
+         * @param converter - the converter to use.
+         * @param path - the original repository path of the user in the content-package.
+         * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
+         */
+        public GroupParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
+            super(converter, path, intermediatePath, REP_GROUP);
+        }
+
+        @Override
+        void handleUser(@NotNull String id) {
+            converter.getAclManager().addGroup(new Group(id, path, intermediatePath));
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/SystemUsersEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/SystemUsersEntryHandler.java
deleted file mode 100644
index 3785a2c..0000000
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/SystemUsersEntryHandler.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.feature.cpconverter.handlers;
-
-import org.apache.jackrabbit.vault.util.PlatformNameFormat;
-import org.jetbrains.annotations.NotNull;
-import org.xml.sax.Attributes;
-
-import org.apache.jackrabbit.vault.fs.io.Archive;
-import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
-import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
-import org.apache.sling.feature.cpconverter.accesscontrol.SystemUser;
-import org.apache.sling.feature.cpconverter.shared.AbstractJcrNodeParser;
-import org.apache.sling.feature.cpconverter.shared.RepoPath;
-
-import java.io.InputStream;
-import java.util.regex.Matcher;
-
-public final class SystemUsersEntryHandler extends AbstractRegexEntryHandler {
-
-    public SystemUsersEntryHandler() {
-        super("/jcr_root(/home/users/.*/)\\.content.xml");
-    }
-
-    @Override
-    public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
-            throws Exception {
-        Matcher matcher = getPattern().matcher(path);
-        if (matcher.matches()) {
-            path = matcher.group(1);
-        }
-
-        RepoPath originalPath = new RepoPath(PlatformNameFormat.getRepositoryPath(path));
-        RepoPath intermediatePath = originalPath.getParent();
-
-        SystemUserParser systemUserParser = new SystemUserParser(converter, originalPath, intermediatePath);
-        try (InputStream input = archive.openInputStream(entry)) {
-            systemUserParser.parse(input);
-        }
-    }
-
-    private static final class SystemUserParser extends AbstractJcrNodeParser<Void> {
-
-        private final static String REP_SYSTEM_USER = "rep:SystemUser";
-
-        private final static String REP_AUTHORIZABLE_ID = "rep:authorizableId";
-
-        private final ContentPackage2FeatureModelConverter converter;
-
-        private final RepoPath path;
-
-        private final RepoPath intermediatePath;
-
-        /**
-         * @param converter - the converter to use.
-         * @param path - the original repository path of the user in the content-package.
-         * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
-         */
-        public SystemUserParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
-            super(REP_SYSTEM_USER);
-            this.converter = converter;
-            this.path = path;
-            this.intermediatePath = intermediatePath;
-        }
-
-        @Override
-        protected void onJcrRootElement(String uri, String localName, String qName, Attributes attributes) {
-            String authorizableId = attributes.getValue(REP_AUTHORIZABLE_ID);
-            if (authorizableId != null && !authorizableId.isEmpty()) {
-                converter.getAclManager().addSystemUser(new SystemUser(authorizableId, path, intermediatePath));
-            }
-        }
-
-        @Override
-        protected Void getParsingResult() {
-            return null;
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java
new file mode 100644
index 0000000..6773c4d
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java
@@ -0,0 +1,61 @@
+/*
+ * 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.feature.cpconverter.handlers;
+
+import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.accesscontrol.SystemUser;
+import org.apache.sling.feature.cpconverter.accesscontrol.User;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.jetbrains.annotations.NotNull;
+
+public final class UsersEntryHandler extends AbstractUserEntryHandler {
+
+    public UsersEntryHandler() {
+        // FIXME: SLING-9969
+        super("/jcr_root(/home/users/.*/)\\.content.xml");
+    }
+
+    @Override
+    AbstractUserParser createParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath originalPath, @NotNull RepoPath intermediatePath) {
+        return new SystemUserParser(converter, originalPath, intermediatePath);
+    }
+
+    private static final class SystemUserParser extends AbstractUserParser {
+
+        private static final String REP_SYSTEM_USER = "rep:SystemUser";
+        private static final String REP_USER = "rep:User";
+
+        /**
+         * @param converter - the converter to use.
+         * @param path - the original repository path of the user in the content-package.
+         * @param intermediatePath - the intermediate path the user should have - most likely the (direct) parent of the path.
+         */
+        public SystemUserParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath path, @NotNull RepoPath intermediatePath) {
+            super(converter, path, intermediatePath, REP_SYSTEM_USER, REP_USER);
+        }
+
+        @Override
+        void handleUser(@NotNull String id) {
+            if (REP_USER.equals(detectedPrimaryType)) {
+                converter.getAclManager().addUser(new User(id, path, intermediatePath));
+            } else{
+                converter.getAclManager().addSystemUser(new SystemUser(id, path, intermediatePath));
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java b/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java
index 79caf44..c265f5f 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java
@@ -19,10 +19,12 @@ package org.apache.sling.feature.cpconverter.shared;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 
 import java.io.InputStream;
+import java.util.Set;
 
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
+import com.google.common.collect.ImmutableSet;
 import org.jetbrains.annotations.NotNull;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
@@ -34,10 +36,12 @@ public abstract class AbstractJcrNodeParser<O> extends DefaultHandler {
 
     private static final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
 
-    private final String primaryType;
+    private final Set<String> primaryTypes;
 
-    public AbstractJcrNodeParser(@NotNull String primaryType) {
-        this.primaryType = primaryType;
+    protected String detectedPrimaryType;
+
+    protected AbstractJcrNodeParser(@NotNull String... primaryTypes) {
+        this.primaryTypes = ImmutableSet.of(primaryTypes);
     }
 
     public O parse(InputStream input) throws Exception {
@@ -54,12 +58,9 @@ public abstract class AbstractJcrNodeParser<O> extends DefaultHandler {
         }
     }
 
-    protected final @NotNull String getPrimaryType() {
-        return primaryType;
-    }
-
     protected void onJcrRootNode(String uri, String localName, String qName, Attributes attributes, String primaryType) throws SAXException {
-        if (this.primaryType.equals(primaryType)) {
+        if (this.primaryTypes.contains(primaryType)) {
+            detectedPrimaryType = primaryType;
             onJcrRootElement(uri, localName, qName, attributes);
         }
     }
@@ -67,5 +68,4 @@ public abstract class AbstractJcrNodeParser<O> extends DefaultHandler {
     protected abstract void onJcrRootElement(String uri, String localName, String qName, Attributes attributes) throws SAXException;
 
     protected abstract O getParsingResult();
-
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java
index 8e9f290..ec25f3a 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java
@@ -24,7 +24,7 @@ import org.apache.jackrabbit.vault.packaging.PackageId;
 import org.apache.jackrabbit.vault.packaging.PackageManager;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
 import org.apache.sling.feature.cpconverter.handlers.EntryHandler;
-import org.apache.sling.feature.cpconverter.handlers.SystemUsersEntryHandler;
+import org.apache.sling.feature.cpconverter.handlers.UsersEntryHandler;
 import org.apache.sling.feature.cpconverter.handlers.VersionResolverContentPackageEntryHandler;
 import org.jetbrains.annotations.NotNull;
 
@@ -41,7 +41,7 @@ public final class RecollectorVaultPackageScanner extends BaseVaultPackageScanne
         super(packageManager, strictValidation);
         this.converter = converter;
         handlers = new EntryHandler[] {
-                new SystemUsersEntryHandler(),
+                new UsersEntryHandler(),
                 new VersionResolverContentPackageEntryHandler(this, subContentPackages)
         };
     }
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler b/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler
index 1ab38fb..7a82e4e 100644
--- a/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler
@@ -1,10 +1,12 @@
 org.apache.sling.feature.cpconverter.handlers.BundleEntryHandler
 org.apache.sling.feature.cpconverter.handlers.ConfigurationEntryHandler
 org.apache.sling.feature.cpconverter.handlers.ContentPackageEntryHandler
+org.apache.sling.feature.cpconverter.handlers.GroupEntryHandler
 org.apache.sling.feature.cpconverter.handlers.JsonConfigurationEntryHandler
 org.apache.sling.feature.cpconverter.handlers.NodeTypesEntryHandler
 org.apache.sling.feature.cpconverter.handlers.PrivilegesHandler
 org.apache.sling.feature.cpconverter.handlers.PropertiesConfigurationEntryHandler
 org.apache.sling.feature.cpconverter.handlers.RepPolicyEntryHandler
 org.apache.sling.feature.cpconverter.handlers.RepRepoPolicyEntryHandler
+org.apache.sling.feature.cpconverter.handlers.UsersEntryHandler
 org.apache.sling.feature.cpconverter.handlers.XmlConfigurationEntryHandler
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManagerTest.java b/src/test/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManagerTest.java
index 98c1863..52b66fa 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManagerTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/accesscontrol/AclManagerTest.java
@@ -66,7 +66,6 @@ public class AclManagerTest {
             .map(Path::toFile)
             .forEach(File::delete);
     }
-
     @Test
     public void makeSureAclsAreCreatedOnlyoutsideSytemUsersPaths() throws Exception {
         aclManager.addSystemUser(new SystemUser("acs-commons-package-replication-status-event-service", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
@@ -93,14 +92,11 @@ public class AclManagerTest {
         // acs-commons-on-deploy-scripts-service will be missed
         String expected =
                 "create service user acs-commons-package-replication-status-event-service with path /home/users/system" + System.lineSeparator() +
-                "create path /asd/not(nt:unstructured mixin rep:AccessControllable,mix:created)/system/user/path" + System.lineSeparator() +
-                // see SLING-8561
-                // "set ACL for acs-commons-package-replication-status-event-service\n" +
-                // "allow jcr:read,crx:replicate,jcr:removeNode on /asd/public\n" +
-                // "end\n" +
-                "set ACL for acs-commons-package-replication-status-event-service" + System.lineSeparator() +
-                "allow jcr:read,rep:write,rep:indexDefinitionManagement on /asd/not/system/user/path" + System.lineSeparator() +
-                "end" + System.lineSeparator();
+                        "create path /asd/not(nt:unstructured mixin rep:AccessControllable,mix:created)/system/user/path" + System.lineSeparator() +
+                        "set ACL for acs-commons-package-replication-status-event-service" + System.lineSeparator() +
+                        "allow jcr:read,rep:write,rep:indexDefinitionManagement on /asd/not/system/user/path" + System.lineSeparator() +
+                        "allow jcr:read,crx:replicate,jcr:removeNode on /home/users/system" + System.lineSeparator() +
+                        "end" + System.lineSeparator();
         String actual = repoinitExtension.getText();
         assertEquals(expected, actual);
 
@@ -201,6 +197,151 @@ public class AclManagerTest {
         assertFalse(operations.isEmpty());
     }
 
+    @Test
+    public void testGroupHandlingWithGroupUsed() {
+        aclManager.addSystemUser(new SystemUser("sys-usr", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
+
+        aclManager.addGroup(new Group("test", new RepoPath("/home/groups/test"),  new RepoPath("/home/groups/test")));
+        aclManager.addAcl("sys-usr", newAcl(true, "jcr:read", "/home/groups/test"));
+        VaultPackageAssembler assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new File(System.getProperty("java.io.tmpdir")));
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        FeaturesManager fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user sys-usr with path /home/users/system" + System.lineSeparator() +
+                        "create group test with path /home/groups/test" + System.lineSeparator() +
+                        "set ACL for sys-usr" + System.lineSeparator() +
+                        "allow jcr:read on home(test)" + System.lineSeparator() +
+                        "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+    }
+
+    @Test
+    public void testGroupHandlingWithGroupNotUsed() {
+        aclManager.addSystemUser(new SystemUser("sys-usr", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
+
+        aclManager.addGroup(new Group("test", new RepoPath("/home/groups/test"),  new RepoPath("/home/groups/test")));
+        aclManager.addAcl("sys-usr", newAcl(true, "jcr:read", "/content/test"));
+        VaultPackageAssembler assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new File(System.getProperty("java.io.tmpdir")));
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        FeaturesManager fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user sys-usr with path /home/users/system" + System.lineSeparator() +
+                        "set ACL for sys-usr" + System.lineSeparator() +
+                        "allow jcr:read on /content/test" + System.lineSeparator() +
+                        "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testGroupHandlingWithGroupMatchingSubPath() {
+        aclManager.addSystemUser(new SystemUser("sys-usr", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
+
+        aclManager.addGroup(new Group("test", new RepoPath("/home/groups/test"),  new RepoPath("/home/groups/test")));
+        aclManager.addAcl("sys-usr", newAcl(true, "jcr:read", "/home/groups/test/foo"));
+        VaultPackageAssembler assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new File(System.getProperty("java.io.tmpdir")));
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        FeaturesManager fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testUserHandlingWithMatchingUser() {
+        aclManager.addSystemUser(new SystemUser("sys-usr", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
+
+        aclManager.addUser(new User("test", new RepoPath("/home/users/test"),  new RepoPath("/home/users/test")));
+        aclManager.addAcl("sys-usr", newAcl(true, "jcr:read", "/home/users/test/foo"));
+        VaultPackageAssembler assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new File(System.getProperty("java.io.tmpdir")));
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        FeaturesManager fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+    }
+
+    @Test
+    public void testUserHandlingWithNonMatchingUser() {
+        aclManager.addSystemUser(new SystemUser("sys-usr", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
+
+        aclManager.addUser(new User("test", new RepoPath("/home/users/test"),  new RepoPath("/home/users/test")));
+        aclManager.addAcl("sys-usr", newAcl(true, "jcr:read", "/content/test"));
+        VaultPackageAssembler assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new File(System.getProperty("java.io.tmpdir")));
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        FeaturesManager fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user sys-usr with path /home/users/system" + System.lineSeparator() +
+                        "set ACL for sys-usr" + System.lineSeparator() +
+                        "allow jcr:read on /content/test" + System.lineSeparator() +
+                        "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testPathHandlingWithUser() {
+        aclManager.addSystemUser(new SystemUser("sys-usr", new RepoPath("/home/users/system/foo"), new RepoPath("/home/users/system")));
+
+        aclManager.addUser(new User("test", new RepoPath("/home/users/test"),  new RepoPath("/home/users/test")));
+        aclManager.addAcl("sys-usr", newAcl(true, "jcr:read", "/home/users/test2"));
+        VaultPackageAssembler assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new File(System.getProperty("java.io.tmpdir")));
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        FeaturesManager fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user sys-usr with path /home/users/system" + System.lineSeparator() +
+                        "set ACL for sys-usr" + System.lineSeparator() +
+                        "allow jcr:read on /home/users/test2" + System.lineSeparator() +
+                        "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+    }
+
     private static AccessControlEntry newAcl(boolean isAllow, String privileges, String path) {
         return new AccessControlEntry(isAllow, privileges, new RepoPath(PlatformNameFormat.getRepositoryPath(path)));
     }
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandlerTest.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandlerTest.java
index a9bf8eb..e2d9889 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandlerTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandlerTest.java
@@ -23,8 +23,11 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
 import org.apache.sling.feature.cpconverter.accesscontrol.DefaultAclManager;
+import org.apache.sling.feature.cpconverter.accesscontrol.Group;
 import org.apache.sling.feature.cpconverter.accesscontrol.SystemUser;
+import org.apache.sling.feature.cpconverter.accesscontrol.User;
 import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
@@ -32,6 +35,7 @@ import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.apache.sling.repoinit.parser.RepoInitParser;
 import org.apache.sling.repoinit.parser.impl.RepoInitParserService;
 import org.apache.sling.repoinit.parser.operations.Operation;
+import org.jetbrains.annotations.NotNull;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -96,31 +100,32 @@ public final class RepPolicyEntryHandlerTest {
         // commented ACLs are due SLING-8561
         String expected =
                 "create service user acs-commons-ensure-oak-index-service with path /home/users/system" + System.lineSeparator() +
-                // "create path (sling:Folder) /asd\n" +
-                // "create path (sling:Folder) /asd/public\n" +
-                // "set ACL for acs-commons-ensure-oak-index-service\n" +
-                // "allow jcr:read,rep:write,rep:indexDefinitionManagement on /asd/public restriction(rep:glob,*/oak:index/*)\n" +
-                // "end\n" +
                 "create service user acs-commons-dispatcher-flush-service with path /home/users/system" + System.lineSeparator() +
-                // "set ACL for acs-commons-dispatcher-flush-service\n" +
-                // "allow jcr:read,crx:replicate,jcr:removeNode on /asd/public\n" +
-                // "end\n" +
                 "create service user acs-commons-package-replication-status-event-service with path /home/users/system" + System.lineSeparator() +
-                // "set ACL for acs-commons-package-replication-status-event-service\n" +
-                // "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on /asd/public\n" +
-                // "end\n" +
                 "create service user acs-commons-ensure-service-user-service with path /home/users/system" + System.lineSeparator() +
-                // "set ACL for acs-commons-ensure-service-user-service\n" +
-                // "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on /asd/public\n" +
-                // "end\n" +
                 "create service user acs-commons-automatic-package-replicator-service with path /home/users/system" + System.lineSeparator() +
-                // "set ACL for acs-commons-automatic-package-replicator-service\n" +
-                // "allow jcr:read on /asd/public\n" +
-                // "end\n" +
-                "create service user acs-commons-on-deploy-scripts-service with path /home/users/system" + System.lineSeparator();
-                // "set ACL for acs-commons-on-deploy-scripts-service\n" +
-                // "allow jcr:read on /asd/public\n" +
-                // "end\n";
+                "create service user acs-commons-on-deploy-scripts-service with path /home/users/system" + System.lineSeparator() +
+                "set ACL for acs-commons-automatic-package-replicator-service" + System.lineSeparator() +
+                "allow jcr:read on home(acs-commons-automatic-package-replicator-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-package-replication-status-event-service" + System.lineSeparator() +
+                "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on home(acs-commons-package-replication-status-event-service)" + System.lineSeparator() +
+                "deny jcr:write on home(acs-commons-package-replication-status-event-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-dispatcher-flush-service" + System.lineSeparator() +
+                "allow jcr:read,crx:replicate,jcr:removeNode on home(acs-commons-dispatcher-flush-service)" + System.lineSeparator() +
+                "deny jcr:write on home(acs-commons-dispatcher-flush-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-ensure-oak-index-service" + System.lineSeparator() +
+                "allow jcr:read,rep:write,rep:indexDefinitionManagement on home(acs-commons-ensure-oak-index-service) restriction(rep:glob,*/oak:index/*)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-on-deploy-scripts-service" + System.lineSeparator() +
+                "allow jcr:read on home(acs-commons-on-deploy-scripts-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-ensure-service-user-service" + System.lineSeparator() +
+                "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on home(acs-commons-ensure-service-user-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator();
+
         String actual = repoinitExtension.getText();
         assertEquals(expected, actual);
 
@@ -140,26 +145,24 @@ public final class RepPolicyEntryHandlerTest {
         assertNotNull(repoinitExtension);
         assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
 
-        // commented ACLs are due SLING-8561
         String expected =
                 "create service user acs-commons-package-replication-status-event-service with path /home/users/system" + System.lineSeparator() +
-                // "create path (sling:Folder) /asd\n" +
-                // "create path (sling:Folder) /asd/public\n" +
-                // "set ACL for acs-commons-package-replication-status-event-service\n" +
-                // "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on /asd/public\n" +
-                // "end\n" +
                 "create service user acs-commons-ensure-service-user-service with path /home/users/system" + System.lineSeparator() +
-                // "set ACL for acs-commons-ensure-service-user-service\n" +
-                // "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on /asd/public\n" +
-                // "end\n" +
                 "create service user acs-commons-automatic-package-replicator-service with path /home/users/system" + System.lineSeparator() +
-                // "set ACL for acs-commons-automatic-package-replicator-service\n" +
-                // "allow jcr:read on /asd/public\n" +
-                // "end\n" +
-                "create service user acs-commons-on-deploy-scripts-service with path /home/users/system" + System.lineSeparator();
-                //"set ACL for acs-commons-on-deploy-scripts-service\n" +
-                //"allow jcr:read on /asd/public\n" +
-                //"end\n";
+                "create service user acs-commons-on-deploy-scripts-service with path /home/users/system" + System.lineSeparator() +
+                "set ACL for acs-commons-automatic-package-replicator-service" + System.lineSeparator() +
+                "allow jcr:read on home(acs-commons-automatic-package-replicator-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-package-replication-status-event-service" + System.lineSeparator() +
+                "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on home(acs-commons-package-replication-status-event-service)" + System.lineSeparator() +
+                "deny jcr:write on home(acs-commons-package-replication-status-event-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-on-deploy-scripts-service" + System.lineSeparator() +
+                "allow jcr:read on home(acs-commons-on-deploy-scripts-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator() +
+                "set ACL for acs-commons-ensure-service-user-service" + System.lineSeparator() +
+                "allow jcr:read,rep:write,jcr:readAccessControl,jcr:modifyAccessControl on home(acs-commons-ensure-service-user-service)" + System.lineSeparator() +
+                "end" + System.lineSeparator();
         String actual = repoinitExtension.getText();
         assertEquals(expected, actual);
 
@@ -223,6 +226,79 @@ public final class RepPolicyEntryHandlerTest {
         assertNull(repoinitExtension);
     }
 
+    @Test
+    public void policyAtAuthorizableFolder() throws Exception {
+        SystemUser s1 = new SystemUser("service1", new RepoPath("/home/users/system/services/random1"), new RepoPath("/home/users/system/services"));
+
+        AclManager aclManager = new DefaultAclManager();
+        aclManager.addSystemUser(s1);
+
+        ParseResult result = parseAndSetRepoInit("/jcr_root/home/groups/g/_rep_policy.xml", aclManager);
+        Extension repoinitExtension = result.getRepoinitExtension();
+        assertNotNull(repoinitExtension);
+        assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
+
+        String expected =
+                "create service user service1 with path /home/users/system/services" + System.lineSeparator() +
+                "set ACL for service1" + System.lineSeparator() +
+                "allow jcr:read,rep:userManagement on /home/groups/g" + System.lineSeparator() +
+                "end" + System.lineSeparator();
+        assertEquals(expected, repoinitExtension.getText());
+        assertTrue(result.excludedAcls.isEmpty());
+    }
+
+    @Test
+    public void policyAtGroupNode() throws Exception {
+        SystemUser s1 = new SystemUser("service1", new RepoPath("/home/users/system/services/random1"), new RepoPath("/home/users/system/services"));
+        Group gr = new Group("testgroup", new RepoPath("/home/groups/g/HjDnfdMCjekaF4jhhUvO"), new RepoPath("/home/groups/g"));
+
+        AclManager aclManager = new DefaultAclManager();
+        aclManager.addSystemUser(s1);
+        aclManager.addGroup(gr);
+
+        ParseResult result = parseAndSetRepoInit("/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/_rep_policy.xml", aclManager);
+        Extension repoinitExtension = result.getRepoinitExtension();
+        assertNotNull(repoinitExtension);
+        assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
+
+        String expected =
+                "create service user service1 with path /home/users/system/services" + System.lineSeparator() +
+                "create group testgroup with path /home/groups/g" + System.lineSeparator() +
+                "set ACL for service1" + System.lineSeparator() +
+                "allow jcr:read on home(testgroup)" + System.lineSeparator() +
+                "end" + System.lineSeparator();
+        assertEquals(expected, repoinitExtension.getText());
+
+        String expectedExclusions = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><jcr:root xmlns:jcr=\"http://www.jcp.org/jcr/1.0\" xmlns:rep=\"internal\" jcr:primaryType=\"rep:ACL\">\n" +
+                "    <allow1 jcr:primaryType=\"rep:GrantACE\" rep:principalName=\"testgroup\" rep:privileges=\"{Name}[jcr:read]\"/>\n" +
+                "</jcr:root>\n";
+        assertEquals(expectedExclusions, result.excludedAcls);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void policyAtGroupSubTree() throws Exception {
+        SystemUser s1 = new SystemUser("service1", new RepoPath("/home/users/system/services/random1"), new RepoPath("/home/users/system/services"));
+        Group gr = new Group("testgroup3", new RepoPath("/home/groups/g/ouStmkrzT9wCEhtMD9sT"), new RepoPath("/home/groups/g"));
+
+        AclManager aclManager = new DefaultAclManager();
+        aclManager.addSystemUser(s1);
+        aclManager.addGroup(gr);
+
+        parseAndSetRepoInit("/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/_rep_policy.xml", aclManager);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void policyAtUserNode() throws Exception {
+        SystemUser s1 = new SystemUser("service1", new RepoPath("/home/users/system/services/random1"), new RepoPath("/home/users/system/services"));
+        User user = new User("author", new RepoPath("/home/users/a/author"), new RepoPath("/home/users/a"));
+
+        AclManager aclManager = new DefaultAclManager();
+        aclManager.addSystemUser(s1);
+        aclManager.addUser(user);
+
+        parseAndSetRepoInit("/jcr_root/home/users/a/author/_rep_policy.xml", aclManager);
+    }
+
     private ParseResult parseAndSetRepoinit(String...systemUsersNames) throws Exception {
         RepoPath alwaysTheSameOrgPath = new RepoPath("/home/users/system/asd");
         RepoPath alwaysTheSameInterPath = new RepoPath("/home/users/system");
@@ -235,42 +311,25 @@ public final class RepPolicyEntryHandlerTest {
         return parseAndSetRepoinit(systemUsers);
     }
 
-    private ParseResult parseAndSetRepoinit(SystemUser...systemUsers) throws Exception {
+    private ParseResult parseAndSetRepoinit(@NotNull SystemUser...systemUsers) throws Exception {
         String path = "/jcr_root/home/users/system/asd/_rep_policy.xml";
-        Archive archive = mock(Archive.class);
-        Entry entry = mock(Entry.class);
-        VaultPackageAssembler packageAssembler = mock(VaultPackageAssembler.class);
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        when(packageAssembler.createEntry(anyString())).thenReturn(baos);
-
-        when(archive.openInputStream(entry)).thenReturn(getClass().getResourceAsStream(path.substring(1)));
-
-        Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
-        FeaturesManager featuresManager = spy(DefaultFeaturesManager.class);
-        when(featuresManager.getTargetFeature()).thenReturn(feature);
-        ContentPackage2FeatureModelConverter converter = spy(ContentPackage2FeatureModelConverter.class);
-        when(converter.getFeaturesManager()).thenReturn(featuresManager);
-        when(converter.getAclManager()).thenReturn(new DefaultAclManager());
-        when(converter.getMainPackageAssembler()).thenReturn(packageAssembler);
-
-        if (systemUsers != null) {
-            for (SystemUser systemUser : systemUsers) {
-                converter.getAclManager().addSystemUser(systemUser);
-            }
+        AclManager aclManager = new DefaultAclManager();
+        for (SystemUser systemUser : systemUsers) {
+            aclManager.addSystemUser(systemUser);
         }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        return new ParseResult(TestUtils.createRepoInitExtension(handler, aclManager, path, getClass().getResourceAsStream(path.substring(1)), baos), new String(baos.toByteArray()));
+    }
 
-        handler.handle(path, archive, entry, converter);
-
-        when(packageAssembler.getEntry(anyString())).thenReturn(new File("itdoesnotexist"));
-
-        converter.getAclManager().addRepoinitExtension(Arrays.asList(packageAssembler), featuresManager);
-        return new ParseResult(feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT), new String(baos.toByteArray()));
+    @NotNull
+    private ParseResult parseAndSetRepoInit(@NotNull String path, @NotNull AclManager aclManager) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        return new ParseResult(TestUtils.createRepoInitExtension(handler, aclManager, path, getClass().getResourceAsStream(path.substring(1)), baos), new String(baos.toByteArray()));
     }
 
     private static final class ParseResult {
 
         private final Extension repoinitExtension;
-
         private final String excludedAcls;
 
         public ParseResult(Extension repoinitExtension, String excludedAcls) {
@@ -285,7 +344,5 @@ public final class RepPolicyEntryHandlerTest {
         public String getExcludedAcls() {
             return excludedAcls;
         }
-
     }
-
 }
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
index 9e674e0..396766a 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
@@ -26,11 +26,13 @@ import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Arrays;
 
 import static org.mockito.ArgumentMatchers.anyString;
@@ -45,9 +47,15 @@ class TestUtils {
     private TestUtils() {}
 
     static Extension createRepoInitExtension(@NotNull EntryHandler handler, @NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is) throws Exception {
+        return createRepoInitExtension(handler, aclManager, path, is, null);
+    }
+    static Extension createRepoInitExtension(@NotNull EntryHandler handler, @NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is, @Nullable OutputStream out) throws Exception {
         Archive archive = mock(Archive.class);
         Archive.Entry entry = mock(Archive.Entry.class);
         VaultPackageAssembler packageAssembler = mock(VaultPackageAssembler.class);
+        if (out != null) {
+            when(packageAssembler.createEntry(anyString())).thenReturn(out);
+        }
 
         when(archive.openInputStream(entry)).thenReturn(is);
 
@@ -57,6 +65,7 @@ class TestUtils {
         ContentPackage2FeatureModelConverter converter = spy(ContentPackage2FeatureModelConverter.class);
         when(converter.getFeaturesManager()).thenReturn(featuresManager);
         when(converter.getAclManager()).thenReturn(aclManager);
+        when(converter.getMainPackageAssembler()).thenReturn(packageAssembler);
 
         handler.handle(path, archive, entry, converter);
 
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/SystemUsersEntryHandlerTest.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandlerTest.java
similarity index 82%
rename from src/test/java/org/apache/sling/feature/cpconverter/handlers/SystemUsersEntryHandlerTest.java
rename to src/test/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandlerTest.java
index 3fe0523..b232330 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/SystemUsersEntryHandlerTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandlerTest.java
@@ -35,29 +35,29 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class SystemUsersEntryHandlerTest {
+public class UsersEntryHandlerTest {
 
-    private SystemUsersEntryHandler systemUsersEntryHandler;
+    private UsersEntryHandler usersEntryHandler;
 
     @Before
     public void setUp() {
-        systemUsersEntryHandler = new SystemUsersEntryHandler();
+        usersEntryHandler = new UsersEntryHandler();
     }
 
     @After
     public void tearDown() {
-        systemUsersEntryHandler = null;
+        usersEntryHandler = null;
     }
 
     @Test
     public void doesNotMatch() {
-        assertFalse(systemUsersEntryHandler.matches("/this/is/a/path/not/pointing/to/a/valid/configuration.asd"));
-        assertFalse(systemUsersEntryHandler.matches("/home/users/system/asd-share-commons/asd-index-definition-reader/.content.xml"));
+        assertFalse(usersEntryHandler.matches("/this/is/a/path/not/pointing/to/a/valid/configuration.asd"));
+        assertFalse(usersEntryHandler.matches("/home/users/system/asd-share-commons/asd-index-definition-reader/.content.xml"));
     }
 
     @Test
     public void matches() {
-        assertTrue(systemUsersEntryHandler.matches("/jcr_root/home/users/system/asd-share-commons/asd-index-definition-reader/.content.xml"));
+        assertTrue(usersEntryHandler.matches("/jcr_root/home/users/system/asd-share-commons/asd-index-definition-reader/.content.xml"));
     }
 
     @Test
@@ -102,6 +102,6 @@ public class SystemUsersEntryHandlerTest {
     }
 
     private Extension parseAndSetRepoinit(String path) throws Exception {
-        return TestUtils.createRepoInitExtension(systemUsersEntryHandler, new DefaultAclManager(), path, getClass().getResourceAsStream(path.substring(1)));
+        return TestUtils.createRepoInitExtension(usersEntryHandler, new DefaultAclManager(), path, getClass().getResourceAsStream(path.substring(1)));
     }
 }
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/.content.xml
new file mode 100644
index 0000000..280f6f5
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/.content.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:AuthorizableFolder"
+          jcr:mixinTypes="[rep:AccessControllable]"/>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/.content.xml
new file mode 100644
index 0000000..4d9e251
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/.content.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:Group"
+          jcr:mixinTypes="[rep:AccessControllable]"
+          jcr:uuid="9628ffae-cf05-3138-8185-2cb572d50d45"
+          rep:authorizableId="testgroup"
+          rep:principalName="testgroup"/>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/_rep_policy.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/_rep_policy.xml
new file mode 100644
index 0000000..157f7f4
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/HjDnfdMCjekaF4jhhUvO/_rep_policy.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:ACL">
+    <!-- entry to be converted to repo-init statement if service1 is part of the same package -->
+    <allow
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="service1"
+            rep:privileges="{Name}[jcr:read]">
+    </allow>
+    <!-- entry not to be converted to repo-init statement -->
+    <allow1
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="testgroup"
+            rep:privileges="{Name}[jcr:read]">
+    </allow1>
+</jcr:root>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/V084LLw1ypl2l9G0e28c/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/V084LLw1ypl2l9G0e28c/.content.xml
new file mode 100644
index 0000000..307f81b
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/V084LLw1ypl2l9G0e28c/.content.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:Group"
+          jcr:uuid="62a34b2f-0897-32be-909e-a9ae27b85688"
+          rep:authorizableId="testgroup2"
+          rep:principalName="testgroup2"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/V084LLw1ypl2l9G0e28c/_rep_policy.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/V084LLw1ypl2l9G0e28c/_rep_policy.xml
new file mode 100644
index 0000000..942b0a3
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/V084LLw1ypl2l9G0e28c/_rep_policy.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:ACL">
+    <!-- entry not to be converted to repo-init statement -->
+    <allow1
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="testgroup2"
+            rep:privileges="{Name}[jcr:read]">
+    </allow1>
+</jcr:root>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/_rep_policy.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/_rep_policy.xml
new file mode 100644
index 0000000..e912df1
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/_rep_policy.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:ACL">
+    <allow
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="service1"
+            rep:privileges="{Name}[jcr:read,rep:userManagement]">
+    </allow>
+</jcr:root>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/.content.xml
new file mode 100644
index 0000000..5802f67
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/.content.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:Group"
+          jcr:uuid="dff511f7-fa75-3922-b0f4-7194f7ad4267"
+          rep:authorizableId="testgroup3"
+          rep:principalName="testgroup3"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/.content.xml
new file mode 100644
index 0000000..494e2aa
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/.content.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:mixinTypes="[rep:AccessControllable]"
+          jcr:primaryType="nt:unstructured"
+          aboutMe="test group"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/_rep_policy.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/_rep_policy.xml
new file mode 100644
index 0000000..1f5a54b
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/groups/g/ouStmkrzT9wCEhtMD9sT/profile/_rep_policy.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:ACL">
+    <!-- entry to be converted to repo-init statement if service1 is part of the same package -->
+    <allow
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="service1"
+            rep:privileges="{Name}[jcr:read]">
+    </allow>
+    <!-- entry not to be converted to repo-init statement -->
+    <allow1
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="testgroup3"
+            rep:privileges="{Name}[jcr:all]">
+    </allow1>
+</jcr:root>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/.content.xml
new file mode 100644
index 0000000..4f64da2
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/.content.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:mixinTypes="[rep:AccessControllable]"
+          jcr:primaryType="rep:User"
+          jcr:uuid="02bd92fa-a38a-3a6c-80ea-75e59937a1ef"
+          rep:authorizableId="author"
+          rep:principalName="author"/>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/_rep_policy.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/_rep_policy.xml
new file mode 100644
index 0000000..b56cca7
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/_rep_policy.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:ACL">
+    <allow
+            jcr:primaryType="rep:GrantACE"
+            rep:principalName="service1"
+            rep:privileges="{Name}[jcr:read]">
+    </allow>
+</jcr:root>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/profile/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/profile/.content.xml
new file mode 100644
index 0000000..494e2aa
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/a/author/profile/.content.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:mixinTypes="[rep:AccessControllable]"
+          jcr:primaryType="nt:unstructured"
+          aboutMe="test group"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random1/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random1/.content.xml
new file mode 100644
index 0000000..5b113ba
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random1/.content.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:SystemUser"
+          jcr:uuid="0a39b2bb-8594-3d80-a4fe-3464cfb7038b"
+          rep:authorizableId="service1"
+          rep:principalName="service1"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random2/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random2/.content.xml
new file mode 100644
index 0000000..c58ca5c
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random2/.content.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:SystemUser"
+          jcr:uuid="fb3ed345-63d5-37d1-bead-97d5d64feeca"
+          rep:authorizableId="service2"
+          rep:principalName="service2"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random3/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random3/.content.xml
new file mode 100644
index 0000000..9c02a82
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random3/.content.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:SystemUser"
+          jcr:uuid="ec2fbc3d-e9f6-3b3f-94f1-90ff5d05605f"
+          rep:authorizableId="service3"
+          rep:principalName="service3"/>
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random4/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random4/.content.xml
new file mode 100644
index 0000000..327ffdf
--- /dev/null
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random4/.content.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+          jcr:primaryType="rep:SystemUser"
+          jcr:uuid="342acedc-ac4a-3044-93d0-3288d39668af"
+          rep:authorizableId="service3"
+          rep:principalName="service3"/>